]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
block: properly handle REQ_OP_ZONE_APPEND in __bio_split_to_limits
authorChristoph Hellwig <hch@lst.de>
Mon, 26 Aug 2024 17:37:56 +0000 (19:37 +0200)
committerJens Axboe <axboe@kernel.dk>
Thu, 29 Aug 2024 10:32:32 +0000 (04:32 -0600)
Currently REQ_OP_ZONE_APPEND is handled by the bio_split_rw case in
__bio_split_to_limits.  This is harmful because REQ_OP_ZONE_APPEND
bios do not adhere to the soft max_limits value but instead use their
own capped version of max_hw_sectors, leading to incorrect splits that
later blow up in bio_split.

We still need the bio_split_rw logic to count nr_segs for blk-mq code,
so add a new wrapper that passes in the right limit, and turns any bio
that would need a split into an error as an additional debugging aid.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Tested-by: Hans Holmberg <hans.holmberg@wdc.com>
Reviewed-by: Hans Holmberg <hans.holmberg@wdc.com>
Link: https://lore.kernel.org/r/20240826173820.1690925-4-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-merge.c
block/blk.h

index c7222c4685e060d4df09c63c9eb638ea5b431f5b..56769c4bcd799b9ea2cf4857df5063561f38116f 100644 (file)
@@ -378,6 +378,26 @@ struct bio *bio_split_rw(struct bio *bio, const struct queue_limits *lim,
                        get_max_io_size(bio, lim) << SECTOR_SHIFT));
 }
 
+/*
+ * REQ_OP_ZONE_APPEND bios must never be split by the block layer.
+ *
+ * But we want the nr_segs calculation provided by bio_split_rw_at, and having
+ * a good sanity check that the submitter built the bio correctly is nice to
+ * have as well.
+ */
+struct bio *bio_split_zone_append(struct bio *bio,
+               const struct queue_limits *lim, unsigned *nr_segs)
+{
+       unsigned int max_sectors = queue_limits_max_zone_append_sectors(lim);
+       int split_sectors;
+
+       split_sectors = bio_split_rw_at(bio, lim, nr_segs,
+                       max_sectors << SECTOR_SHIFT);
+       if (WARN_ON_ONCE(split_sectors > 0))
+               split_sectors = -EINVAL;
+       return bio_submit_split(bio, split_sectors);
+}
+
 /**
  * bio_split_to_limits - split a bio to fit the queue limits
  * @bio:     bio to be split
index 0d8cd64c126064d6b5e2ffe9bd85888a30ac6692..61c2afa67daabb7d0e99fdb9f90fa9be246c4397 100644 (file)
@@ -337,6 +337,8 @@ struct bio *bio_split_write_zeroes(struct bio *bio,
                const struct queue_limits *lim, unsigned *nsegs);
 struct bio *bio_split_rw(struct bio *bio, const struct queue_limits *lim,
                unsigned *nr_segs);
+struct bio *bio_split_zone_append(struct bio *bio,
+               const struct queue_limits *lim, unsigned *nr_segs);
 
 /*
  * All drivers must accept single-segments bios that are smaller than PAGE_SIZE.
@@ -375,6 +377,8 @@ static inline struct bio *__bio_split_to_limits(struct bio *bio,
                        return bio_split_rw(bio, lim, nr_segs);
                *nr_segs = 1;
                return bio;
+       case REQ_OP_ZONE_APPEND:
+               return bio_split_zone_append(bio, lim, nr_segs);
        case REQ_OP_DISCARD:
        case REQ_OP_SECURE_ERASE:
                return bio_split_discard(bio, lim, nr_segs);