Linux Btrfs filesystem development
 help / color / mirror / Atom feed
From: Qu Wenruo <wqu@suse.com>
To: linux-btrfs@vger.kernel.org
Cc: linux-fsdevel@vger.kernel.org
Subject: Re: [PATCH 3/4] btrfs: replace single page bio_iter_iovec() usage
Date: Mon, 1 Sep 2025 15:55:40 +0930	[thread overview]
Message-ID: <f7e848dc-7dd5-4c8b-9053-c38eb6c7739c@suse.com> (raw)
In-Reply-To: <e1467a67f550f4d54afeac87051621fe58733ca5.1756703958.git.wqu@suse.com>



在 2025/9/1 14:54, Qu Wenruo 写道:
> There are several functions inside btrfs calling bio_iter_iovec(),
> mostly to do a block-by-block iteration on a bio.
> 
> - btrfs_check_read_bio()
> - btrfs_decompress_buf2page()
> - index_one_bio() from raid56
> 
> However that helper is single page based, meaning it will never return a
> bv_len larger than PAGE_SIZE. For now it's fine as we only support bs <=
> ps at most.
> 
> But for the incoming bs > ps support, we want to get bv_len larger than
> PAGE_SIZE so that the bio_vec will cover a full block, not just part of
> the large folio of the block.
> 
> In fact the call site inside btrfs_check_read_bio() will trigger
> ASSERT() inside btrfs_data_csum_ok() when bs > ps support is enabled.
> As bio_iter_iovec() will return a bv_len == 4K, meanwhile the bs is
> larger than 4K, triggering the ASSERT().
> 
> Replace those call sites with mp_bvec_iter_bvec(), which will return the
> full length of from the bi_io_vec array.
> Currently all call sites are already doing extra loop inside the bvec
> range for bs < ps support, so they will be fine.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
>   fs/btrfs/bio.c         | 3 ++-
>   fs/btrfs/compression.c | 3 +--
>   fs/btrfs/raid56.c      | 2 +-
>   3 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c
> index ea7f7a17a3d5..f7aea4310dd6 100644
> --- a/fs/btrfs/bio.c
> +++ b/fs/btrfs/bio.c
> @@ -277,8 +277,9 @@ static void btrfs_check_read_bio(struct btrfs_bio *bbio, struct btrfs_device *de
>   	bbio->bio.bi_status = BLK_STS_OK;
>   
>   	while (iter->bi_size) {
> -		struct bio_vec bv = bio_iter_iovec(&bbio->bio, *iter);
> +		struct bio_vec bv = mp_bvec_iter_bvec(bbio->bio.bi_io_vec, *iter);

This multi-page conversion is going to hit VM_BUG_ON() when 
btrfs_data_csum_ok() got a csum mismatch and has to call memzero_bvec(), 
which is a single page only helper.

I'm wondering what is the proper handling for mp bvec.


Since we're inside one mp vec, all the pages in the bvec should be 
physically contiguous. But will highmem sneak into a bvec?

If not, the memzero_page()'s check looks a little overkilled.

And if highmem page can sneak in, it means we will need a loop to 
map/zero/unmap...

Thanks,
Qu
>   
> +		ASSERT(bv.bv_len >= sectorsize && IS_ALIGNED(bv.bv_len, sectorsize));
>   		bv.bv_len = min(bv.bv_len, sectorsize);
>   		if (status || !btrfs_data_csum_ok(bbio, dev, offset, &bv))
>   			fbio = repair_one_sector(bbio, offset, &bv, fbio);
> diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
> index 068339e86123..8b415c780ba8 100644
> --- a/fs/btrfs/compression.c
> +++ b/fs/btrfs/compression.c
> @@ -1227,14 +1227,13 @@ int btrfs_decompress_buf2page(const char *buf, u32 buf_len,
>   	cur_offset = decompressed;
>   	/* The main loop to do the copy */
>   	while (cur_offset < decompressed + buf_len) {
> -		struct bio_vec bvec;
> +		struct bio_vec bvec = mp_bvec_iter_bvec(orig_bio->bi_io_vec, orig_bio->bi_iter);
>   		size_t copy_len;
>   		u32 copy_start;
>   		/* Offset inside the full decompressed extent */
>   		u32 bvec_offset;
>   		void *kaddr;
>   
> -		bvec = bio_iter_iovec(orig_bio, orig_bio->bi_iter);
>   		/*
>   		 * cb->start may underflow, but subtracting that value can still
>   		 * give us correct offset inside the full decompressed extent.
> diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
> index 3ff2bedfb3a4..df48dd6c3f54 100644
> --- a/fs/btrfs/raid56.c
> +++ b/fs/btrfs/raid56.c
> @@ -1214,7 +1214,7 @@ static void index_one_bio(struct btrfs_raid_bio *rbio, struct bio *bio)
>   	while (iter.bi_size) {
>   		unsigned int index = (offset >> sectorsize_bits);
>   		struct sector_ptr *sector = &rbio->bio_sectors[index];
> -		struct bio_vec bv = bio_iter_iovec(bio, iter);
> +		struct bio_vec bv = mp_bvec_iter_bvec(bio->bi_io_vec, iter);
>   
>   		sector->has_paddr = true;
>   		sector->paddr = bvec_phys(&bv);


  reply	other threads:[~2025-09-01  6:25 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-01  5:24 [PATCH 0/4] btrfs: bs > ps support preparation Qu Wenruo
2025-09-01  5:24 ` [PATCH 1/4] btrfs: support all block sizes which is no larger than page size Qu Wenruo
2025-09-01  5:24 ` [PATCH 2/4] btrfs: cache max and min order inside btrfs_fs_info Qu Wenruo
2025-09-01 18:10   ` David Sterba
2025-09-02  3:46   ` kernel test robot
2025-09-01  5:24 ` [PATCH 3/4] btrfs: replace single page bio_iter_iovec() usage Qu Wenruo
2025-09-01  6:25   ` Qu Wenruo [this message]
2025-09-01  5:24 ` [PATCH 4/4] btrfs: replace bio_for_each_segment usage Qu Wenruo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f7e848dc-7dd5-4c8b-9053-c38eb6c7739c@suse.com \
    --to=wqu@suse.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox