]> git.ipfire.org Git - thirdparty/kernel/linux.git/blobdiff - block/blk-merge.c
Merge tag 'for-6.10/block-20240511' of git://git.kernel.dk/linux
[thirdparty/kernel/linux.git] / block / blk-merge.c
index 4e3483a16b7575ec1d6f1cf9b92ebc7dfca1e9e5..8534c35e04976a8a59cefd9d321d7522768f4ae6 100644 (file)
@@ -377,6 +377,7 @@ struct bio *__bio_split_to_limits(struct bio *bio,
                blkcg_bio_issue_init(split);
                bio_chain(split, bio);
                trace_block_split(split, bio->bi_iter.bi_sector);
+               WARN_ON_ONCE(bio_zone_write_plugging(bio));
                submit_bio_noacct(bio);
                return split;
        }
@@ -779,6 +780,8 @@ static void blk_account_io_merge_request(struct request *req)
        if (blk_do_io_stat(req)) {
                part_stat_lock();
                part_stat_inc(req->part, merges[op_stat_group(req_op(req))]);
+               part_stat_local_dec(req->part,
+                                   in_flight[op_is_write(req_op(req))]);
                part_stat_unlock();
        }
 }
@@ -972,13 +975,7 @@ static void blk_account_io_merge_bio(struct request *req)
        part_stat_unlock();
 }
 
-enum bio_merge_status {
-       BIO_MERGE_OK,
-       BIO_MERGE_NONE,
-       BIO_MERGE_FAILED,
-};
-
-static enum bio_merge_status bio_attempt_back_merge(struct request *req,
+enum bio_merge_status bio_attempt_back_merge(struct request *req,
                struct bio *bio, unsigned int nr_segs)
 {
        const blk_opf_t ff = bio_failfast(bio);
@@ -994,6 +991,9 @@ static enum bio_merge_status bio_attempt_back_merge(struct request *req,
 
        blk_update_mixed_merge(req, bio, false);
 
+       if (req->rq_flags & RQF_ZONE_WRITE_PLUGGING)
+               blk_zone_write_plug_bio_merged(bio);
+
        req->biotail->bi_next = bio;
        req->biotail = bio;
        req->__data_len += bio->bi_iter.bi_size;
@@ -1009,6 +1009,14 @@ static enum bio_merge_status bio_attempt_front_merge(struct request *req,
 {
        const blk_opf_t ff = bio_failfast(bio);
 
+       /*
+        * A front merge for writes to sequential zones of a zoned block device
+        * can happen only if the user submitted writes out of order. Do not
+        * merge such write to let it fail.
+        */
+       if (req->rq_flags & RQF_ZONE_WRITE_PLUGGING)
+               return BIO_MERGE_FAILED;
+
        if (!ll_front_merge_fn(req, bio, nr_segs))
                return BIO_MERGE_FAILED;
 
@@ -1107,10 +1115,9 @@ static enum bio_merge_status blk_attempt_bio_merge(struct request_queue *q,
 bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio,
                unsigned int nr_segs)
 {
-       struct blk_plug *plug;
+       struct blk_plug *plug = current->plug;
        struct request *rq;
 
-       plug = blk_mq_plug(bio);
        if (!plug || rq_list_empty(plug->mq_list))
                return false;