mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/2] btrfs: tag tree block repair and RAID5/6 metadata I/O with REQ_META
@ 2026-11-06 17:33 Mark Korenberg via B4 Relay
  2026-11-06 17:33 ` [PATCH v2 1/2] btrfs: tag tree block repair writes " Mark Korenberg via B4 Relay
  2026-11-06 17:33 ` [PATCH v2 2/2] btrfs: raid56: pass REQ_META to per-device bios Mark Korenberg via B4 Relay
  0 siblings, 2 replies; 5+ messages in thread
From: Mark Korenberg via B4 Relay @ 2026-11-06 17:33 UTC (permalink / raw)
  To: David Sterba, Chris Mason
  Cc: Qu Wenruo, linux-btrfs, linux-kernel, Mark Korenberg

Tree block reads and writes carry REQ_META, so the layers below see
them as metadata I/O: blk-cgroup issues them as root to avoid priority
inversion, wbt does not throttle them, blktrace shows them as such, and
ublk passes the flag to its server as UBLK_IO_F_META.  Two paths of
normal operation lose the flag:

- Patch 1: when a tree block read finds a bad copy, the rewrite from a
  good copy goes out as a plain write.
- Patch 2: on RAID5/6 the rbio builds new per-device bios and drops the
  flag, so all tree block writes, and tree block reads rebuilt from the
  other stripes (for example with a missing device), go out as data
  I/O.  On the other profiles the per-device bios are clones and keep
  it.  Now the flag follows the bios the rbio serves, P/Q included, so
  mixed block groups need no special case.

Thanks to Qu for the review of v1.  I agree that background work
should not get the priority of metadata I/O, so v2 drops the scrub,
dev-replace and relocation parts: they stay untagged even when they
handle metadata, and so do the rebuilds and parity checks that scrub
does on RAID5/6.

RAID5/6 stays, as its own patch, because what it tags is regular
operation, not background work.  The writes are the normal tree block
writeback, which carries REQ_META on every other profile.  A rebuild
read serves a tree block read, the same read that carries REQ_META when
no rebuild is needed.

Zoned devices see no change: they support neither RAID5/6 nor in-place
repair, btrfs_repair_one_zone() relocates the block group instead.

Testing: virtme-ng VM, memory backed null_blk, tracefs
block:block_bio_queue, every bio classified by the chunk type of its
dev extent:
- RAID5 metadata and data, copy /usr/include: all metadata bios, P/Q
  and RMW reads included, carry REQ_META (before: none).  Scrub and the
  copy of a dev-replace carry none.
- RAID5 with one device missing, mounted degraded, all files read: all
  696 metadata bios carry REQ_META (before: the 344 rebuild reads did
  not).
- DUP metadata with one copy of a leaf corrupted, read back: the repair
  write carries REQ_META.
No bio to a data chunk carries the flag, no new warnings, W=1 build
clean.

Changes in v2:
- Leave scrub, dev-replace and remap relocation untagged, including the
  super block reads of scrub: background work (Qu).
- RAID5/6: take REQ_META from the bios the rbio serves instead of the
  chunk type, which also covers rebuild reads and mixed block groups,
  and move it to its own patch (Qu).
- Link to v1: https://lore.kernel.org/r/20261104-btrfs-sb-read-req-meta-v1-1-e06b4d059897@gmail.com

The audit, the patches and the tests were drafted with the help of an
AI assistant (Claude Opus 5.5).

---
Mark Korenberg (2):
      btrfs: tag tree block repair writes with REQ_META
      btrfs: raid56: pass REQ_META to per-device bios

 fs/btrfs/bio.c    |  3 ++-
 fs/btrfs/raid56.c | 14 +++++++++++---
 fs/btrfs/raid56.h |  7 +++++++
 3 files changed, 20 insertions(+), 4 deletions(-)
---
base-commit: df5b88a7914e18488908ddf13e14e31ab39f954c
change-id: 20261104-btrfs-sb-read-req-meta-7be597aaaa51

