blk-integrity: properly account for segments
authorKeith Busch <kbusch@kernel.org>
Fri, 13 Sep 2024 18:28:48 +0000 (11:28 -0700)
committerJens Axboe <axboe@kernel.dk>
Fri, 13 Sep 2024 18:31:45 +0000 (12:31 -0600)
Both types of merging when integrity data is used are miscounting the
segments:

Merging two requests wasn't accounting for the new segment count, so add
the "next" segment count to the first on a successful merge to ensure
this value is accurate.

Merging a bio into an existing request was double counting the bio's
segments, even if the merge failed later on. Move the segment accounting
to the end when the merge is successful.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Link: https://lore.kernel.org/r/20240913182854.2445457-4-kbusch@meta.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-integrity.c
block/blk-merge.c

index 010decc892eaa03e07d232da7c3b8c4453fe7e50..afd101555d3cbd3506f6b295340cd3eefd001e95 100644 (file)
@@ -153,8 +153,6 @@ bool blk_integrity_merge_bio(struct request_queue *q, struct request *req,
            q->limits.max_integrity_segments)
                return false;
 
-       req->nr_integrity_segments += nr_integrity_segs;
-
        return true;
 }
 
index 56769c4bcd799b9ea2cf4857df5063561f38116f..ad763ec313b6ade3622aeb6c43e5868511239132 100644 (file)
@@ -639,6 +639,9 @@ static inline int ll_new_hw_segment(struct request *req, struct bio *bio,
         * counters.
         */
        req->nr_phys_segments += nr_phys_segs;
+       if (bio_integrity(bio))
+               req->nr_integrity_segments += blk_rq_count_integrity_sg(req->q,
+                                                                       bio);
        return 1;
 
 no_merge:
@@ -731,6 +734,7 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
 
        /* Merge is OK... */
        req->nr_phys_segments = total_phys_segments;
+       req->nr_integrity_segments += next->nr_integrity_segments;
        return 1;
 }