diff options
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/rbd.c | 69 |
1 files changed, 23 insertions, 46 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 8b78a08483a6..d250549d27a4 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/fs.h> | 41 | #include <linux/fs.h> |
42 | #include <linux/blkdev.h> | 42 | #include <linux/blkdev.h> |
43 | #include <linux/slab.h> | 43 | #include <linux/slab.h> |
44 | #include <linux/idr.h> | ||
44 | 45 | ||
45 | #include "rbd_types.h" | 46 | #include "rbd_types.h" |
46 | 47 | ||
@@ -385,6 +386,8 @@ static struct kmem_cache *rbd_img_request_cache; | |||
385 | static struct kmem_cache *rbd_obj_request_cache; | 386 | static struct kmem_cache *rbd_obj_request_cache; |
386 | static struct kmem_cache *rbd_segment_name_cache; | 387 | static struct kmem_cache *rbd_segment_name_cache; |
387 | 388 | ||
389 | static DEFINE_IDA(rbd_dev_id_ida); | ||
390 | |||
388 | static int rbd_img_request_submit(struct rbd_img_request *img_request); | 391 | static int rbd_img_request_submit(struct rbd_img_request *img_request); |
389 | 392 | ||
390 | static void rbd_dev_device_release(struct device *dev); | 393 | static void rbd_dev_device_release(struct device *dev); |
@@ -4371,20 +4374,27 @@ static void rbd_bus_del_dev(struct rbd_device *rbd_dev) | |||
4371 | device_unregister(&rbd_dev->dev); | 4374 | device_unregister(&rbd_dev->dev); |
4372 | } | 4375 | } |
4373 | 4376 | ||
4374 | static atomic64_t rbd_dev_id_max = ATOMIC64_INIT(0); | ||
4375 | |||
4376 | /* | 4377 | /* |
4377 | * Get a unique rbd identifier for the given new rbd_dev, and add | 4378 | * Get a unique rbd identifier for the given new rbd_dev, and add |
4378 | * the rbd_dev to the global list. The minimum rbd id is 1. | 4379 | * the rbd_dev to the global list. |
4379 | */ | 4380 | */ |
4380 | static void rbd_dev_id_get(struct rbd_device *rbd_dev) | 4381 | static int rbd_dev_id_get(struct rbd_device *rbd_dev) |
4381 | { | 4382 | { |
4382 | rbd_dev->dev_id = atomic64_inc_return(&rbd_dev_id_max); | 4383 | int new_dev_id; |
4384 | |||
4385 | new_dev_id = ida_simple_get(&rbd_dev_id_ida, 0, 0, GFP_KERNEL); | ||
4386 | if (new_dev_id < 0) | ||
4387 | return new_dev_id; | ||
4388 | |||
4389 | rbd_dev->dev_id = new_dev_id; | ||
4383 | 4390 | ||
4384 | spin_lock(&rbd_dev_list_lock); | 4391 | spin_lock(&rbd_dev_list_lock); |
4385 | list_add_tail(&rbd_dev->node, &rbd_dev_list); | 4392 | list_add_tail(&rbd_dev->node, &rbd_dev_list); |
4386 | spin_unlock(&rbd_dev_list_lock); | 4393 | spin_unlock(&rbd_dev_list_lock); |
4394 | |||
4387 | dout("rbd_dev %p given dev id %d\n", rbd_dev, rbd_dev->dev_id); | 4395 | dout("rbd_dev %p given dev id %d\n", rbd_dev, rbd_dev->dev_id); |
4396 | |||
4397 | return 0; | ||
4388 | } | 4398 | } |
4389 | 4399 | ||
4390 | /* | 4400 | /* |
@@ -4393,48 +4403,13 @@ static void rbd_dev_id_get(struct rbd_device *rbd_dev) | |||
4393 | */ | 4403 | */ |
4394 | static void rbd_dev_id_put(struct rbd_device *rbd_dev) | 4404 | static void rbd_dev_id_put(struct rbd_device *rbd_dev) |
4395 | { | 4405 | { |
4396 | struct list_head *tmp; | ||
4397 | int rbd_id = rbd_dev->dev_id; | ||
4398 | int max_id; | ||
4399 | |||
4400 | rbd_assert(rbd_id > 0); | ||
4401 | |||
4402 | dout("rbd_dev %p released dev id %d\n", rbd_dev, rbd_dev->dev_id); | ||
4403 | spin_lock(&rbd_dev_list_lock); | 4406 | spin_lock(&rbd_dev_list_lock); |
4404 | list_del_init(&rbd_dev->node); | 4407 | list_del_init(&rbd_dev->node); |
4405 | |||
4406 | /* | ||
4407 | * If the id being "put" is not the current maximum, there | ||
4408 | * is nothing special we need to do. | ||
4409 | */ | ||
4410 | if (rbd_id != atomic64_read(&rbd_dev_id_max)) { | ||
4411 | spin_unlock(&rbd_dev_list_lock); | ||
4412 | return; | ||
4413 | } | ||
4414 | |||
4415 | /* | ||
4416 | * We need to update the current maximum id. Search the | ||
4417 | * list to find out what it is. We're more likely to find | ||
4418 | * the maximum at the end, so search the list backward. | ||
4419 | */ | ||
4420 | max_id = 0; | ||
4421 | list_for_each_prev(tmp, &rbd_dev_list) { | ||
4422 | struct rbd_device *rbd_dev; | ||
4423 | |||
4424 | rbd_dev = list_entry(tmp, struct rbd_device, node); | ||
4425 | if (rbd_dev->dev_id > max_id) | ||
4426 | max_id = rbd_dev->dev_id; | ||
4427 | } | ||
4428 | spin_unlock(&rbd_dev_list_lock); | 4408 | spin_unlock(&rbd_dev_list_lock); |
4429 | 4409 | ||
4430 | /* | 4410 | ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id); |
4431 | * The max id could have been updated by rbd_dev_id_get(), in | 4411 | |
4432 | * which case it now accurately reflects the new maximum. | 4412 | dout("rbd_dev %p released dev id %d\n", rbd_dev, rbd_dev->dev_id); |
4433 | * Be careful not to overwrite the maximum value in that | ||
4434 | * case. | ||
4435 | */ | ||
4436 | atomic64_cmpxchg(&rbd_dev_id_max, rbd_id, max_id); | ||
4437 | dout(" max dev id has been reset\n"); | ||
4438 | } | 4413 | } |
4439 | 4414 | ||
4440 | /* | 4415 | /* |
@@ -4857,10 +4832,12 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev) | |||
4857 | { | 4832 | { |
4858 | int ret; | 4833 | int ret; |
4859 | 4834 | ||
4860 | /* generate unique id: find highest unique id, add one */ | 4835 | /* Get an id and fill in device name. */ |
4861 | rbd_dev_id_get(rbd_dev); | 4836 | |
4837 | ret = rbd_dev_id_get(rbd_dev); | ||
4838 | if (ret) | ||
4839 | return ret; | ||
4862 | 4840 | ||
4863 | /* Fill in the device name, now that we have its id. */ | ||
4864 | BUILD_BUG_ON(DEV_NAME_LEN | 4841 | BUILD_BUG_ON(DEV_NAME_LEN |
4865 | < sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH); | 4842 | < sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH); |
4866 | sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->dev_id); | 4843 | sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->dev_id); |