On Wed, Sep 21, 2022 at 06:16:18PM +0100, Al Viro wrote: > On Wed, Sep 21, 2022 at 11:10:10AM +0200, Alexander Larsson wrote: > > When do_read_cache_folio() returns an error pointer the code > > was dereferencing it rather than forwarding the error via > > ERR_CAST(). > > > > Found during code review. > > > > Fixes: 539a3322f208 ("filemap: Add read_cache_folio and read_mapping_folio") > > Signed-off-by: Alexander Larsson <alexl@xxxxxxxxxx> > > --- > > mm/filemap.c | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/mm/filemap.c b/mm/filemap.c > > index 15800334147b..6bc55506f7a8 100644 > > --- a/mm/filemap.c > > +++ b/mm/filemap.c > > @@ -3560,7 +3560,7 @@ static struct page *do_read_cache_page(struct address_space *mapping, > > > > folio = do_read_cache_folio(mapping, index, filler, file, gfp); > > if (IS_ERR(folio)) > > - return &folio->page; > > + return ERR_CAST(folio); > > Where do you see a dereference? I agree that your variant is cleaner, > but &folio->page does *NOT* dereference anything - it's an equivalent of > > (struct page *)((unsigned long)folio + offsetof(struct folio, page)) > > and the reason it happens to work is that page is the first member in > struct folio, so the offsetof ends up being 0 and we are left with a cast > from struct folio * to struct page *, i.e. the same thing ERR_CAST() > variant end up with (it casts to void *, which is converted to struct > page * since return acts as assignment wrt type conversions). > > It *is* brittle and misguiding, and your patch is a much more clear > way to spell that thing, no arguments about it; just that your patch > is not changing behaviour. I don't see it that way. &folio->page is the idiomatic way to do this. What it really is, is an indicator that code needs to be converted from calling do_read_cache_page() and friends to calling the folio equivalents. Also, I should have moved this code to folio-compat.c where it would be with all the other code that uses this idiom.