Best regards,
-- 
Mark Korenberg <socketpair@gmail.com>



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 1/2] btrfs: tag tree block repair writes with REQ_META
  2026-11-06 17:33 [PATCH v2 0/2] btrfs: tag tree block repair and RAID5/6 metadata I/O with REQ_META Mark Korenberg via B4 Relay
@ 2026-11-06 17:33 ` Mark Korenberg via B4 Relay
  2026-11-06 20:31   ` Qu Wenruo
  2026-11-06 17:33 ` [PATCH v2 2/2] btrfs: raid56: pass REQ_META to per-device bios Mark Korenberg via B4 Relay
  1 sibling, 1 reply; 5+ messages in thread
From: Mark Korenberg via B4 Relay @ 2026-11-06 17:33 UTC (permalink / raw)
  To: David Sterba, Chris Mason
  Cc: Qu Wenruo, linux-btrfs, linux-kernel, Mark Korenberg

From: Mark Korenberg <socketpair@gmail.com>

When a tree block read finds a bad copy, btrfs_repair_eb_io_failure()
rewrites it from a good one through btrfs_repair_bbio_failure().  That
rewrite is a plain REQ_OP_WRITE | REQ_SYNC, while the read that found
the bad copy and all other tree block writes carry REQ_META.

Tag it with REQ_META when the bbio belongs to the btree inode.

Signed-off-by: Mark Korenberg <socketpair@gmail.com>
---
 fs/btrfs/bio.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

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);

-- 
2.56.0



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 2/2] btrfs: raid56: pass REQ_META to per-device bios
  2026-11-06 17:33 [PATCH v2 0/2] btrfs: tag tree block repair and RAID5/6 metadata I/O with REQ_META Mark Korenberg via B4 Relay
  2026-11-06 17:33 ` [PATCH v2 1/2] btrfs: tag tree block repair writes " Mark Korenberg via B4 Relay
@ 2026-11-06 17:33 ` Mark Korenberg via B4 Relay
  2026-11-06 20:26   ` Qu Wenruo
  1 sibling, 1 reply; 5+ messages in thread
From: Mark Korenberg via B4 Relay @ 2026-11-06 17:33 UTC (permalink / raw)
  To: David Sterba, Chris Mason
  Cc: Qu Wenruo, linux-btrfs, linux-kernel, Mark Korenberg

From: Mark Korenberg <socketpair@gmail.com>

RAID5/6 writes, and reads that need a rebuild, go through an rbio,
which builds new per-device bios from a bare REQ_OP_READ or
REQ_OP_WRITE.  So all tree block writes on RAID5/6 lose REQ_META, while
on the other profiles the per-device bios are clones and keep it.  The
same goes for a tree block read rebuilt from the other stripes, for
example with a missing device.

Pass REQ_META on to all per-device bios of an rbio, data and P/Q alike,
if any bio it serves has it.  Scrub and relocation do not set REQ_META,
so their rbios stay untagged, as do rbios that only serve file data.

Signed-off-by: Mark Korenberg <socketpair@gmail.com>
---
 fs/btrfs/raid56.c | 14 +++++++++++---
 fs/btrfs/raid56.h |  7 +++++++
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
index a8a8004bb14c..63b5acbf107e 100644
--- a/fs/btrfs/raid56.c
+++ b/fs/btrfs/raid56.c
@@ -1202,10 +1202,15 @@ static int rbio_add_io_paddrs(struct btrfs_raid_bio *rbio, struct bio_list *bio_
 		}
 	}
 
