Allow users to hook into prep/unprep functions just before an IO is
dispatched to the device driver. This is necessary for request-based
logic to take place at upper layers.

Signed-off-by: Matias Bjørling <m...@bjorling.me>
---
 block/blk-mq.c         | 28 ++++++++++++++++++++++++++--
 include/linux/blk-mq.h |  1 +
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/block/blk-mq.c b/block/blk-mq.c
index 33c4285..f3dd028 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -338,6 +338,11 @@ EXPORT_SYMBOL(__blk_mq_end_request);
 
 void blk_mq_end_request(struct request *rq, int error)
 {
+       struct request_queue *q = rq->q;
+
+       if (q->unprep_rq_fn)
+               q->unprep_rq_fn(q, rq);
+
        if (blk_update_request(rq, error, blk_rq_bytes(rq)))
                BUG();
        __blk_mq_end_request(rq, error);
@@ -753,6 +758,17 @@ static void flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, 
struct list_head *list)
        }
 }
 
+static int blk_mq_prep_rq(struct request_queue *q, struct request *rq)
+{
+       if (!q->prep_rq_fn)
+               return 0;
+
+       if (rq->cmd_flags & REQ_DONTPREP)
+               return 0;
+
+       return q->prep_rq_fn(q, rq);
+}
+
 /*
  * Run this hardware queue, pulling any software queues mapped to it in.
  * Note that this function currently has various problems around ordering
@@ -812,11 +828,15 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx 
*hctx)
                bd.list = dptr;
                bd.last = list_empty(&rq_list);
 
-               ret = q->mq_ops->queue_rq(hctx, &bd);
+               ret = blk_mq_prep_rq(q, rq);
+               if (likely(!ret))
+                       ret = q->mq_ops->queue_rq(hctx, &bd);
                switch (ret) {
                case BLK_MQ_RQ_QUEUE_OK:
                        queued++;
                        continue;
+               case BLK_MQ_RQ_QUEUE_DONE:
+                       continue;
                case BLK_MQ_RQ_QUEUE_BUSY:
                        list_add(&rq->queuelist, &rq_list);
                        __blk_mq_requeue_request(rq);
@@ -1270,10 +1290,14 @@ static void blk_mq_make_request(struct request_queue 
*q, struct bio *bio)
                 * error (busy), just add it to our list as we previously
                 * would have done
                 */
-               ret = q->mq_ops->queue_rq(data.hctx, &bd);
+               ret = blk_mq_prep_rq(q, rq);
+               if (likely(!ret))
+                       ret = q->mq_ops->queue_rq(data.hctx, &bd);
                if (ret == BLK_MQ_RQ_QUEUE_OK)
                        goto done;
                else {
+                       if (ret == BLK_MQ_RQ_QUEUE_DONE)
+                               goto done;
                        __blk_mq_requeue_request(rq);
 
                        if (ret == BLK_MQ_RQ_QUEUE_ERROR) {
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index 7aec861..d7b39af 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -140,6 +140,7 @@ enum {
        BLK_MQ_RQ_QUEUE_OK      = 0,    /* queued fine */
        BLK_MQ_RQ_QUEUE_BUSY    = 1,    /* requeue IO for later */
        BLK_MQ_RQ_QUEUE_ERROR   = 2,    /* end IO with error */
+       BLK_MQ_RQ_QUEUE_DONE    = 3,    /* IO is already handled */
 
        BLK_MQ_F_SHOULD_MERGE   = 1 << 0,
        BLK_MQ_F_TAG_SHARED     = 1 << 1,
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to