[PATCH 4/4] blk-mq: support shared tag maps

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---
 block/blk-mq-tag.c     |    2 ++
 block/blk-mq.c         |   83 +++++++++++++++++++++++++++++++++++++++++++-----
 block/blk-mq.h         |    2 ++
 include/linux/blk-mq.h |   12 +++++++
 4 files changed, 91 insertions(+), 8 deletions(-)

diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c
index 108f82b..a7b1888 100644
--- a/block/blk-mq-tag.c
+++ b/block/blk-mq-tag.c
@@ -121,6 +121,8 @@ struct blk_mq_tags *blk_mq_init_tags(unsigned int total_tags,
 	if (!tags)
 		return NULL;
 
+	kref_init(&tags->ref_count);
+
 	nr_tags = total_tags - reserved_tags;
 	nr_cache = nr_tags / num_possible_cpus();
 
diff --git a/block/blk-mq.c b/block/blk-mq.c
index f1b5d52..3d63d71 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1051,8 +1051,10 @@ void blk_mq_free_commands(struct request_queue *q,
 }
 EXPORT_SYMBOL(blk_mq_free_commands);
 
-static void blk_mq_free_rq_map(struct blk_mq_tags *tags)
+static void blk_mq_free_rq_map(struct kref *kref)
 {
+	struct blk_mq_tags *tags =
+		container_of(kref, struct blk_mq_tags, ref_count);
 	struct page *page;
 
 	while (!list_empty(&tags->page_list)) {
@@ -1066,6 +1068,17 @@ static void blk_mq_free_rq_map(struct blk_mq_tags *tags)
 	blk_mq_free_tags(tags);
 }
 
+static void blk_mq_put_rq_map(struct blk_mq_tags *tags)
+{
+	kref_put(&tags->ref_count, blk_mq_free_rq_map);
+}
+
+static struct blk_mq_tags *blk_mq_get_rq_map(struct blk_mq_tags *tags)
+{
+	kref_get(&tags->ref_count);
+	return tags;
+}
+
 static size_t order_to_size(unsigned int order)
 {
 	size_t ret = PAGE_SIZE;
@@ -1144,7 +1157,7 @@ static struct blk_mq_tags *blk_mq_init_rq_map(unsigned int total_tags,
 
 fail:
 	pr_warn("%s: failed to allocate requests\n", __func__);
-	blk_mq_free_rq_map(tags);
+	blk_mq_put_rq_map(tags);
 	return NULL;
 }
 
@@ -1178,10 +1191,14 @@ static int blk_mq_init_hw_queues(struct request_queue *q,
 						blk_mq_hctx_notify, hctx);
 		blk_mq_register_cpu_notifier(&hctx->cpu_notifier);
 
-		hctx->tags = blk_mq_init_rq_map(hctx->queue_depth,
-				reg->reserved_tags, reg->cmd_size, node);
-		if (!hctx->tags)
-			break;
+		if (reg->shared_tags) {
+			hctx->tags = blk_mq_get_rq_map(reg->shared_tags->tags[i]);
+		} else {
+			hctx->tags = blk_mq_init_rq_map(hctx->queue_depth,
+					reg->reserved_tags, reg->cmd_size, node);
+			if (!hctx->tags)
+				break;
+		}
 
 		/*
 		 * Allocate space for all possible cpus to avoid allocation in
@@ -1221,7 +1238,7 @@ static int blk_mq_init_hw_queues(struct request_queue *q,
 
 		blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
 		if (hctx->tags)
-			blk_mq_free_rq_map(hctx->tags);
+			blk_mq_put_rq_map(hctx->tags);
 		kfree(hctx->ctxs);
 	}
 
@@ -1399,7 +1416,7 @@ void blk_mq_free_queue(struct request_queue *q)
 		kfree(hctx->ctx_map);
 		kfree(hctx->ctxs);
 		if (hctx->tags)
-			blk_mq_free_rq_map(hctx->tags);
+			blk_mq_put_rq_map(hctx->tags);
 		blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
 		if (q->mq_ops->exit_hctx)
 			q->mq_ops->exit_hctx(hctx, i);
@@ -1459,6 +1476,56 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb,
 	return NOTIFY_OK;
 }
 
+struct blk_mq_shared_tags *blk_mq_alloc_shared_tags(struct blk_mq_reg *reg,
+		int (*init)(void *, struct request *), void *data)
+{
+	struct blk_mq_shared_tags *shared_tags;
+	int i, j;
+
+	shared_tags = kmalloc_node(sizeof(*shared_tags) +
+				reg->nr_hw_queues * sizeof(struct blk_mq_tags),
+				GFP_KERNEL, reg->numa_node);
+	if (!shared_tags)
+		goto out;
+
+	shared_tags->nr_hw_queues = reg->nr_hw_queues;
+	shared_tags->queue_depth = reg->queue_depth;
+	for (i = 0; i < reg->nr_hw_queues; i++) {
+		shared_tags->tags[i] = blk_mq_init_rq_map(reg->queue_depth,
+				reg->reserved_tags, reg->cmd_size, reg->numa_node);
+		if (!shared_tags->tags[i])
+			goto out_unwind;
+
+		for (j = 0; j < reg->queue_depth; j++) {
+			struct request *rq = shared_tags->tags[i]->rqs[j];
+			int ret;
+
+			ret = init(data, rq);
+			BUG_ON(ret);
+		}
+	}
+
+	return shared_tags;
+
+out_unwind:
+	while (--i >= 0)
+		blk_mq_put_rq_map(shared_tags->tags[i]);
+out:
+	return NULL;
+}
+
+void blk_mq_free_shared_tags(struct blk_mq_shared_tags *shared_tags,
+		void (*exit)(void *, struct request *), void *data)
+{
+	int i, j;
+
+	for (i = 0; i < shared_tags->nr_hw_queues; i++) {
+		for (j = 0; j < shared_tags->queue_depth; j++)
+			exit(data, shared_tags->tags[i]->rqs[j]);
+		blk_mq_put_rq_map(shared_tags->tags[i]);
+	}
+}
+
 void blk_mq_disable_hotplug(void)
 {
 	mutex_lock(&all_q_mutex);
diff --git a/block/blk-mq.h b/block/blk-mq.h
index eca3a47..d7c753b 100644
--- a/block/blk-mq.h
+++ b/block/blk-mq.h
@@ -17,6 +17,8 @@ struct blk_mq_tags {
 
 	struct request **rqs;
 	struct list_head page_list;
+
+	struct kref ref_count;
 };
 
 struct blk_mq_ctx {
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index 69aa3ad..a564167 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -47,6 +47,12 @@ struct blk_mq_hw_ctx {
 	struct kobject		kobj;
 };
 
+struct blk_mq_shared_tags {
+	unsigned int		nr_hw_queues;
+	unsigned int		queue_depth;
+	struct blk_mq_tags	*tags[];
+};
+
 struct blk_mq_reg {
 	struct blk_mq_ops	*ops;
 	unsigned int		nr_hw_queues;
@@ -56,6 +62,7 @@ struct blk_mq_reg {
 	int			numa_node;
 	unsigned int		timeout;
 	unsigned int		flags;		/* BLK_MQ_F_* */
+	struct blk_mq_shared_tags *shared_tags;
 };
 
 typedef int (queue_rq_fn)(struct blk_mq_hw_ctx *, struct request *);
@@ -118,6 +125,11 @@ void blk_mq_unregister_disk(struct gendisk *);
 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);
 
+struct blk_mq_shared_tags *blk_mq_alloc_shared_tags(struct blk_mq_reg *reg,
+		int (*init)(void *, struct request *), void *data);
+void blk_mq_free_shared_tags(struct blk_mq_shared_tags *shared_tags,
+		void (*exit)(void *, struct request *), void *data);
+
 void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule);
 
 void blk_mq_insert_request(struct request *, bool, bool, bool);
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux