blk-mq: allow blk_mq_init_commands() to return failure
authorJens Axboe <axboe@fb.com>
Fri, 14 Mar 2014 16:43:15 +0000 (10:43 -0600)
committerJens Axboe <axboe@fb.com>
Fri, 14 Mar 2014 16:43:15 +0000 (10:43 -0600)
If drivers do dynamic allocation in the hardware command init
path, then we need to be able to handle and return failures.

And if they do allocations or mappings in the init command path,
then we need a cleanup function to free up that space at exit
time. So add blk_mq_free_commands() as the cleanup function.

This is required for the mtip32xx driver conversion to blk-mq.

Signed-off-by: Jens Axboe <axboe@fb.com>
block/blk-mq.c
drivers/block/virtio_blk.c
include/linux/blk-mq.h

index 01d8735db8d3e425c84bfa3694935bcd1301e277..92284af4e0df35583b2a691f377752d332b3183e 100644 (file)
@@ -1058,8 +1058,46 @@ static void blk_mq_hctx_notify(void *data, unsigned long action,
        blk_mq_put_ctx(ctx);
 }
 
-static void blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
-                                   void (*init)(void *, struct blk_mq_hw_ctx *,
+static int blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
+                                  int (*init)(void *, struct blk_mq_hw_ctx *,
+                                       struct request *, unsigned int),
+                                  void *data)
+{
+       unsigned int i;
+       int ret = 0;
+
+       for (i = 0; i < hctx->queue_depth; i++) {
+               struct request *rq = hctx->rqs[i];
+
+               ret = init(data, hctx, rq, i);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+int blk_mq_init_commands(struct request_queue *q,
+                        int (*init)(void *, struct blk_mq_hw_ctx *,
+                                       struct request *, unsigned int),
+                        void *data)
+{
+       struct blk_mq_hw_ctx *hctx;
+       unsigned int i;
+       int ret = 0;
+
+       queue_for_each_hw_ctx(q, hctx, i) {
+               ret = blk_mq_init_hw_commands(hctx, init, data);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(blk_mq_init_commands);
+
+static void blk_mq_free_hw_commands(struct blk_mq_hw_ctx *hctx,
+                                   void (*free)(void *, struct blk_mq_hw_ctx *,
                                        struct request *, unsigned int),
                                    void *data)
 {
@@ -1068,12 +1106,12 @@ static void blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
        for (i = 0; i < hctx->queue_depth; i++) {
                struct request *rq = hctx->rqs[i];
 
-               init(data, hctx, rq, i);
+               free(data, hctx, rq, i);
        }
 }
 
-void blk_mq_init_commands(struct request_queue *q,
-                         void (*init)(void *, struct blk_mq_hw_ctx *,
+void blk_mq_free_commands(struct request_queue *q,
+                         void (*free)(void *, struct blk_mq_hw_ctx *,
                                        struct request *, unsigned int),
                          void *data)
 {
@@ -1081,9 +1119,9 @@ void blk_mq_init_commands(struct request_queue *q,
        unsigned int i;
 
        queue_for_each_hw_ctx(q, hctx, i)
-               blk_mq_init_hw_commands(hctx, init, data);
+               blk_mq_free_hw_commands(hctx, free, data);
 }
-EXPORT_SYMBOL(blk_mq_init_commands);
+EXPORT_SYMBOL(blk_mq_free_commands);
 
 static void blk_mq_free_rq_map(struct blk_mq_hw_ctx *hctx)
 {
index b1cb3f4c4db45543c653fd86ce28e75b67522430..0eace43cea113159d9e94fc75e1710049d0e0c00 100644 (file)
@@ -490,13 +490,14 @@ static struct blk_mq_reg virtio_mq_reg = {
        .flags          = BLK_MQ_F_SHOULD_MERGE,
 };
 
-static void virtblk_init_vbr(void *data, struct blk_mq_hw_ctx *hctx,
+static int virtblk_init_vbr(void *data, struct blk_mq_hw_ctx *hctx,
                             struct request *rq, unsigned int nr)
 {
        struct virtio_blk *vblk = data;
        struct virtblk_req *vbr = rq->special;
 
        sg_init_table(vbr->sg, vblk->sg_elems);
+       return 0;
 }
 
 static int virtblk_probe(struct virtio_device *vdev)
index 18ba8a627f46e0fd77a97aa0257940d845f7f8a4..33ff10ebcabb804d57d34f24ed88a33b0c331b67 100644 (file)
@@ -117,7 +117,8 @@ enum {
 struct request_queue *blk_mq_init_queue(struct blk_mq_reg *, void *);
 int blk_mq_register_disk(struct gendisk *);
 void blk_mq_unregister_disk(struct gendisk *);
-void blk_mq_init_commands(struct request_queue *, void (*init)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data);
+int blk_mq_init_commands(struct request_queue *, int (*init)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data);
+void blk_mq_free_commands(struct request_queue *, void (*free)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data);
 
 void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule);