mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Qu Wenruo <wqu@suse.com>
To: socketpair@gmail.com, David Sterba <dsterba@suse.com>,
	Chris Mason <mason@kernel.org>
Cc: Mark Harmstone <mark@harmstone.com>,
	linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] btrfs: tag all metadata I/O with REQ_META
Date: Thu, 5 Nov 2026 19:37:43 +1030	[thread overview]
Message-ID: <9e2c808e-6edf-42b4-a70f-5fecc8f1eb69@suse.com> (raw)
In-Reply-To: <20261104-btrfs-sb-read-req-meta-v1-1-e06b4d059897@gmail.com>



在 2026/11/4 21:08, Mark Korenberg via B4 Relay 写道:
> From: Mark Korenberg <socketpair@gmail.com>
> 
> Tree block reads and writes and super block writes carry REQ_META, but
> several other paths do metadata I/O without it, so the block layer and
> drivers (blktrace, BFQ, blk-cgroup, wbt, ublk) see it as data I/O:
> 
> - scrub reads super blocks with a bare REQ_OP_READ;
> - btrfs_repair_bbio_failure() rewrites a bad tree block copy without it;
> - RAID5/6 rbios build new per-device bios from a bare op, so all tree
>    block writes on RAID5/6, and recovery reads, lose the flag;

I think this can lead to very cursed combinations.

A RAID56 mixed block groups. In that case, how do you handle recovery?

A vertical stripe can contain both data and metadata, should the 
recovery be counted as data or meta?


> - scrub and dev-replace read, repair and copy metadata block groups
>    without it;

Again, what if a block group is mixed?

> - remap relocation copies metadata block groups without it.
> 
> Tag these by the chunk type: metadata and system chunks get REQ_META,
> mixed chunks do not,

That almost kill the meaning of re-introduce this flag.

I'm more interested in how other dm devices, like LVM/dmraid handle 
those REQ_META flags.

E.g. a btrfs over a LVM/mdraid, and btrfs passes REQ_META for a tree 
block read, then should the LVM/mdraid pass REQ_META to the underlying 
devices?

If not, I see no particular reason to strictly follow that for 
scrub/dev-replace/raid56 recovery.

> as they also hold data.  All bios of a block group
> then carry the same flag and stay mergeable (blk-cgroup does not merge
> bios that differ in REQ_META).

I'm more interested in what you really want to archieve?

Just to make the REQ_META more consistent?

