Re: [PATCH] mm/filemap: Use filemap_read_page in filemap_fault

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Mar 02, 2021 at 10:07:35PM -0800, Andrew Morton wrote:
> > > We also handle AOP_TRUNCATED_PAGE which the present code fails to do. 
> > > Should this be in the changelog?
> > 
> > No, the present code does handle AOP_TRUNCATED_PAGE.  It's perhaps not
> > the clearest in the diff, but it's there.  Here's git show -U5:
> > 
> > -       ClearPageError(page);
> >         fpin = maybe_unlock_mmap_for_io(vmf, fpin);
> > -       error = mapping->a_ops->readpage(file, page);
> > -       if (!error) {
> > -               wait_on_page_locked(page);
> > -               if (!PageUptodate(page))
> > -                       error = -EIO;
> > -       }
> > +       error = filemap_read_page(file, mapping, page);
> >         if (fpin)
> >                 goto out_retry;
> >         put_page(page);
> >  
> >         if (!error || error == AOP_TRUNCATED_PAGE)
> >                 goto retry_find;
> >  
> > -       shrink_readahead_size_eio(ra);
> >         return VM_FAULT_SIGBUS;
> 
> But ->readpage() doesn't check for !mapping (does it?).  So the
> ->readpage() cannot return AOP_TRUNCATED_PAGE.

Filesystems can return AOP_TRUNCATED_PAGE from ->readpage.  I think
ocfs2 is the only one to do so currently.

> However filemap_read_page() does check for !mapping.  So current -linus
> doesn't check for !mapping, and post-willy does do this?

Oh!  I see what you mean now.  I can't come up with a sequence of events
where this check is going to do anything useful.  It may be left over from
earlier times.  Here's an earlier version of generic_file_buffered_read()
before Kent refactored it:

                /* Start the actual read. The read will unlock the page. */
                error = mapping->a_ops->readpage(filp, page);
[...]
                if (!PageUptodate(page)) {
                        error = lock_page_killable(page);
                        if (unlikely(error))
                                goto readpage_error;
                        if (!PageUptodate(page)) {
                                if (page->mapping == NULL) {
                                        /*
                                         * invalidate_mapping_pages got it
                                         */
                                        unlock_page(page);
                                        put_page(page);


But here's the thing ... invalidate_mapping_pages() doesn't
ClearPageUptodate.  The only places where we ClearPageUptodate is on an
I/O error.

So ... as far as I can tell, the only way to hit this is:

 - Get an I/O error during the wait
 - Have another thread cause the page to be removed from the page cache
   (eg do direct I/O to the file) before this thread is run.

and the consequence to this change is that we have another attempt to
read the page instead of returning an error immediately.  I'm OK with
that unintentional change, although I think the previous behaviour was
also perfectly acceptable (after all, there was an I/O error while trying
to read this page).

Delving into the linux-fullhistory tree, this code was introduced by ...

commit 56f0d5fe6851037214a041a5cb4fc66199256544
Author: Andrew Morton <akpm@xxxxxxxx>
Date:   Fri Jan 7 22:03:01 2005 -0800

    [PATCH] readpage-vs-invalidate fix

    A while ago we merged a patch which tried to solve a problem wherein a
    concurrent read() and invalidate_inode_pages() would cause the read() to
    return -EIO because invalidate cleared PageUptodate() at the wrong time.

We no longer clear PageUptodate, so I think this is stale code?  Perhaps
you could check with the original author ...




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux