Skip to content

Commit 49d2439

Browse files
ps-ushankaraxboe
authored andcommitted
blk-mq: enforce op-specific segment limits in blk_insert_cloned_request
The block layer might merge together discard requests up until the max_discard_segments limit is hit, but blk_insert_cloned_request checks the segment count against max_segments regardless of the req op. This can result in errors like the following when discards are issued through a DM device and max_discard_segments exceeds max_segments for the queue of the chosen underlying device. blk_insert_cloned_request: over max segments limit. (256 > 129) Fix this by looking at the req_op and enforcing the appropriate segment limit - max_discard_segments for REQ_OP_DISCARDs and max_segments for everything else. Signed-off-by: Uday Shankar <[email protected]> Reviewed-by: Keith Busch <[email protected]> Reviewed-by: Ming Lei <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 326ac2c commit 49d2439

File tree

3 files changed

+11
-10
lines changed

3 files changed

+11
-10
lines changed

block/blk-merge.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -586,13 +586,6 @@ int __blk_rq_map_sg(struct request_queue *q, struct request *rq,
586586
}
587587
EXPORT_SYMBOL(__blk_rq_map_sg);
588588

589-
static inline unsigned int blk_rq_get_max_segments(struct request *rq)
590-
{
591-
if (req_op(rq) == REQ_OP_DISCARD)
592-
return queue_max_discard_segments(rq->q);
593-
return queue_max_segments(rq->q);
594-
}
595-
596589
static inline unsigned int blk_rq_get_max_sectors(struct request *rq,
597590
sector_t offset)
598591
{

block/blk-mq.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3000,6 +3000,7 @@ blk_status_t blk_insert_cloned_request(struct request *rq)
30003000
{
30013001
struct request_queue *q = rq->q;
30023002
unsigned int max_sectors = blk_queue_get_max_sectors(q, req_op(rq));
3003+
unsigned int max_segments = blk_rq_get_max_segments(rq);
30033004
blk_status_t ret;
30043005

30053006
if (blk_rq_sectors(rq) > max_sectors) {
@@ -3026,9 +3027,9 @@ blk_status_t blk_insert_cloned_request(struct request *rq)
30263027
* original queue.
30273028
*/
30283029
rq->nr_phys_segments = blk_recalc_rq_segments(rq);
3029-
if (rq->nr_phys_segments > queue_max_segments(q)) {
3030-
printk(KERN_ERR "%s: over max segments limit. (%hu > %hu)\n",
3031-
__func__, rq->nr_phys_segments, queue_max_segments(q));
3030+
if (rq->nr_phys_segments > max_segments) {
3031+
printk(KERN_ERR "%s: over max segments limit. (%u > %u)\n",
3032+
__func__, rq->nr_phys_segments, max_segments);
30323033
return BLK_STS_IOERR;
30333034
}
30343035

block/blk.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,13 @@ static inline bool blk_discard_mergable(struct request *req)
156156
return false;
157157
}
158158

159+
static inline unsigned int blk_rq_get_max_segments(struct request *rq)
160+
{
161+
if (req_op(rq) == REQ_OP_DISCARD)
162+
return queue_max_discard_segments(rq->q);
163+
return queue_max_segments(rq->q);
164+
}
165+
159166
static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q,
160167
enum req_op op)
161168
{

0 commit comments

Comments
 (0)