When requeuing a request to a zoned block device, preserve the LBA order per zone. Cc: Christoph Hellwig <hch@xxxxxx> Cc: Ming Lei <ming.lei@xxxxxxxxxx> Cc: Damien Le Moal <damien.lemoal@xxxxxxxxxxxxxxxxxx> Cc: Johannes Thumshirn <johannes.thumshirn@xxxxxxx> Signed-off-by: Bart Van Assche <bvanassche@xxxxxxx> --- block/blk-mq.c | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index cc32ad0cd548..2ec7d6140114 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1495,6 +1495,44 @@ static void blk_mq_requeue_work(struct work_struct *work) blk_mq_run_hw_queues(q, false); } +static void blk_mq_insert_rq(struct request *rq, struct list_head *list, + bool at_head) +{ + bool zone_in_list = false; + struct request *rq2; + + /* + * For request queues associated with a zoned block device, check + * whether another request for the same zone has already been queued. + */ + if (blk_queue_is_zoned(rq->q)) { + const unsigned int zno = blk_rq_zone_no(rq); + + list_for_each_entry(rq2, list, queuelist) { + if (blk_rq_zone_no(rq2) == zno) { + zone_in_list = true; + if (blk_rq_pos(rq) < blk_rq_pos(rq2)) + break; + } + } + } + if (!zone_in_list) { + if (at_head) { + rq->rq_flags |= RQF_SOFTBARRIER; + list_add(&rq->queuelist, list); + } else { + list_add_tail(&rq->queuelist, list); + } + } else { + /* + * Insert the request in the list before another request for + * the same zone and with a higher LBA. If there is no such + * request, insert the request at the end of the list. + */ + list_add_tail(&rq->queuelist, &rq2->queuelist); + } +} + void blk_mq_add_to_requeue_list(struct request *rq, bool at_head, bool kick_requeue_list) { @@ -1508,12 +1546,7 @@ void blk_mq_add_to_requeue_list(struct request *rq, bool at_head, BUG_ON(rq->rq_flags & RQF_SOFTBARRIER); spin_lock_irqsave(&q->requeue_lock, flags); - if (at_head) { - rq->rq_flags |= RQF_SOFTBARRIER; - list_add(&rq->queuelist, &q->requeue_list); - } else { - list_add_tail(&rq->queuelist, &q->requeue_list); - } + blk_mq_insert_rq(rq, &q->requeue_list, at_head); spin_unlock_irqrestore(&q->requeue_lock, flags); if (kick_requeue_list)