[PATCH 1/2] block: allow write streams on partitions
From: Keoseong Park
Date: Fri Sep 11 2026 - 02:47:55 EST
bdev_max_write_streams() returns 0 for partitions, so nothing on top of
a partition can use write streams. Passing the disk's streams through
would not be correct either: two partitions sharing a stream would put
unrelated data into the same reclaim unit.
Give each partition its own subset of the disk's write streams, kept in
a per-partition map in struct block_device. bdev_max_write_streams()
reports the partition's count, so existing users work with
partition-relative stream numbers (1..count), and blk_partition_remap()
translates them to disk streams like it remaps sectors. Only
REQ_OP_WRITE bios are translated, as that is the only operation that
consumes a write stream. A write with a stream beyond the partition's
count fails the bio; blkdev_direct_IO() rejects those before
submission, so this only catches in-kernel submitters.
Nothing assigns streams to partitions yet, so there is no functional
change.
The idea of translating the stream in blk_partition_remap() is from an
earlier patch by Christoph Hellwig, which assigned a contiguous range of
streams to each partition instead of a map.
Link: https://lore.kernel.org/all/20241119121632.1225556-16-hch@xxxxxx/
Signed-off-by: Keoseong Park <keosung.park@xxxxxxxxxxx>
---
block/bdev.c | 1 +
block/blk-core.c | 10 +++++++++-
include/linux/blk_types.h | 3 +++
include/linux/blkdev.h | 2 +-
4 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/block/bdev.c b/block/bdev.c
index cd8323083740..7306a4ef0a86 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -438,6 +438,7 @@ static void bdev_free_inode(struct inode *inode)
free_percpu(bdev->bd_stats);
kfree(bdev->bd_meta_info);
+ kfree(bdev->bd_write_stream_map);
security_bdev_free(bdev);
if (!bdev_is_partition(bdev)) {
diff --git a/block/blk-core.c b/block/blk-core.c
index 196bccf27f58..3b6f09b3943f 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -616,7 +616,8 @@ static inline int bio_check_eod(struct bio *bio)
}
/*
- * Remap block n of partition p to block n+start(p) of the disk.
+ * Remap block n of partition p to block n+start(p) of the disk, and the
+ * write streams of partition p to the disk write streams reserved for them.
*/
static int blk_partition_remap(struct bio *bio)
{
@@ -630,6 +631,13 @@ static int blk_partition_remap(struct bio *bio)
bio->bi_iter.bi_sector -
p->bd_start_sect);
}
+ if (bio->bi_write_stream && bio_op(bio) == REQ_OP_WRITE) {
+ if (unlikely(bio->bi_write_stream > p->bd_nr_write_streams))
+ return -EINVAL;
+
+ bio->bi_write_stream =
+ p->bd_write_stream_map[bio->bi_write_stream - 1];
+ }
bio_set_flag(bio, BIO_REMAPPED);
return 0;
}
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 98e21b4cbf32..0bbfa2708099 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -71,6 +71,9 @@ struct block_device {
struct partition_meta_info *bd_meta_info;
int bd_writers;
+ /* partition write stream s is disk stream bd_write_stream_map[s - 1] */
+ u8 bd_nr_write_streams;
+ u8 *bd_write_stream_map;
#ifdef CONFIG_SECURITY
void *bd_security;
#endif
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 4f7905c3412b..686ed60a0bb7 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1303,7 +1303,7 @@ static inline unsigned int bdev_max_segments(struct block_device *bdev)
static inline unsigned short bdev_max_write_streams(struct block_device *bdev)
{
if (bdev_is_partition(bdev))
- return 0;
+ return bdev->bd_nr_write_streams;
return bdev_limits(bdev)->max_write_streams;
}
--
2.43.0