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
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.