aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIlya Dryomov <idryomov@gmail.com>2017-04-13 06:17:38 -0400
committerIlya Dryomov <idryomov@gmail.com>2017-05-04 03:19:23 -0400
commit5769ed0cb12dcd135251e546863196cec0b58e34 (patch)
treecb030108daaddd6f624152df7e99fd6c20a33385
parentfd22aef8b47cfc068448df65c1183698b0abd815 (diff)
rbd: fix error handling around rbd_init_disk()
add_disk() takes an extra reference on disk->queue, which is put in put_disk() -> disk_release(). Avoiding blk_cleanup_queue() (which also puts the queue) until add_disk() sets GENHD_FL_UP works for the queue itself, but leaks various queue internals. Conditioning tag_set freeing on GENHD_FL_UP is wrong too: all error paths after rbd_init_disk() leak the tag_set. Move the final "announce" steps out of rbd_dev_device_setup() so that it can be unwound like any other function. Leave "announce" steps to do_rbd_add/remove(). Signed-off-by: Ilya Dryomov <idryomov@gmail.com> Reviewed-by: Jason Dillaman <dillaman@redhat.com>
-rw-r--r--drivers/block/rbd.c87
1 files changed, 44 insertions, 43 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index b299ed0315f8..50395af7a9a6 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -4114,19 +4114,10 @@ static int rbd_queue_rq(struct blk_mq_hw_ctx *hctx,
4114 4114
4115static void rbd_free_disk(struct rbd_device *rbd_dev) 4115static void rbd_free_disk(struct rbd_device *rbd_dev)
4116{ 4116{
4117 struct gendisk *disk = rbd_dev->disk; 4117 blk_cleanup_queue(rbd_dev->disk->queue);
4118 4118 blk_mq_free_tag_set(&rbd_dev->tag_set);
4119 if (!disk) 4119 put_disk(rbd_dev->disk);
4120 return;
4121
4122 rbd_dev->disk = NULL; 4120 rbd_dev->disk = NULL;
4123 if (disk->flags & GENHD_FL_UP) {
4124 del_gendisk(disk);
4125 if (disk->queue)
4126 blk_cleanup_queue(disk->queue);
4127 blk_mq_free_tag_set(&rbd_dev->tag_set);
4128 }
4129 put_disk(disk);
4130} 4121}
4131 4122
4132static int rbd_obj_read_sync(struct rbd_device *rbd_dev, 4123static int rbd_obj_read_sync(struct rbd_device *rbd_dev,
@@ -4385,8 +4376,12 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
4385 if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC)) 4376 if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC))
4386 q->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES; 4377 q->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES;
4387 4378
4379 /*
4380 * disk_release() expects a queue ref from add_disk() and will
4381 * put it. Hold an extra ref until add_disk() is called.
4382 */
4383 WARN_ON(!blk_get_queue(q));
4388 disk->queue = q; 4384 disk->queue = q;
4389
4390 q->queuedata = rbd_dev; 4385 q->queuedata = rbd_dev;
4391 4386
4392 rbd_dev->disk = disk; 4387 rbd_dev->disk = disk;
@@ -5875,6 +5870,15 @@ out_err:
5875 return ret; 5870 return ret;
5876} 5871}
5877 5872
5873static void rbd_dev_device_release(struct rbd_device *rbd_dev)
5874{
5875 clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
5876 rbd_dev_mapping_clear(rbd_dev);
5877 rbd_free_disk(rbd_dev);
5878 if (!single_major)
5879 unregister_blkdev(rbd_dev->major, rbd_dev->name);
5880}
5881
5878/* 5882/*
5879 * rbd_dev->header_rwsem must be locked for write and will be unlocked 5883 * rbd_dev->header_rwsem must be locked for write and will be unlocked
5880 * upon return. 5884 * upon return.
@@ -5910,26 +5914,13 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
5910 set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE); 5914 set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE);
5911 set_disk_ro(rbd_dev->disk, rbd_dev->mapping.read_only); 5915 set_disk_ro(rbd_dev->disk, rbd_dev->mapping.read_only);
5912 5916
5913 dev_set_name(&rbd_dev->dev, "%d", rbd_dev->dev_id); 5917 ret = dev_set_name(&rbd_dev->dev, "%d", rbd_dev->dev_id);
5914 ret = device_add(&rbd_dev->dev);
5915 if (ret) 5918 if (ret)
5916 goto err_out_mapping; 5919 goto err_out_mapping;
5917 5920
5918 /* Everything's ready. Announce the disk to the world. */
5919
5920 set_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags); 5921 set_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
5921 up_write(&rbd_dev->header_rwsem); 5922 up_write(&rbd_dev->header_rwsem);
5922 5923 return 0;
5923 spin_lock(&rbd_dev_list_lock);
5924 list_add_tail(&rbd_dev->node, &rbd_dev_list);
5925 spin_unlock(&rbd_dev_list_lock);
5926
5927 add_disk(rbd_dev->disk);
5928 pr_info("%s: capacity %llu features 0x%llx\n", rbd_dev->disk->disk_name,
5929 (unsigned long long)get_capacity(rbd_dev->disk) << SECTOR_SHIFT,
5930 rbd_dev->header.features);
5931
5932 return ret;
5933 5924
5934err_out_mapping: 5925err_out_mapping:
5935 rbd_dev_mapping_clear(rbd_dev); 5926 rbd_dev_mapping_clear(rbd_dev);
@@ -6131,11 +6122,30 @@ static ssize_t do_rbd_add(struct bus_type *bus,
6131 if (rc) 6122 if (rc)
6132 goto err_out_image_probe; 6123 goto err_out_image_probe;
6133 6124
6125 /* Everything's ready. Announce the disk to the world. */
6126
6127 rc = device_add(&rbd_dev->dev);
6128 if (rc)
6129 goto err_out_device_setup;
6130
6131 add_disk(rbd_dev->disk);
6132 /* see rbd_init_disk() */
6133 blk_put_queue(rbd_dev->disk->queue);
6134
6135 spin_lock(&rbd_dev_list_lock);
6136 list_add_tail(&rbd_dev->node, &rbd_dev_list);
6137 spin_unlock(&rbd_dev_list_lock);
6138
6139 pr_info("%s: capacity %llu features 0x%llx\n", rbd_dev->disk->disk_name,
6140 (unsigned long long)get_capacity(rbd_dev->disk) << SECTOR_SHIFT,
6141 rbd_dev->header.features);
6134 rc = count; 6142 rc = count;
6135out: 6143out:
6136 module_put(THIS_MODULE); 6144 module_put(THIS_MODULE);
6137 return rc; 6145 return rc;
6138 6146
6147err_out_device_setup:
6148 rbd_dev_device_release(rbd_dev);
6139err_out_image_probe: 6149err_out_image_probe:
6140 rbd_dev_image_release(rbd_dev); 6150 rbd_dev_image_release(rbd_dev);
6141err_out_rbd_dev: 6151err_out_rbd_dev:
@@ -6165,21 +6175,6 @@ static ssize_t rbd_add_single_major(struct bus_type *bus,
6165 return do_rbd_add(bus, buf, count); 6175 return do_rbd_add(bus, buf, count);
6166} 6176}
6167 6177
6168static void rbd_dev_device_release(struct rbd_device *rbd_dev)
6169{
6170 rbd_free_disk(rbd_dev);
6171
6172 spin_lock(&rbd_dev_list_lock);
6173 list_del_init(&rbd_dev->node);
6174 spin_unlock(&rbd_dev_list_lock);
6175
6176 clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
6177 device_del(&rbd_dev->dev);
6178 rbd_dev_mapping_clear(rbd_dev);
6179 if (!single_major)
6180 unregister_blkdev(rbd_dev->major, rbd_dev->name);
6181}
6182
6183static void rbd_dev_remove_parent(struct rbd_device *rbd_dev) 6178static void rbd_dev_remove_parent(struct rbd_device *rbd_dev)
6184{ 6179{
6185 while (rbd_dev->parent) { 6180 while (rbd_dev->parent) {
@@ -6266,6 +6261,12 @@ static ssize_t do_rbd_remove(struct bus_type *bus,
6266 blk_set_queue_dying(rbd_dev->disk->queue); 6261 blk_set_queue_dying(rbd_dev->disk->queue);
6267 } 6262 }
6268 6263
6264 del_gendisk(rbd_dev->disk);
6265 spin_lock(&rbd_dev_list_lock);
6266 list_del_init(&rbd_dev->node);
6267 spin_unlock(&rbd_dev_list_lock);
6268 device_del(&rbd_dev->dev);
6269
6269 down_write(&rbd_dev->lock_rwsem); 6270 down_write(&rbd_dev->lock_rwsem);
6270 if (__rbd_is_lock_owner(rbd_dev)) 6271 if (__rbd_is_lock_owner(rbd_dev))
6271 rbd_unlock(rbd_dev); 6272 rbd_unlock(rbd_dev);