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 ...