linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/2] blk-mq: fix oops caused by CPU hotplug
@ 2015-04-21  2:00 Ming Lei
  2015-04-21  2:00 ` [PATCH v1 1/2] blk-mq: fix race between timeout and " Ming Lei
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Ming Lei @ 2015-04-21  2:00 UTC (permalink / raw)
  To: Jens Axboe, linux-kernel; +Cc: Christoph Hellwig, Al Viro, Maxim Patlasov

Hi Guys,

Dongsu Park reported[1] that kernel oops can be triggered easily by
CPU plug when there is pending I/O on virtio-scsi.

Turns out two problems exist in blk-mq core code and both can trigger
oops by CPU plug:
        - timeout handling vs CPU hotplug, especially unmapped hw queue tags
        is still touched by timeout handler
        - in case of shared tags, there is one bug about setting and checking
        hctx->tags during CPU hotplug

The two patches fix the two problem, and Dongsu has verified that
the oops is fixed with the two patches too.

[1], http://marc.info/?t=142926389200008&r=1&w=2

V1:
	- update comment
	- moving tags allocation in blk_mq_map_swqueue() because
	unmapped hw queue can be remapped after CPU topo is changed

 block/blk-mq.c |   50 ++++++++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 24 deletions(-)


Thanks,
Ming Lei


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v1 1/2] blk-mq: fix race between timeout and CPU hotplug
  2015-04-21  2:00 [PATCH v1 0/2] blk-mq: fix oops caused by CPU hotplug Ming Lei
@ 2015-04-21  2:00 ` Ming Lei
  2015-04-21  2:00 ` [PATCH v1 2/2] blk-mq: fix CPU hotplug handling Ming Lei
  2015-04-23 16:27 ` [PATCH v1 0/2] blk-mq: fix oops caused by CPU hotplug Jens Axboe
  2 siblings, 0 replies; 4+ messages in thread
From: Ming Lei @ 2015-04-21  2:00 UTC (permalink / raw)
  To: Jens Axboe, linux-kernel
  Cc: Christoph Hellwig, Al Viro, Maxim Patlasov, Ming Lei, stable

Firstly during CPU hotplug, even queue is freezed, timeout
handler still may come and access hctx->tags, which may cause
use after free, so this patch deactivates timeout handler
inside CPU hotplug notifier.

Secondly, tags can be shared by more than one queues, so we
have to check if the hctx has been unmapped, otherwise
still use-after-free on tags can be triggered.

Cc: <stable@vger.kernel.org>
Reported-by: Dongsu Park <dongsu.park@profitbricks.com>
Tested-by: Dongsu Park <dongsu.park@profitbricks.com>
Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 block/blk-mq.c |   16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/block/blk-mq.c b/block/blk-mq.c
index ade8a2d..1fccb98 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -677,8 +677,11 @@ static void blk_mq_rq_timer(unsigned long priv)
 		data.next = blk_rq_timeout(round_jiffies_up(data.next));
 		mod_timer(&q->timeout, data.next);
 	} else {
-		queue_for_each_hw_ctx(q, hctx, i)
-			blk_mq_tag_idle(hctx);
+		queue_for_each_hw_ctx(q, hctx, i) {
+			/* the hctx may be unmapped, so check it here */
+			if (blk_mq_hw_queue_mapped(hctx))
+				blk_mq_tag_idle(hctx);
+		}
 	}
 }
 
@@ -2090,9 +2093,16 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb,
 	 */
 	list_for_each_entry(q, &all_q_list, all_q_node)
 		blk_mq_freeze_queue_start(q);