-	/* put a new bio on the list */
+	/*
+	 * Put a new bio on the list.  Every per-device bio, data and P/Q
+	 * alike, serves the bios in rbio->bio_list, so it is metadata I/O if
+	 * any of them is: a tree block write, or a tree block read rebuilt
+	 * from the other stripes.
+	 */
 	bio = bio_alloc(stripe->dev->bdev,
 			max(rbio->bioc->stripe_len >> PAGE_SHIFT, 1),
-			op, GFP_NOFS);
+			op | rbio->req_meta, GFP_NOFS);
 	bio->bi_iter.bi_sector = disk_start >> SECTOR_SHIFT;
 	bio->bi_private = rbio;
 
@@ -1246,8 +1251,11 @@ static void index_rbio_pages(struct btrfs_raid_bio *rbio)
 	struct bio *bio;
 
 	spin_lock(&rbio->bio_list_lock);
-	bio_list_for_each(bio, &rbio->bio_list)
+	rbio->req_meta = 0;
+	bio_list_for_each(bio, &rbio->bio_list) {
 		index_one_bio(rbio, bio);
+		rbio->req_meta |= bio->bi_opf & REQ_META;
+	}
 
 	spin_unlock(&rbio->bio_list_lock);
 }
diff --git a/fs/btrfs/raid56.h b/fs/btrfs/raid56.h
index 8700910b8dc9..a5a0ff8e4a03 100644
--- a/fs/btrfs/raid56.h
+++ b/fs/btrfs/raid56.h
@@ -139,6 +139,13 @@ struct btrfs_raid_bio {
 	 */
 	enum btrfs_rbio_ops operation;
 
+	/*
+	 * REQ_META if any bio in bio_list has it.  Set under bio_list_lock by
+	 * index_rbio_pages(), which runs before every assembly of per-device
+	 * bios.
+	 */
+	blk_opf_t req_meta;
+
 	/* How many pages there are for the full stripe including P/Q */
 	u16 nr_pages;
 

-- 
2.56.0



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 2/2] btrfs: raid56: pass REQ_META to per-device bios
  2026-11-06 17:33 ` [PATCH v2 2/2] btrfs: raid56: pass REQ_META to per-device bios Mark Korenberg via B4 Relay
@ 2026-11-06 20:26   ` Qu Wenruo
  0 siblings, 0 replies; 5+ messages in thread
From: Qu Wenruo @ 2026-11-06 20:26 UTC (permalink / raw)
  To: socketpair, David Sterba, Chris Mason; +Cc: linux-btrfs, linux-kernel



在 2026/11/7 04:03, Mark Korenberg via B4 Relay 写道:
> From: Mark Korenberg <socketpair@gmail.com>
> 
> RAID5/6 writes, and reads that need a rebuild, go through an rbio,
> which builds new per-device bios from a bare REQ_OP_READ or
> REQ_OP_WRITE.  So all tree block writes on RAID5/6 lose REQ_META, while
> on the other profiles the per-device bios are clones and keep it.  The
> same goes for a tree block read rebuilt from the other stripes, for
> example with a missing device.
> 
> Pass REQ_META on to all per-device bios of an rbio, data and P/Q alike,
> if any bio it serves has it.  Scrub and relocation do not set REQ_META,
> so their rbios stay untagged, as do rbios that only serve file data.
> 
> Signed-off-by: Mark Korenberg <socketpair@gmail.com>

NACK.

One should not even use RAID56 for metadata chunks in the first place.
Nor we're any different from other RAID56 implementation.

> ---
>   fs/btrfs/raid56.c | 14 +++++++++++---
>   fs/btrfs/raid56.h |  7 +++++++
>   2 files changed, 18 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
> index a8a8004bb14c..63b5acbf107e 100644
> --- a/fs/btrfs/raid56.c
> +++ b/fs/btrfs/raid56.c
> @@ -1202,10 +1202,15 @@ static int rbio_add_io_paddrs(struct btrfs_raid_bio *rbio, struct bio_list *bio_
>   		}
>   	}
>   
> -	/* put a new bio on the list */
> +	/*
> +	 * Put a new bio on the list.  Every per-device bio, data and P/Q
> +	 * alike, serves the bios in rbio->bio_list, so it is metadata I/O if
> +	 * any of them is: a tree block write, or a tree block read rebuilt
> +	 * from the other stripes.
> +	 */
>   	bio = bio_alloc(stripe->dev->bdev,
>   			max(rbio->bioc->stripe_len >> PAGE_SHIFT, 1),
> -			op, GFP_NOFS);
> +			op | rbio->req_meta, GFP_NOFS);
>   	bio->bi_iter.bi_sector = disk_start >> SECTOR_SHIFT;
>   	bio->bi_private = rbio;
>   
> @@ -1246,8 +1251,11 @@ static void index_rbio_pages(struct btrfs_raid_bio *rbio)
>   	struct bio *bio;
>   
>   	spin_lock(&rbio->bio_list_lock);
> -	bio_list_for_each(bio, &rbio->bio_list)
> +	rbio->req_meta = 0;
> +	bio_list_for_each(bio, &rbio->bio_list) {
>   		index_one_bio(rbio, bio);
> +		rbio->req_meta |= bio->bi_opf & REQ_META;
> +	}
>   
>   	spin_unlock(&rbio->bio_list_lock);
>   }
> diff --git a/fs/btrfs/raid56.h b/fs/btrfs/raid56.h
> index 8700910b8dc9..a5a0ff8e4a03 100644
> --- a/fs/btrfs/raid56.h
> +++ b/fs/btrfs/raid56.h
> @@ -139,6 +139,13 @@ struct btrfs_raid_bio {
>   	 */
>   	enum btrfs_rbio_ops operation;
>   
> +	/*
> +	 * REQ_META if any bio in bio_list has it.  Set under bio_list_lock by
> +	 * index_rbio_pages(), which runs before every assembly of per-device
> +	 * bios.
> +	 */
> +	blk_opf_t req_meta;
> +
>   	/* How many pages there are for the full stripe including P/Q */
>   	u16 nr_pages;
>   
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 1/2] btrfs: tag tree block repair writes with REQ_META
  2026-11-06 17:33 ` [PATCH v2 1/2] btrfs: tag tree block repair writes " Mark Korenberg via B4 Relay
@ 2026-11-06 20:31   ` Qu Wenruo
  0 siblings, 0 replies; 5+ messages in thread
From: Qu Wenruo @ 2026-11-06 20:31 UTC (permalink / raw)
  To: socketpair, David Sterba, Chris Mason; +Cc: linux-btrfs, linux-kernel



在 2026/11/7 04:03, Mark Korenberg via B4 Relay 写道:
> From: Mark Korenberg <socketpair@gmail.com>
> 
> When a tree block read finds a bad copy, btrfs_repair_eb_io_failure()
> rewrites it from a good one through btrfs_repair_bbio_failure().  That
> rewrite is a plain REQ_OP_WRITE | REQ_SYNC, while the read that found
> the bad copy and all other tree block writes carry REQ_META.
> 
> Tag it with REQ_META when the bbio belongs to the btree inode.
> 
> Signed-off-by: Mark Korenberg <socketpair@gmail.com>

This part looks fine to me.

Reviewed-by: Qu Wenruo <wqu@suse.com>

Thanks,
Qu

> ---
>   fs/btrfs/bio.c | 3 ++-
>   1 file changed, 2 insertions(+), 1 deletion(-)
> 
> 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);
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-11-06 20:31 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-06 17:33 [PATCH v2 0/2] btrfs: tag tree block repair and RAID5/6 metadata I/O with REQ_META Mark Korenberg via B4 Relay
2026-11-06 17:33 ` [PATCH v2 1/2] btrfs: tag tree block repair writes " Mark Korenberg via B4 Relay
2026-11-06 20:31   ` Qu Wenruo
2026-11-06 17:33 ` [PATCH v2 2/2] btrfs: raid56: pass REQ_META to per-device bios Mark Korenberg via B4 Relay
2026-11-06 20:26   ` Qu Wenruo

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®