> 
> This does not change the btrfs submission path: scrub and remap bbios
> skip checksumming, and scrub_read_endio() and scrub_repair_read_endio()
> do not wait for other I/O, so running them on endio_meta_workers is
> fine.  With blk-cgroup, metadata scrub I/O is now issued as root and
> charged back, like other metadata I/O.
> 
> bdev_rw_virt() takes an enum req_op, but gfs2 and xfs already pass
> REQ_META through it.
> 
> Signed-off-by: Mark Korenberg <socketpair@gmail.com>
> ---
> I noticed this in the request log of a ublk zoned device: tree block
> reads and writes arrive with UBLK_IO_F_META, while the super block
> reads at mount do not.  An audit of all bio submission sites in
> fs/btrfs then found the paths listed in the commit message.
> 
> The super block reads at mount are the one case I left alone, along
> with a few others:
> - btrfs_read_disk_super() and sb_write_pointer() read through the
>    block device page cache, which cannot pass REQ_META.  That is on
>    purpose since 8f32380d3f29 ("btrfs: use the page cache for super
>    block reading"), to stay coherent with mkfs and udev.  The same goes
>    for btrfs_scratch_superblocks().
> - Discards free space, and the empty preflush of write_dev_flush()
>    covers the whole device.
> 
> Testing: virtme-ng VM, memory backed null_blk, tracefs
> block:block_bio_queue, every bio classified as super block or by the
> chunk type of its dev extent:
> - RAID5 metadata and data: copy /usr/include, scrub, then replace
>    devid 1 with a new device
> - DUP metadata with one copy of a leaf corrupted, read the directory
>    until "read error corrected"
> 
> Bios of metadata chunks, with REQ_META / without:
> 
>                                  before      after
>    RAID5 writes (and RMW reads)  0 / 274     245 / 0
>    scrub                         0 / 390     369 / 0
>    scrub, super blocks           0 / 6         6 / 0
>    dev-replace                   0 / 258     243 / 0
>    repair write                  0 / 1         1 / 0
> 
> No data bio carries REQ_META, before or after.  No new warnings, W=1
> build clean.
> 
> Not tested: the remap relocation part, btrfs-progs 7.1 here cannot
> create a remap-tree filesystem.  Mark, could you give it a look?
> 
> The audit, the patch and the test were drafted with the help of an AI
> assistant (Claude Opus 5.5).
> ---
>   fs/btrfs/bio.c        |  3 ++-
>   fs/btrfs/raid56.c     |  3 ++-
>   fs/btrfs/relocation.c | 13 ++++++++-----
>   fs/btrfs/scrub.c      |  5 +++--
>   fs/btrfs/volumes.h    | 10 ++++++++++
>   5 files changed, 25 insertions(+), 9 deletions(-)
> 
> diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c
> index 2e12a6d7e16f..efbce4d549ff 100644
> --- a/fs/btrfs/bio.c
> +++ b/fs/btrfs/bio.c
> @@ -951,7 +951,8 @@ int btrfs_repair_bbio_failure(struct btrfs_bio *bbio, const struct bvec_iter *or
>   	}
>   
>   	repair_bio = bio_alloc(smap.dev->bdev, max(1, length >> PAGE_SHIFT),
> -			       REQ_OP_WRITE | REQ_SYNC, GFP_NOFS);
> +			       REQ_OP_WRITE | REQ_SYNC |
> +			       (is_data_inode(inode) ? 0 : REQ_META), GFP_NOFS);
>   	repair_bio->bi_iter.bi_sector = smap.physical >> SECTOR_SHIFT;
>   	while (cur < length) {
>   		struct page *page = bio_iter_page(&bbio->bio, iter);
> diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
> index a8a8004bb14c..1b5cdcdeced3 100644
> --- a/fs/btrfs/raid56.c
> +++ b/fs/btrfs/raid56.c
> @@ -1205,7 +1205,8 @@ static int rbio_add_io_paddrs(struct btrfs_raid_bio *rbio, struct bio_list *bio_
>   	/* put a new bio on the list */
>   	bio = bio_alloc(stripe->dev->bdev,
>   			max(rbio->bioc->stripe_len >> PAGE_SHIFT, 1),
> -			op, GFP_NOFS);
> +			op | btrfs_chunk_req_meta(rbio->bioc->map_type),
> +			GFP_NOFS);

At least I do not think it's a good idea to touch RAID56, unless you can 
prove that mdraid is also passing those flags.

I want to align btrfs to existing RAID56 implementation, not the opposite.

>   	bio->bi_iter.bi_sector = disk_start >> SECTOR_SHIFT;
>   	bio->bi_private = rbio;
>   
> diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
> index b2ac5b836b21..af17be38eea3 100644
> --- a/fs/btrfs/relocation.c
> +++ b/fs/btrfs/relocation.c
> @@ -4146,8 +4146,9 @@ static int copy_remapped_data_io(struct btrfs_fs_info *fs_info,
>   }
>   
>   static int copy_remapped_data(struct btrfs_fs_info *fs_info, u64 old_addr,
> -			      u64 new_addr, u64 length)
> +			      u64 new_addr, u64 length, u64 type)
>   {
> +	const blk_opf_t meta = btrfs_chunk_req_meta(type);
>   	int ret;
>   	const u64 copy_len = min_t(u64, length, SZ_1M);
>   	struct page **pages;
> @@ -4172,12 +4173,12 @@ static int copy_remapped_data(struct btrfs_fs_info *fs_info, u64 old_addr,
>   		to_copy = min_t(u64, to_copy, BIO_MAX_VECS << PAGE_SHIFT);
>   
>   		ret = copy_remapped_data_io(fs_info, &priv, pages, old_addr,
> -					    to_copy, REQ_OP_READ);
> +					    to_copy, REQ_OP_READ | meta);
>   		if (ret)
>   			goto end;
>   
>   		ret = copy_remapped_data_io(fs_info, &priv, pages, new_addr,
> -					    to_copy, REQ_OP_WRITE);
> +					    to_copy, REQ_OP_WRITE | meta);
>   		if (ret)
>   			goto end;
>   
> @@ -4344,7 +4345,8 @@ static int move_existing_remap(struct btrfs_fs_info *fs_info,
>   		goto end;
>   	}
>   
> -	ret = copy_remapped_data(fs_info, new_addr, dest_addr, dest_length);
> +	ret = copy_remapped_data(fs_info, new_addr, dest_addr, dest_length,
> +				 bg->flags);
>   	if (unlikely(ret))
>   		goto end;
>   
> @@ -5161,7 +5163,8 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info,
>   		}
>   	}
>   
> -	ret = copy_remapped_data(fs_info, start, new_addr, length);
> +	ret = copy_remapped_data(fs_info, start, new_addr, length,
> +				 src_bg->flags);
>   	if (ret) {
>   		btrfs_abort_transaction(trans, ret);
>   		goto fail;
> diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
> index 98362c91bce4..269948b1caeb 100644
> --- a/fs/btrfs/scrub.c
> +++ b/fs/btrfs/scrub.c
> @@ -934,7 +934,8 @@ static struct btrfs_bio *alloc_scrub_bbio(struct btrfs_fs_info *fs_info,
>   	 * enough to contain the full stripe.
>   	 */
>   	bbio = btrfs_bio_alloc(round_up(stripe->stripe_len, PAGE_SIZE) >>
> -			       PAGE_SHIFT, opf,
> +			       PAGE_SHIFT,
> +			       opf | btrfs_chunk_req_meta(stripe->bg->flags),
>   			       BTRFS_I(fs_info->btree_inode),
>   			       logical, end_io, stripe);
>   	bbio->is_scrub = true;
> @@ -2957,7 +2958,7 @@ static int scrub_one_super(struct scrub_ctx *sctx, struct btrfs_device *dev,
>   	int ret;
>   
>   	ret = bdev_rw_virt(dev->bdev, physical >> SECTOR_SHIFT, sb,
> -			BTRFS_SUPER_INFO_SIZE, REQ_OP_READ);
> +			BTRFS_SUPER_INFO_SIZE, REQ_OP_READ | REQ_META);
>   	if (ret < 0)
>   		return ret;
>   	ret = btrfs_check_super_csum(fs_info, sb);
> diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
> index 891bc2432870..66796f09eae8 100644
> --- a/fs/btrfs/volumes.h
> +++ b/fs/btrfs/volumes.h
> @@ -709,6 +709,16 @@ static inline enum btrfs_map_op btrfs_op(const struct bio *bio)
>   	}
>   }
>   
> +/*
> + * REQ_META for I/O to a chunk of type @type that holds only tree blocks.
> + * A mixed chunk also holds data and gets no flag, otherwise its data
> + * would be tagged as metadata.
> + */
> +static inline blk_opf_t btrfs_chunk_req_meta(u64 type)
> +{
> +	return (type & BTRFS_BLOCK_GROUP_DATA) ? 0 : REQ_META;

Missing BLOCK_GROUP_METADATA_REMAP and also handling BLOCK_GROUP_SYSTEM.

> +}
> +
>   static inline unsigned long btrfs_chunk_item_size(int num_stripes)
>   {
>   	return offsetof(struct btrfs_chunk, stripe) +
> 
> ---
> base-commit: df5b88a7914e18488908ddf13e14e31ab39f954c
> change-id: 20261104-btrfs-sb-read-req-meta-7be597aaaa51
> 
> Best regards,


  parent reply	other threads:[~2026-11-05  9:07 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-04 10:38 Mark Korenberg via B4 Relay
2026-11-04 17:21 ` David Sterba
2026-11-04 19:03   ` Марк Коренберг
2026-11-05  9:07 ` Qu Wenruo [this message]
2026-11-05 14:47   ` Mark Korenberg

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=9e2c808e-6edf-42b4-a70f-5fecc8f1eb69@suse.com \
    --to=wqu@suse.com \
    --cc=dsterba@suse.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mark@harmstone.com \
    --cc=mason@kernel.org \
    --cc=socketpair@gmail.com \
    /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

all inboxes | Powered by JetHome®