On Tue, Sep 29, 2020 at 10:46:53AM +0200, Jan Kara wrote: > On Mon 14-09-20 14:00:34, Matthew Wilcox (Oracle) wrote: > > Rewrite shmem_seek_hole_data() and move it to filemap.c. > > > > + rcu_read_lock(); > > + while ((page = xas_find_get_entry(&xas, max, XA_PRESENT))) { > > + loff_t pos = xas.xa_index * PAGE_SIZE; > > OK, but for ordinary filesystems this could be problematic because of > exceptional entries?
For ordinary filesystems, I have this queued up on top: http://git.infradead.org/users/willy/pagecache.git/commitdiff/02c740b215bab901f95a560759b3bd906648da08 which handles exceptional entries. It treats shadow/swap/DAX entries the same -- there's definitely data there, it's just not in a struct page right now. > Also for shmem you've dropped the PageUptodate check which I'm not sure is > safe? That was unintentional. I did run xfstests against this patch (just did it again ... it passes), so I suspect it doesn't create a !Uptodate page. I'll see if I can enhance the existing xfstests to catch this case. The patch I link to above also doesn't handle !Uptodate pages on shmem filesystems the same way that the current code does. So ... on top of this patch, I propose doing this: @@ -2416,6 +2416,14 @@ generic_file_read_iter(struct kiocb *iocb, struct iov_ite r *iter) } EXPORT_SYMBOL(generic_file_read_iter); +static inline loff_t page_seek_hole_data(struct page *page, + loff_t start, loff_t end, bool seek_data) +{ + if (xa_is_value(page) || PageUptodate(page)) + return seek_data ? start : end; + return seek_data ? end : start; +} + static inline unsigned int seek_page_size(struct xa_state *xas, struct page *page) { @@ -2463,10 +2471,10 @@ loff_t mapping_seek_hole_data(struct address_space *mapping, loff_t start, start = pos; } - if (seek_data) + pos += seek_page_size(&xas, page); + start = page_seek_hole_data(page, start, pos, seek_data); + if (start < pos) goto unlock; - - start = pos + seek_page_size(&xas, page); } rcu_read_unlock(); ... and then rebasing the other patch on top of this works out nicely. Here's the result: http://git.infradead.org/users/willy/pagecache.git/commitdiff/9eb3f496b7cdcdcae83026e861e148f46921c367 http://git.infradead.org/users/willy/pagecache.git/commitdiff/7d93274088f0872d849a906d783dc260bee106b9