-	list_for_each_entry(q, &all_q_list, all_q_node)
+	list_for_each_entry(q, &all_q_list, all_q_node) {
 		blk_mq_freeze_queue_wait(q);
 
+		/*
+		 * timeout handler can't touch hw queue during the
+		 * reinitialization
+		 */
+		del_timer_sync(&q->timeout);
+	}
+
 	list_for_each_entry(q, &all_q_list, all_q_node)
 		blk_mq_queue_reinit(q);
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v1 2/2] blk-mq: fix CPU hotplug handling
  2015-04-21  2:00 [PATCH v1 0/2] blk-mq: fix oops caused by CPU hotplug Ming Lei
  2015-04-21  2:00 ` [PATCH v1 1/2] blk-mq: fix race between timeout and " Ming Lei
@ 2015-04-21  2:00 ` Ming Lei
  2015-04-23 16:27 ` [PATCH v1 0/2] blk-mq: fix oops caused by CPU hotplug Jens Axboe
  2 siblings, 0 replies; 4+ messages in thread
From: Ming Lei @ 2015-04-21  2:00 UTC (permalink / raw)
  To: Jens Axboe, linux-kernel
  Cc: Christoph Hellwig, Al Viro, Maxim Patlasov, Ming Lei, stable

hctx->tags has to be set as NULL in case that it is to be unmapped
no matter if set->tags[hctx->queue_num] is NULL or not in blk_mq_map_swqueue()
because shared tags can be freed already from another request queue.

The same situation has to be considered during handling CPU online too.
Unmapped hw queue can be remapped after CPU topo is changed, so we need
to allocate tags for the hw queue in blk_mq_map_swqueue(). Then tags
allocation for hw queue can be removed in hctx cpu online notifier, and it
is reasonable to do that after mapping is updated.

Cc: <stable@vger.kernel.org>
Reported-by: Dongsu Park <dongsu.park@profitbricks.com>
Tested-by: Dongsu Park <dongsu.park@profitbricks.com>
Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 block/blk-mq.c |   34 +++++++++++++---------------------
 1 file changed, 13 insertions(+), 21 deletions(-)

diff --git a/block/blk-mq.c b/block/blk-mq.c
index 1fccb98..76f460e 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1574,22 +1574,6 @@ static int blk_mq_hctx_cpu_offline(struct blk_mq_hw_ctx *hctx, int cpu)
 	return NOTIFY_OK;
 }
 
-static int blk_mq_hctx_cpu_online(struct blk_mq_hw_ctx *hctx, int cpu)
-{
-	struct request_queue *q = hctx->queue;
-	struct blk_mq_tag_set *set = q->tag_set;
-
-	if (set->tags[hctx->queue_num])
-		return NOTIFY_OK;
-
-	set->tags[hctx->queue_num] = blk_mq_init_rq_map(set, hctx->queue_num);
-	if (!set->tags[hctx->queue_num])
-		return NOTIFY_STOP;
-
-	hctx->tags = set->tags[hctx->queue_num];
-	return NOTIFY_OK;
-}
-
 static int blk_mq_hctx_notify(void *data, unsigned long action,
 			      unsigned int cpu)
 {
@@ -1597,8 +1581,11 @@ static int blk_mq_hctx_notify(void *data, unsigned long action,
 
 	if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
 		return blk_mq_hctx_cpu_offline(hctx, cpu);
-	else if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN)
-		return blk_mq_hctx_cpu_online(hctx, cpu);
+
+	/*
+	 * In case of CPU online, tags may be reallocated
+	 * in blk_mq_map_swqueue() after mapping is updated.
+	 */
 
 	return NOTIFY_OK;
 }
@@ -1778,6 +1765,7 @@ static void blk_mq_map_swqueue(struct request_queue *q)
 	unsigned int i;
 	struct blk_mq_hw_ctx *hctx;
 	struct blk_mq_ctx *ctx;
+	struct blk_mq_tag_set *set = q->tag_set;
 
 	queue_for_each_hw_ctx(q, hctx, i) {
 		cpumask_clear(hctx->cpumask);
@@ -1806,16 +1794,20 @@ static void blk_mq_map_swqueue(struct request_queue *q)
 		 * disable it and free the request entries.
 		 */
 		if (!hctx->nr_ctx) {
-			struct blk_mq_tag_set *set = q->tag_set;
-
 			if (set->tags[i]) {
 				blk_mq_free_rq_map(set, set->tags[i], i);
 				set->tags[i] = NULL;
-				hctx->tags = NULL;
 			}
+			hctx->tags = NULL;
 			continue;
 		}
 
+		/* unmapped hw queue can be remapped after CPU topo changed */
+		if (!set->tags[i])
+			set->tags[i] = blk_mq_init_rq_map(set, i);
+		hctx->tags = set->tags[i];
+		WARN_ON(!hctx->tags);
+
 		/*
 		 * Set the map size to the number of mapped software queues.
 		 * This is more accurate and more efficient than looping
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v1 0/2] blk-mq: fix oops caused by CPU hotplug
  2015-04-21  2:00 [PATCH v1 0/2] blk-mq: fix oops caused by CPU hotplug Ming Lei
  2015-04-21  2:00 ` [PATCH v1 1/2] blk-mq: fix race between timeout and " Ming Lei
  2015-04-21  2:00 ` [PATCH v1 2/2] blk-mq: fix CPU hotplug handling Ming Lei
@ 2015-04-23 16:27 ` Jens Axboe
  2 siblings, 0 replies; 4+ messages in thread
From: Jens Axboe @ 2015-04-23 16:27 UTC (permalink / raw)
  To: Ming Lei, linux-kernel; +Cc: Christoph Hellwig, Al Viro, Maxim Patlasov

On 04/20/2015 08:00 PM, Ming Lei wrote:
> Hi Guys,
>
> Dongsu Park reported[1] that kernel oops can be triggered easily by
> CPU plug when there is pending I/O on virtio-scsi.
>
> Turns out two problems exist in blk-mq core code and both can trigger
> oops by CPU plug:
>          - timeout handling vs CPU hotplug, especially unmapped hw queue tags
>          is still touched by timeout handler
>          - in case of shared tags, there is one bug about setting and checking
>          hctx->tags during CPU hotplug
>
> The two patches fix the two problem, and Dongsu has verified that
> the oops is fixed with the two patches too.
>
> [1], http://marc.info/?t=142926389200008&r=1&w=2

Applied, thanks Ming!

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2015-04-23 16:28 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-21  2:00 [PATCH v1 0/2] blk-mq: fix oops caused by CPU hotplug Ming Lei
2015-04-21  2:00 ` [PATCH v1 1/2] blk-mq: fix race between timeout and " Ming Lei
2015-04-21  2:00 ` [PATCH v1 2/2] blk-mq: fix CPU hotplug handling Ming Lei
2015-04-23 16:27 ` [PATCH v1 0/2] blk-mq: fix oops caused by CPU hotplug Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).