On Wed 24-02-21 09:44:53, Jens Axboe wrote: > For O_DIRECT reads/writes, we check if we need to issue a call to > filemap_write_and_wait_range() to issue and/or wait for writeback for any > page in the given range. The existing mechanism just checks for a page in > the range, which is suboptimal for IOCB_NOWAIT as we'll fallback to the > slow path (and needing retry) if there's just a clean page cache page in > the range. > > Provide filemap_range_needs_writeback() which tries a little harder to > check if we actually need to issue and/or wait for writeback in the > range. > > Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> Looks good to me. Feel free to add: Reviewed-by: Jan Kara <jack@xxxxxxx> Honza > --- > include/linux/fs.h | 2 ++ > mm/filemap.c | 43 +++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 45 insertions(+) > > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 6d8b1e7337e4..4925275e6365 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -2633,6 +2633,8 @@ static inline int filemap_fdatawait(struct address_space *mapping) > > extern bool filemap_range_has_page(struct address_space *, loff_t lstart, > loff_t lend); > +extern bool filemap_range_needs_writeback(struct address_space *, > + loff_t lstart, loff_t lend); > extern int filemap_write_and_wait_range(struct address_space *mapping, > loff_t lstart, loff_t lend); > extern int __filemap_fdatawrite_range(struct address_space *mapping, > diff --git a/mm/filemap.c b/mm/filemap.c > index 6ff2a3fb0dc7..13338f877677 100644 > --- a/mm/filemap.c > +++ b/mm/filemap.c > @@ -635,6 +635,49 @@ static bool mapping_needs_writeback(struct address_space *mapping) > return mapping->nrpages; > } > > +/** > + * filemap_range_needs_writeback - check if range potentially needs writeback > + * @mapping: address space within which to check > + * @start_byte: offset in bytes where the range starts > + * @end_byte: offset in bytes where the range ends (inclusive) > + * > + * Find at least one page in the range supplied, usually used to check if > + * direct writing in this range will trigger a writeback. Used by O_DIRECT > + * read/write with IOCB_NOWAIT, to see if the caller needs to do > + * filemap_write_and_wait_range() before proceeding. > + * > + * Return: %true if the caller should do filemap_write_and_wait_range() before > + * doing O_DIRECT to a page in this range, %false otherwise. > + */ > +bool filemap_range_needs_writeback(struct address_space *mapping, > + loff_t start_byte, loff_t end_byte) > +{ > + XA_STATE(xas, &mapping->i_pages, start_byte >> PAGE_SHIFT); > + pgoff_t max = end_byte >> PAGE_SHIFT; > + struct page *page; > + > + if (!mapping_needs_writeback(mapping)) > + return false; > + if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) && > + !mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK)) > + return false; > + if (end_byte < start_byte) > + return false; > + > + rcu_read_lock(); > + xas_for_each(&xas, page, max) { > + if (xas_retry(&xas, page)) > + continue; > + if (xa_is_value(page)) > + continue; > + if (PageDirty(page) || PageLocked(page) || PageWriteback(page)) > + break; > + } > + rcu_read_unlock(); > + return page != NULL; > +} > +EXPORT_SYMBOL_GPL(filemap_range_needs_writeback); > + > /** > * filemap_write_and_wait_range - write out & wait on a file range > * @mapping: the address_space for the pages > -- > 2.30.0 > -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR