aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <axboe@fb.com>2014-03-14 12:43:15 -0400
committerJens Axboe <axboe@fb.com>2014-03-14 12:43:15 -0400
commit95363efde193079541cb379eb47140e9c4d355d5 (patch)
treeda7417035ca5f25d6818430feaa54cb09a2ba86d
parent89f8b33ca1ea881d1d84542282cb85d07d02e78d (diff)
blk-mq: allow blk_mq_init_commands() to return failure
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>
-rw-r--r--block/blk-mq.c52
-rw-r--r--drivers/block/virtio_blk.c3
-rw-r--r--include/linux/blk-mq.h3
3 files changed, 49 insertions, 9 deletions
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 01d8735db8d3..92284af4e0df 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1058,8 +1058,46 @@ static void blk_mq_hctx_notify(void *data, unsigned long action,
1058 blk_mq_put_ctx(ctx); 1058 blk_mq_put_ctx(ctx);
1059} 1059}
1060 1060
1061static void blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx, 1061static int blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
1062 void (*init)(void *, struct blk_mq_hw_ctx *, 1062 int (*init)(void *, struct blk_mq_hw_ctx *,
1063 struct request *, unsigned int),
1064 void *data)
1065{
1066 unsigned int i;
1067 int ret = 0;
1068
1069 for (i = 0; i < hctx->queue_depth; i++) {
1070 struct request *rq = hctx->rqs[i];
1071
1072 ret = init(data, hctx, rq, i);
1073 if (ret)
1074 break;
1075 }
1076
1077 return ret;
1078}
1079
1080int blk_mq_init_commands(struct request_queue *q,
1081 int (*init)(void *, struct blk_mq_hw_ctx *,
1082 struct request *, unsigned int),
1083 void *data)
1084{
1085 struct blk_mq_hw_ctx *hctx;
1086 unsigned int i;
1087 int ret = 0;
1088
1089 queue_for_each_hw_ctx(q, hctx, i) {
1090 ret = blk_mq_init_hw_commands(hctx, init, data);
1091 if (ret)
1092 break;
1093 }
1094
1095 return ret;
1096}
1097EXPORT_SYMBOL(blk_mq_init_commands);
1098
1099static void blk_mq_free_hw_commands(struct blk_mq_hw_ctx *hctx,
1100 void (*free)(void *, struct blk_mq_hw_ctx *,
1063 struct request *, unsigned int), 1101 struct request *, unsigned int),
1064 void *data) 1102 void *data)
1065{ 1103{
@@ -1068,12 +1106,12 @@ static void blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
1068 for (i = 0; i < hctx->queue_depth; i++) { 1106 for (i = 0; i < hctx->queue_depth; i++) {
1069 struct request *rq = hctx->rqs[i]; 1107 struct request *rq = hctx->rqs[i];
1070 1108
1071 init(data, hctx, rq, i); 1109 free(data, hctx, rq, i);
1072 } 1110 }
1073} 1111}
1074 1112
1075void blk_mq_init_commands(struct request_queue *q, 1113void blk_mq_free_commands(struct request_queue *q,
1076 void (*init)(void *, struct blk_mq_hw_ctx *, 1114 void (*free)(void *, struct blk_mq_hw_ctx *,
1077 struct request *, unsigned int), 1115 struct request *, unsigned int),
1078 void *data) 1116 void *data)
1079{ 1117{
@@ -1081,9 +1119,9 @@ void blk_mq_init_commands(struct request_queue *q,
1081 unsigned int i; 1119 unsigned int i;
1082 1120
1083 queue_for_each_hw_ctx(q, hctx, i) 1121 queue_for_each_hw_ctx(q, hctx, i)
1084 blk_mq_init_hw_commands(hctx, init, data); 1122 blk_mq_free_hw_commands(hctx, free, data);
1085} 1123}
1086EXPORT_SYMBOL(blk_mq_init_commands); 1124EXPORT_SYMBOL(blk_mq_free_commands);
1087 1125
1088static void blk_mq_free_rq_map(struct blk_mq_hw_ctx *hctx) 1126static void blk_mq_free_rq_map(struct blk_mq_hw_ctx *hctx)
1089{ 1127{
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index b1cb3f4c4db4..0eace43cea11 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -490,13 +490,14 @@ static struct blk_mq_reg virtio_mq_reg = {
490 .flags = BLK_MQ_F_SHOULD_MERGE, 490 .flags = BLK_MQ_F_SHOULD_MERGE,
491}; 491};
492 492
493static void virtblk_init_vbr(void *data, struct blk_mq_hw_ctx *hctx, 493static int virtblk_init_vbr(void *data, struct blk_mq_hw_ctx *hctx,
494 struct request *rq, unsigned int nr) 494 struct request *rq, unsigned int nr)
495{ 495{
496 struct virtio_blk *vblk = data; 496 struct virtio_blk *vblk = data;
497 struct virtblk_req *vbr = rq->special; 497 struct virtblk_req *vbr = rq->special;
498 498
499 sg_init_table(vbr->sg, vblk->sg_elems); 499 sg_init_table(vbr->sg, vblk->sg_elems);
500 return 0;
500} 501}
501 502
502static int virtblk_probe(struct virtio_device *vdev) 503static int virtblk_probe(struct virtio_device *vdev)
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index 18ba8a627f46..33ff10ebcabb 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -117,7 +117,8 @@ enum {
117struct request_queue *blk_mq_init_queue(struct blk_mq_reg *, void *); 117struct request_queue *blk_mq_init_queue(struct blk_mq_reg *, void *);
118int blk_mq_register_disk(struct gendisk *); 118int blk_mq_register_disk(struct gendisk *);
119void blk_mq_unregister_disk(struct gendisk *); 119void blk_mq_unregister_disk(struct gendisk *);
120void blk_mq_init_commands(struct request_queue *, void (*init)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data); 120int blk_mq_init_commands(struct request_queue *, int (*init)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data);
121void blk_mq_free_commands(struct request_queue *, void (*free)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data);
121 122
122void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule); 123void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule);
123 124