Re: [PATCH 3/7] btrfs: Use filemap_invalidate_pages()
Boris Burkov <[email protected]>
| Newsgroups | org.kvack.linux-mm,dev.linux.lists.fuse-devel,org.kernel.vger.linux-block,org.kernel.vger.linux-btrfs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-nfs |
|---|---|
| Message-ID | <[email protected]> |
On Thu, Aug 20, 2026 at 08:33:36PM +0100, Matthew Wilcox (Oracle) wrote: > btrfs relies on invalidate_inode_pages2() / > invalidate_inode_pages2_range() doing writeback by calling > btrfs_launder_folio(). While this works, it is inefficient as each I don't believe btrfs_launder_folio() is doing writeback, it is just dropping otherwise leaked qgroup reservation. So this part of the commit message feels inaccurate to me, at least. > folio is written back and waited for individually. Far better to call > filemap_invalidate_pages() which will do a bulk write first, then remove > the page cache. > > With this done, btrfs_launder_folio() no longer needs to exist so > delete it. > > Signed-off-by: Matthew Wilcox (Oracle) <[email protected]> > --- > fs/btrfs/direct-io.c | 2 +- > fs/btrfs/disk-io.c | 11 +++++++---- > fs/btrfs/free-space-cache.c | 4 ++-- > fs/btrfs/inode.c | 12 ++---------- > fs/btrfs/volumes.c | 4 ++-- > 5 files changed, 14 insertions(+), 19 deletions(-) > > diff --git a/fs/btrfs/direct-io.c b/fs/btrfs/direct-io.c > index 460326d34143..4bb5890d0898 100644 > --- a/fs/btrfs/direct-io.c > +++ b/fs/btrfs/direct-io.c > @@ -115,7 +115,7 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend, > /* > * We could trigger writeback for this range (and wait > * for it to complete) and then invalidate the pages for > - * this range (through invalidate_inode_pages2_range()), > + * this range (through filemap_invalidate_pages()), > * but that can lead us to a deadlock with a concurrent > * call to readahead (a buffered read or a defrag call > * triggered a readahead) on a page lock due to an > diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c > index 2f1666d9544e..2cf9189225c9 100644 > --- a/fs/btrfs/disk-io.c > +++ b/fs/btrfs/disk-io.c > @@ -3304,7 +3304,8 @@ static void invalidate_and_check_btree_folios(struct btrfs_fs_info *fs_info) > struct extent_buffer *eb; > int ret; > > - ret = invalidate_inode_pages2(fs_info->btree_inode->i_mapping); > + ret = filemap_invalidate_pages(fs_info->btree_inode->i_mapping, 0, > + OFFSET_MAX); > if (likely(ret == 0)) > return; > > @@ -3339,7 +3340,8 @@ static void invalidate_and_check_btree_folios(struct btrfs_fs_info *fs_info) > rcu_read_lock(); > } > rcu_read_unlock(); > - invalidate_inode_pages2(fs_info->btree_inode->i_mapping); > + filemap_invalidate_pages(fs_info->btree_inode->i_mapping, 0, > + OFFSET_MAX); > } > > static u32 calc_block_max_order(u32 sectorsize_bits) > @@ -4739,7 +4741,8 @@ static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root) > unsigned int nofs_flag; > > nofs_flag = memalloc_nofs_save(); > - invalidate_inode_pages2(inode->i_mapping); > + filemap_invalidate_pages(inode->i_mapping, 0, > + OFFSET_MAX); I believe that this was the original motivating call to invalidate_inode_pages2 that I cared about. The context it runs in is when the filesystem has failed on a transaction and needs to invalidate the remaining dirty pages that have delalloc associated with them. I am trying to figure out if trying to force the writeback in this semi-failed context will also result in freeing the reservation, and also testing this patch series on the test that I originally fixed with launder_folio(). With all that said, thank you for working on cleaning up the mess I made by adding this "creative" usage of ->launder_folio(). Hopefully we can figure this out cleanly. Thanks, Boris > memalloc_nofs_restore(nofs_flag); > iput(inode); > } > @@ -4837,7 +4840,7 @@ static void btrfs_cleanup_bg_io(struct btrfs_block_group *cache) > unsigned int nofs_flag; > > nofs_flag = memalloc_nofs_save(); > - invalidate_inode_pages2(inode->i_mapping); > + filemap_invalidate_pages(inode->i_mapping, 0, OFFSET_MAX); > memalloc_nofs_restore(nofs_flag); > > BTRFS_I(inode)->generation = 0; > diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c > index e2af75a205ea..a5d5eba2c85d 100644 > --- a/fs/btrfs/free-space-cache.c > +++ b/fs/btrfs/free-space-cache.c > @@ -1307,7 +1307,7 @@ static int __btrfs_wait_cache_io(struct btrfs_root *root, > io_ctl->entries, io_ctl->bitmaps); > out: > if (ret) { > - invalidate_inode_pages2(inode->i_mapping); > + filemap_invalidate_pages(inode->i_mapping, 0, OFFSET_MAX); > BTRFS_I(inode)->generation = 0; > if (block_group) > btrfs_debug(root->fs_info, > @@ -1500,7 +1500,7 @@ static int __btrfs_write_out_cache(struct inode *inode, > io_ctl->inode = NULL; > io_ctl_free(io_ctl); > if (ret) { > - invalidate_inode_pages2(inode->i_mapping); > + filemap_invalidate_pages(inode->i_mapping, 0, OFFSET_MAX); > BTRFS_I(inode)->generation = 0; > } > btrfs_update_inode(trans, BTRFS_I(inode)); > diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c > index 2534cd9284d5..a1bb73f083aa 100644 > --- a/fs/btrfs/inode.c > +++ b/fs/btrfs/inode.c > @@ -7616,12 +7616,6 @@ static void wait_subpage_spinlock(struct folio *folio) > spin_unlock_irq(&bfs->lock); > } > > -static int btrfs_launder_folio(struct folio *folio) > -{ > - return btrfs_qgroup_free_data(folio_to_inode(folio), NULL, folio_pos(folio), > - folio_size(folio), NULL); > -} > - > static bool __btrfs_release_folio(struct folio *folio, gfp_t gfp_flags) > { > if (try_release_extent_mapping(folio, gfp_flags)) { > @@ -10027,9 +10021,8 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from, > ret = btrfs_wait_ordered_range(inode, start, num_bytes); > if (ret) > goto out_cb; > - ret = invalidate_inode_pages2_range(inode->vfs_inode.i_mapping, > - start >> PAGE_SHIFT, > - end >> PAGE_SHIFT); > + ret = filemap_invalidate_pages(inode->vfs_inode.i_mapping, > + start, end); > if (ret) > goto out_cb; > btrfs_lock_extent(io_tree, start, end, &cached_state); > @@ -10782,7 +10775,6 @@ static const struct address_space_operations btrfs_aops = { > .writepages = btrfs_writepages, > .readahead = btrfs_readahead, > .invalidate_folio = btrfs_invalidate_folio, > - .launder_folio = btrfs_launder_folio, > .release_folio = btrfs_release_folio, > .migrate_folio = btrfs_migrate_folio, > .dirty_folio = btrfs_data_dirty_folio, > diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c > index 6eab4cc73ce4..0301465ab87f 100644 > --- a/fs/btrfs/volumes.c > +++ b/fs/btrfs/volumes.c > @@ -1370,8 +1370,8 @@ struct btrfs_super_block *btrfs_read_disk_super(struct block_device *bdev, > * Drop the page of the primary superblock, so later read will > * always read from the device. > */ > - invalidate_inode_pages2_range(mapping, bytenr >> PAGE_SHIFT, > - (bytenr + BTRFS_SUPER_INFO_SIZE) >> PAGE_SHIFT); > + filemap_invalidate_pages(mapping, bytenr, > + bytenr + BTRFS_SUPER_INFO_SIZE - 1); > } > > filemap_invalidate_lock_shared(mapping); > -- > 2.47.3 >