From: Greg Kroah-Hartman Date: Fri, 15 May 2015 02:18:06 +0000 (-0700) Subject: 4.0-stable patches X-Git-Tag: v3.10.79~21 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0ba19905cf7c3ed5c0af6fbc32b1beec465ded67;p=thirdparty%2Fkernel%2Fstable-queue.git 4.0-stable patches added patches: blk-mq-fix-cpu-hotplug-handling.patch blk-mq-fix-race-between-timeout-and-cpu-hotplug.patch block-destroy-bdi-before-blockdev-is-unregistered.patch --- diff --git a/queue-4.0/blk-mq-fix-cpu-hotplug-handling.patch b/queue-4.0/blk-mq-fix-cpu-hotplug-handling.patch new file mode 100644 index 00000000000..21810cba639 --- /dev/null +++ b/queue-4.0/blk-mq-fix-cpu-hotplug-handling.patch @@ -0,0 +1,100 @@ +From 2a34c0872adf252f23a6fef2d051a169ac796cef Mon Sep 17 00:00:00 2001 +From: Ming Lei +Date: Tue, 21 Apr 2015 10:00:20 +0800 +Subject: blk-mq: fix CPU hotplug handling + +From: Ming Lei + +commit 2a34c0872adf252f23a6fef2d051a169ac796cef upstream. + +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. + +Reported-by: Dongsu Park +Tested-by: Dongsu Park +Signed-off-by: Ming Lei +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + block/blk-mq.c | 34 +++++++++++++--------------------- + 1 file changed, 13 insertions(+), 21 deletions(-) + +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -1573,22 +1573,6 @@ static int blk_mq_hctx_cpu_offline(struc + 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) + { +@@ -1596,8 +1580,11 @@ static int blk_mq_hctx_notify(void *data + + 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; + } +@@ -1779,6 +1766,7 @@ static void blk_mq_map_swqueue(struct re + 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); +@@ -1805,16 +1793,20 @@ static void blk_mq_map_swqueue(struct re + * 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); ++ + /* + * Initialize batch roundrobin counts + */ diff --git a/queue-4.0/blk-mq-fix-race-between-timeout-and-cpu-hotplug.patch b/queue-4.0/blk-mq-fix-race-between-timeout-and-cpu-hotplug.patch new file mode 100644 index 00000000000..f07d1dcd5ff --- /dev/null +++ b/queue-4.0/blk-mq-fix-race-between-timeout-and-cpu-hotplug.patch @@ -0,0 +1,62 @@ +From f054b56c951bf1731ba7314a4c7f1cc0b2977cc9 Mon Sep 17 00:00:00 2001 +From: Ming Lei +Date: Tue, 21 Apr 2015 10:00:19 +0800 +Subject: blk-mq: fix race between timeout and CPU hotplug + +From: Ming Lei + +commit f054b56c951bf1731ba7314a4c7f1cc0b2977cc9 upstream. + +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. + +Reported-by: Dongsu Park +Tested-by: Dongsu Park +Signed-off-by: Ming Lei +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + block/blk-mq.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -675,8 +675,11 @@ static void blk_mq_rq_timer(unsigned lon + 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); ++ } + } + } + +@@ -2075,9 +2078,16 @@ static int blk_mq_queue_reinit_notify(st + */ + 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); + diff --git a/queue-4.0/block-destroy-bdi-before-blockdev-is-unregistered.patch b/queue-4.0/block-destroy-bdi-before-blockdev-is-unregistered.patch new file mode 100644 index 00000000000..251575e9320 --- /dev/null +++ b/queue-4.0/block-destroy-bdi-before-blockdev-is-unregistered.patch @@ -0,0 +1,111 @@ +From 6cd18e711dd8075da9d78cfc1239f912ff28968a Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Mon, 27 Apr 2015 14:12:22 +1000 +Subject: block: destroy bdi before blockdev is unregistered. + +From: NeilBrown + +commit 6cd18e711dd8075da9d78cfc1239f912ff28968a upstream. + +Because of the peculiar way that md devices are created (automatically +when the device node is opened), a new device can be created and +registered immediately after the + blk_unregister_region(disk_devt(disk), disk->minors); +call in del_gendisk(). + +Therefore it is important that all visible artifacts of the previous +device are removed before this call. In particular, the 'bdi'. + +Since: +commit c4db59d31e39ea067c32163ac961e9c80198fd37 +Author: Christoph Hellwig + fs: don't reassign dirty inodes to default_backing_dev_info + +moved the + device_unregister(bdi->dev); +call from bdi_unregister() to bdi_destroy() it has been quite easy to +lose a race and have a new (e.g.) "md127" be created after the +blk_unregister_region() call and before bdi_destroy() is ultimately +called by the final 'put_disk', which must come after del_gendisk(). + +The new device finds that the bdi name is already registered in sysfs +and complains + +> [ 9627.630029] WARNING: CPU: 18 PID: 3330 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x5a/0x70() +> [ 9627.630032] sysfs: cannot create duplicate filename '/devices/virtual/bdi/9:127' + +We can fix this by moving the bdi_destroy() call out of +blk_release_queue() (which can happen very late when a refcount +reaches zero) and into blk_cleanup_queue() - which happens exactly when the md +device driver calls it. + +Then it is only necessary for md to call blk_cleanup_queue() before +del_gendisk(). As loop.c devices are also created on demand by +opening the device node, we make the same change there. + +Fixes: c4db59d31e39ea067c32163ac961e9c80198fd37 +Reported-by: Azat Khuzhin +Cc: Christoph Hellwig +Signed-off-by: NeilBrown +Reviewed-by: Christoph Hellwig +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + block/blk-core.c | 2 ++ + block/blk-sysfs.c | 2 -- + drivers/block/loop.c | 2 +- + drivers/md/md.c | 4 ++-- + 4 files changed, 5 insertions(+), 5 deletions(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -552,6 +552,8 @@ void blk_cleanup_queue(struct request_qu + q->queue_lock = &q->__queue_lock; + spin_unlock_irq(lock); + ++ bdi_destroy(&q->backing_dev_info); ++ + /* @q is and will stay empty, shutdown and put */ + blk_put_queue(q); + } +--- a/block/blk-sysfs.c ++++ b/block/blk-sysfs.c +@@ -522,8 +522,6 @@ static void blk_release_queue(struct kob + + blk_trace_shutdown(q); + +- bdi_destroy(&q->backing_dev_info); +- + ida_simple_remove(&blk_queue_ida, q->id); + call_rcu(&q->rcu_head, blk_free_queue_rcu); + } +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -1672,8 +1672,8 @@ out: + + static void loop_remove(struct loop_device *lo) + { +- del_gendisk(lo->lo_disk); + blk_cleanup_queue(lo->lo_queue); ++ del_gendisk(lo->lo_disk); + blk_mq_free_tag_set(&lo->tag_set); + put_disk(lo->lo_disk); + kfree(lo); +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -4754,12 +4754,12 @@ static void md_free(struct kobject *ko) + if (mddev->sysfs_state) + sysfs_put(mddev->sysfs_state); + ++ if (mddev->queue) ++ blk_cleanup_queue(mddev->queue); + if (mddev->gendisk) { + del_gendisk(mddev->gendisk); + put_disk(mddev->gendisk); + } +- if (mddev->queue) +- blk_cleanup_queue(mddev->queue); + + kfree(mddev); + } diff --git a/queue-4.0/series b/queue-4.0/series index 64018e33e6d..71dc091c843 100644 --- a/queue-4.0/series +++ b/queue-4.0/series @@ -20,3 +20,6 @@ xen-console-update-console-event-channel-on-resume.patch xen-events-set-irq_info-evtchn-before-binding-the-channel-to-cpu-in-__startup_pirq.patch xen-pciback-add-name-prefix-to-global-permissive-variable.patch revert-dm-crypt-fix-deadlock-when-async-crypto-algorithm-returns-ebusy.patch +block-destroy-bdi-before-blockdev-is-unregistered.patch +blk-mq-fix-race-between-timeout-and-cpu-hotplug.patch +blk-mq-fix-cpu-hotplug-handling.patch