When queue_max_discard_segments(q) is 1, blk_discard_mergable() will return false for discard request, then normal request merge is applied. However, only queue_max_segments() is checked, so max discard segment limit isn't respected. Check max discard segment limit in the request merge code for fixing the issue. Discard request failure of virtio_blk is fixed. Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxx> Fixes: 69840466086d ("block: fix the DISCARD request merge") Cc: Christoph Hellwig <hch@xxxxxx> Cc: Stefano Garzarella <sgarzare@xxxxxxxxxx> --- block/blk-merge.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/block/blk-merge.c b/block/blk-merge.c index 5196dc145270..d18fb88ca8bd 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -533,10 +533,16 @@ int __blk_rq_map_sg(struct request_queue *q, struct request *rq, } EXPORT_SYMBOL(__blk_rq_map_sg); +static inline unsigned int blk_rq_get_max_segments(struct request *rq) +{ + return req_op(rq) == REQ_OP_DISCARD ? + queue_max_discard_segments(rq->q) : queue_max_segments(rq->q); +} + static inline int ll_new_hw_segment(struct request *req, struct bio *bio, unsigned int nr_phys_segs) { - if (req->nr_phys_segments + nr_phys_segs > queue_max_segments(req->q)) + if (req->nr_phys_segments + nr_phys_segs > blk_rq_get_max_segments(req)) goto no_merge; if (blk_integrity_merge_bio(req->q, req, bio) == false) @@ -624,7 +630,7 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req, return 0; total_phys_segments = req->nr_phys_segments + next->nr_phys_segments; - if (total_phys_segments > queue_max_segments(q)) + if (total_phys_segments > blk_rq_get_max_segments(req)) return 0; if (blk_integrity_merge_rq(q, req, next) == false) -- 2.25.2