aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBart Van Assche <bart.vanassche@wdc.com>2018-01-17 14:48:10 -0500
committerJens Axboe <axboe@kernel.dk>2018-01-18 14:54:44 -0500
commit2c2086afc2b8b974fac32cb028e73dc27bfae442 (patch)
tree0a9d392612cbbdb0d3dcdf9190444d1964eeb962
parent14a23498ba97683c6790b1bcd8b2cdfe9ad99797 (diff)
block: Protect less code with sysfs_lock in blk_{un,}register_queue()
The __blk_mq_register_dev(), blk_mq_unregister_dev(), elv_register_queue() and elv_unregister_queue() calls need to be protected with sysfs_lock but other code in these functions not. Hence protect only this code with sysfs_lock. This patch fixes a locking inversion issue in blk_unregister_queue() and also in an error path of blk_register_queue(): it is not allowed to hold sysfs_lock around the kobject_del(&q->kobj) call. Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--block/blk-sysfs.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 4a6a40ffd78e..cbea895a5547 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -853,6 +853,10 @@ struct kobj_type blk_queue_ktype = {
853 .release = blk_release_queue, 853 .release = blk_release_queue,
854}; 854};
855 855
856/**
857 * blk_register_queue - register a block layer queue with sysfs
858 * @disk: Disk of which the request queue should be registered with sysfs.
859 */
856int blk_register_queue(struct gendisk *disk) 860int blk_register_queue(struct gendisk *disk)
857{ 861{
858 int ret; 862 int ret;
@@ -909,11 +913,12 @@ int blk_register_queue(struct gendisk *disk)
909 if (q->request_fn || (q->mq_ops && q->elevator)) { 913 if (q->request_fn || (q->mq_ops && q->elevator)) {
910 ret = elv_register_queue(q); 914 ret = elv_register_queue(q);
911 if (ret) { 915 if (ret) {
916 mutex_unlock(&q->sysfs_lock);
912 kobject_uevent(&q->kobj, KOBJ_REMOVE); 917 kobject_uevent(&q->kobj, KOBJ_REMOVE);
913 kobject_del(&q->kobj); 918 kobject_del(&q->kobj);
914 blk_trace_remove_sysfs(dev); 919 blk_trace_remove_sysfs(dev);
915 kobject_put(&dev->kobj); 920 kobject_put(&dev->kobj);
916 goto unlock; 921 return ret;
917 } 922 }
918 } 923 }
919 ret = 0; 924 ret = 0;
@@ -923,6 +928,13 @@ unlock:
923} 928}
924EXPORT_SYMBOL_GPL(blk_register_queue); 929EXPORT_SYMBOL_GPL(blk_register_queue);
925 930
931/**
932 * blk_unregister_queue - counterpart of blk_register_queue()
933 * @disk: Disk of which the request queue should be unregistered from sysfs.
934 *
935 * Note: the caller is responsible for guaranteeing that this function is called
936 * after blk_register_queue() has finished.
937 */
926void blk_unregister_queue(struct gendisk *disk) 938void blk_unregister_queue(struct gendisk *disk)
927{ 939{
928 struct request_queue *q = disk->queue; 940 struct request_queue *q = disk->queue;
@@ -935,8 +947,9 @@ void blk_unregister_queue(struct gendisk *disk)
935 return; 947 return;
936 948
937 /* 949 /*
938 * Protect against the 'queue' kobj being accessed 950 * Since sysfs_remove_dir() prevents adding new directory entries
939 * while/after it is removed. 951 * before removal of existing entries starts, protect against
952 * concurrent elv_iosched_store() calls.
940 */ 953 */
941 mutex_lock(&q->sysfs_lock); 954 mutex_lock(&q->sysfs_lock);
942 955
@@ -944,18 +957,24 @@ void blk_unregister_queue(struct gendisk *disk)
944 queue_flag_clear(QUEUE_FLAG_REGISTERED, q); 957 queue_flag_clear(QUEUE_FLAG_REGISTERED, q);
945 spin_unlock_irq(q->queue_lock); 958 spin_unlock_irq(q->queue_lock);
946 959
947 wbt_exit(q); 960 /*
948 961 * Remove the sysfs attributes before unregistering the queue data
962 * structures that can be modified through sysfs.
963 */
949 if (q->mq_ops) 964 if (q->mq_ops)
950 blk_mq_unregister_dev(disk_to_dev(disk), q); 965 blk_mq_unregister_dev(disk_to_dev(disk), q);
951 966 mutex_unlock(&q->sysfs_lock);
952 if (q->request_fn || (q->mq_ops && q->elevator))
953 elv_unregister_queue(q);
954 967
955 kobject_uevent(&q->kobj, KOBJ_REMOVE); 968 kobject_uevent(&q->kobj, KOBJ_REMOVE);
956 kobject_del(&q->kobj); 969 kobject_del(&q->kobj);
957 blk_trace_remove_sysfs(disk_to_dev(disk)); 970 blk_trace_remove_sysfs(disk_to_dev(disk));
958 kobject_put(&disk_to_dev(disk)->kobj);
959 971
972 wbt_exit(q);
973
974 mutex_lock(&q->sysfs_lock);
975 if (q->request_fn || (q->mq_ops && q->elevator))
976 elv_unregister_queue(q);
960 mutex_unlock(&q->sysfs_lock); 977 mutex_unlock(&q->sysfs_lock);
978
979 kobject_put(&disk_to_dev(disk)->kobj);
961} 980}