Discard requests operate under different constraints than other operations and have different rules for merging. This patch will treat such requests as a special case, using the same criteria and segment accounting used for merging a discard bio into a reqseut.
Signed-off-by: Keith Busch <keith.bu...@intel.com> --- block/blk-merge.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/block/blk-merge.c b/block/blk-merge.c index 8452fc7164cc..37186fb02cf1 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -550,6 +550,25 @@ static bool req_no_special_merge(struct request *req) return !q->mq_ops && req->special; } +static int req_attempt_discard_merge(struct request_queue *q, struct request *req, + struct request *next) +{ + unsigned short segments = blk_rq_nr_discard_segments(req); + + if (segments >= queue_max_discard_segments(q)) + goto no_merge; + if (blk_rq_sectors(req) + bio_sectors(next->bio) > + blk_rq_get_max_sectors(req, blk_rq_pos(req))) + goto no_merge; + + req->nr_phys_segments = segments + blk_rq_nr_discard_segments(next); + return 1; + +no_merge: + req_set_nomerge(q, req); + return 0; +} + static int ll_merge_requests_fn(struct request_queue *q, struct request *req, struct request *next) { @@ -564,6 +583,13 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req, if (req_no_special_merge(req) || req_no_special_merge(next)) return 0; + /* + * Merging discard requests use different constraints than other + * operations. + */ + if (req_op(req) == REQ_OP_DISCARD) + return req_attempt_discard_merge(q, req, next); + if (req_gap_back_merge(req, next->bio)) return 0; -- 2.14.3