Skip to contentSkip to conversation

blk-mq: fix leak of hctx->ctx_map

PATCH In review Ming Lei 2 participants 6 messages May 27, 2014 Block layer

lore
Share & tools
lore

Ming Lei

author
#0 lore raw

cover blk-mq: fix leak of hctx->ctx_map

Misc changes.

Thanks,
--
Ming Lei

author
#1 lore raw

PATCH 1/3 blk-mq: fix leak of hctx->ctx_map

hctx->ctx_map should have been freed inside blk_mq_free_queue().

---
 block/blk-mq.c |    1 +
 1 file changed, 1 insertion(+)
block/blk-mq.c +1 -0
index 54e7886..ba39fa7 100644
@@ -1841,6 +1841,7 @@ void blk_mq_free_queue(struct request_queue *q)
 
 	queue_for_each_hw_ctx(q, hctx, i) {
 		kfree(hctx->ctxs);
+		blk_mq_free_bitmap(&hctx->ctx_map);
 		blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
 		if (q->mq_ops->exit_hctx)
 			q->mq_ops->exit_hctx(hctx, i);
Signature · 1 line
1.7.9.5
author
#2 lore raw

PATCH 2/3 blk-mq: avoid code duplication

In reply to Ming Lei

blk_mq_exit_hw_queues() and blk_mq_free_hw_queues() are introduced to avoid code duplication.

---
 block/blk-mq.c |   60 ++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 37 insertions(+), 23 deletions(-)
block/blk-mq.c +37 -23
index ba39fa7..e32c04c 100644
@@ -1519,11 +1519,43 @@ static int blk_mq_hctx_notify(void *data, unsigned long action,
 	return NOTIFY_OK;
 }
 
+static void blk_mq_exit_hw_queues(struct request_queue *q,
+		struct blk_mq_tag_set *set, int nr_queue)
+{
+	struct blk_mq_hw_ctx *hctx;
+	unsigned int i;
+
+	queue_for_each_hw_ctx(q, hctx, i) {
+		if (i == nr_queue)
+			break;
+
+		if (set->ops->exit_hctx)
+			set->ops->exit_hctx(hctx, i);
+
+		blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
+		kfree(hctx->ctxs);
+		blk_mq_free_bitmap(&hctx->ctx_map);
+	}
+
+}
+
+static void blk_mq_free_hw_queues(struct request_queue *q,
+		struct blk_mq_tag_set *set)
+{
+	struct blk_mq_hw_ctx *hctx;
+	unsigned int i;
+
+	queue_for_each_hw_ctx(q, hctx, i) {
+		free_cpumask_var(hctx->cpumask);
+		set->ops->free_hctx(hctx, i);
+	}
+}
+
 static int blk_mq_init_hw_queues(struct request_queue *q,
 		struct blk_mq_tag_set *set)
 {
 	struct blk_mq_hw_ctx *hctx;
-	unsigned int i, j;
+	unsigned int i;
 
 	/*
 	 * Initialize hardware queues
@@ -1575,17 +1607,7 @@ static int blk_mq_init_hw_queues(struct request_queue *q,
 	/*
 	 * Init failed
 	 */
-	queue_for_each_hw_ctx(q, hctx, j) {
-		if (i == j)
-			break;
-
-		if (set->ops->exit_hctx)
-			set->ops->exit_hctx(hctx, j);
-
-		blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
-		kfree(hctx->ctxs);
-		blk_mq_free_bitmap(&hctx->ctx_map);
-	}
+	blk_mq_exit_hw_queues(q, set, i);
 
 	return 1;
 }
@@ -1834,20 +1856,12 @@ EXPORT_SYMBOL(blk_mq_init_queue);
 
 void blk_mq_free_queue(struct request_queue *q)
 {
-	struct blk_mq_hw_ctx *hctx;
-	int i;
+	struct blk_mq_tag_set	*set = q->tag_set;
 
 	blk_mq_del_queue_tag_set(q);
 
-	queue_for_each_hw_ctx(q, hctx, i) {
-		kfree(hctx->ctxs);
-		blk_mq_free_bitmap(&hctx->ctx_map);
-		blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
-		if (q->mq_ops->exit_hctx)
-			q->mq_ops->exit_hctx(hctx, i);
-		free_cpumask_var(hctx->cpumask);
-		q->mq_ops->free_hctx(hctx, i);
-	}
+	blk_mq_exit_hw_queues(q, set, set->nr_hw_queues);
+	blk_mq_free_hw_queues(q, set);
 
 	free_percpu(q->queue_ctx);
 	kfree(q->queue_hw_ctx);
Signature · 1 line
1.7.9.5
author
#3 lore raw

PATCH 3/3 block: only allocate/free mq_usage_counter in blk-mq

In reply to Ming Lei

The percpu counter is only used for blk-mq, so move its allocation and free inside blk-mq, and don't allocate it for legacy queue device.

---
 block/blk-core.c  |    7 +------
 block/blk-mq.c    |    5 +++++
 block/blk-sysfs.c |    2 --
 3 files changed, 6 insertions(+), 8 deletions(-)
block/blk-core.c +1 -6
index 5b6f768..29d5fba 100644
@@ -576,12 +576,9 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 	if (!q)
 		return NULL;
 
-	if (percpu_counter_init(&q->mq_usage_counter, 0))
-		goto fail_q;
-
 	q->id = ida_simple_get(&blk_queue_ida, 0, 0, gfp_mask);
 	if (q->id < 0)
-		goto fail_c;
+		goto fail_q;
 
 	q->backing_dev_info.ra_pages =
 			(VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
@@ -639,8 +636,6 @@ fail_bdi:
 	bdi_destroy(&q->backing_dev_info);
 fail_id:
 	ida_simple_remove(&blk_queue_ida, q->id);
-fail_c:
-	percpu_counter_destroy(&q->mq_usage_counter);
 fail_q:
 	kmem_cache_free(blk_requestq_cachep, q);
 	return NULL;
block/blk-mq.c +5 -0
index e32c04c..d80cb89 100644
@@ -1777,6 +1777,9 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
 	if (!q)
 		goto err_hctxs;
 
+	if (percpu_counter_init(&q->mq_usage_counter, 0))
+		goto err_map;
+
 	q->mq_map = blk_mq_make_queue_map(set);
 	if (!q->mq_map)
 		goto err_map;
@@ -1863,6 +1866,8 @@ void blk_mq_free_queue(struct request_queue *q)
 	blk_mq_exit_hw_queues(q, set, set->nr_hw_queues);
 	blk_mq_free_hw_queues(q, set);
 
+	percpu_counter_destroy(&q->mq_usage_counter);
+
 	free_percpu(q->queue_ctx);
 	kfree(q->queue_hw_ctx);
 	kfree(q->mq_map);
block/blk-sysfs.c +0 -2
index 4d6811a..23321fb 100644
@@ -517,8 +517,6 @@ static void blk_release_queue(struct kobject *kobj)
 	if (q->queue_tags)
 		__blk_queue_free_tags(q);
 
-	percpu_counter_destroy(&q->mq_usage_counter);
-
 	if (q->mq_ops)
 		blk_mq_free_queue(q);
 
Signature · 1 line
1.7.9.5
maintainer
#4 lore raw
In reply to Ming Lei
Quoted 1 line · Ming Lei

Misc changes.

All look good, however they don't apply to the current for-3.16/core branch. What are they against? I hand applied 1, but could you regenerate 2+3 against the current tree?

Signature · 1 line
Jens Axboe
author
#5 lore raw
Quoted 6 lines · Jens Axboe
Quoted 1 line · Ming Lei

Misc changes.

All look good, however they don't apply to the current for-3.16/core branch. What are they against? I hand applied 1, but could you regenerate 2+3 against the current tree?

It is against your tree several days ago, and will resend the 2nd and 3rd out.

Thanks,

Signature · 1 line
Ming Lei