From 6bb323e9561e440bb617d8e70a45892399ad0381 Mon Sep 17 00:00:00 2001 From: Tahsin Erdogan Date: Tue, 14 Feb 2017 19:27:38 -0800 Subject: [PATCH] block: do not allow updates through sysfs until registration completes When a new disk shows up, sysfs queue directory is created before elevator is registered. This allows a user to attempt a scheduler switch even though the initial registration hasn't completed yet. In one scenario, blk_register_queue() calls elv_register_queue() and right before cfq_registered_queue() is called, another process executes elevator_switch() and replaces q->elevator with deadline scheduler. When cfq_registered_queue() executes it interprets e->elevator_data as struct cfq_data even though it is actually struct deadline_data. Grab q->sysfs_lock in blk_register_queue() to synchronize with sysfs callers. Signed-off-by: Tahsin Erdogan Signed-off-by: Jens Axboe [sw0312.kim: backport mainline commit b410aff2bd9f to fix possible deadlock in blk-mq for cpu hotplug] Signed-off-by: Seung-Woo Kim Change-Id: Ifcdada904f565a7eb456d7b69966f7408ac256a3 --- block/blk-sysfs.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 9cc8d7c..88c13e5 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -695,19 +695,24 @@ int blk_register_queue(struct gendisk *disk) if (ret) return ret; + if (q->mq_ops) + blk_mq_register_dev(dev, q); + + /* Prevent changes through sysfs until registration is completed. */ + mutex_lock(&q->sysfs_lock); + ret = kobject_add(&q->kobj, kobject_get(&dev->kobj), "%s", "queue"); if (ret < 0) { blk_trace_remove_sysfs(dev); - return ret; + goto unlock; } kobject_uevent(&q->kobj, KOBJ_ADD); - if (q->mq_ops) - blk_mq_register_dev(dev, q); - - if (!q->request_fn) - return 0; + if (!q->request_fn) { + ret = 0; + goto unlock; + } ret = elv_register_queue(q); if (ret) { @@ -715,10 +720,12 @@ int blk_register_queue(struct gendisk *disk) kobject_del(&q->kobj); blk_trace_remove_sysfs(dev); kobject_put(&dev->kobj); - return ret; + goto unlock; } - - return 0; + ret = 0; +unlock: + mutex_unlock(&q->sysfs_lock); + return ret; } void blk_unregister_queue(struct gendisk *disk) -- 2.7.4