diff options
author | Mike Christie <mchristi@redhat.com> | 2016-08-18 12:38:45 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2016-08-24 17:49:17 -0400 |
commit | 0276dca6c1ecb9a665645ff573e70685a57759af (patch) | |
tree | 36498244b9e8de7e3d51cc494d32d4979ae94191 | |
parent | 0d6d1e9c2e970c26e8a1ec4932ffffacec90e0b4 (diff) |
rbd: add force close option
This adds a force close option, so we can force the unmapping
of a rbd device that is open. If a path/device is blacklisted, apps
like multipathd can map a new device and then unmap the old one.
The unmapping cleanup would then be handled by the generic hotunplug
code paths in multipahd like is done for iSCSI, FC/FCOE, SAS, etc.
Signed-off-by: Mike Christie <mchristi@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
-rw-r--r-- | Documentation/ABI/testing/sysfs-bus-rbd | 10 | ||||
-rw-r--r-- | drivers/block/rbd.c | 35 |
2 files changed, 33 insertions, 12 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-rbd b/Documentation/ABI/testing/sysfs-bus-rbd index 6dccbf82fcf4..f208ac58d613 100644 --- a/Documentation/ABI/testing/sysfs-bus-rbd +++ b/Documentation/ABI/testing/sysfs-bus-rbd | |||
@@ -6,7 +6,7 @@ Description: | |||
6 | 6 | ||
7 | Being used for adding and removing rbd block devices. | 7 | Being used for adding and removing rbd block devices. |
8 | 8 | ||
9 | Usage: <mon ip addr> <options> <pool name> <rbd image name> [snap name] | 9 | Usage: <mon ip addr> <options> <pool name> <rbd image name> [<snap name>] |
10 | 10 | ||
11 | $ echo "192.168.0.1 name=admin rbd foo" > /sys/bus/rbd/add | 11 | $ echo "192.168.0.1 name=admin rbd foo" > /sys/bus/rbd/add |
12 | 12 | ||
@@ -14,9 +14,13 @@ The snapshot name can be "-" or omitted to map the image read/write. A <dev-id> | |||
14 | will be assigned for any registered block device. If snapshot is used, it will | 14 | will be assigned for any registered block device. If snapshot is used, it will |
15 | be mapped read-only. | 15 | be mapped read-only. |
16 | 16 | ||
17 | Removal of a device: | 17 | Usage: <dev-id> [force] |
18 | 18 | ||
19 | $ echo <dev-id> > /sys/bus/rbd/remove | 19 | $ echo 2 > /sys/bus/rbd/remove |
20 | |||
21 | Optional "force" argument which when passed will wait for running requests and | ||
22 | then unmap the image. Requests sent to the driver after initiating the removal | ||
23 | will be failed. (August 2016, since 4.9.) | ||
20 | 24 | ||
21 | What: /sys/bus/rbd/add_single_major | 25 | What: /sys/bus/rbd/add_single_major |
22 | Date: December 2013 | 26 | Date: December 2013 |
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 8ff2dc872008..35fc1da6c83d 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
@@ -6347,18 +6347,26 @@ static ssize_t do_rbd_remove(struct bus_type *bus, | |||
6347 | struct rbd_device *rbd_dev = NULL; | 6347 | struct rbd_device *rbd_dev = NULL; |
6348 | struct list_head *tmp; | 6348 | struct list_head *tmp; |
6349 | int dev_id; | 6349 | int dev_id; |
6350 | unsigned long ul; | 6350 | char opt_buf[6]; |
6351 | bool already = false; | 6351 | bool already = false; |
6352 | bool force = false; | ||
6352 | int ret; | 6353 | int ret; |
6353 | 6354 | ||
6354 | ret = kstrtoul(buf, 10, &ul); | 6355 | dev_id = -1; |
6355 | if (ret) | 6356 | opt_buf[0] = '\0'; |
6356 | return ret; | 6357 | sscanf(buf, "%d %5s", &dev_id, opt_buf); |
6357 | 6358 | if (dev_id < 0) { | |
6358 | /* convert to int; abort if we lost anything in the conversion */ | 6359 | pr_err("dev_id out of range\n"); |
6359 | dev_id = (int)ul; | ||
6360 | if (dev_id != ul) | ||
6361 | return -EINVAL; | 6360 | return -EINVAL; |
6361 | } | ||
6362 | if (opt_buf[0] != '\0') { | ||
6363 | if (!strcmp(opt_buf, "force")) { | ||
6364 | force = true; | ||
6365 | } else { | ||
6366 | pr_err("bad remove option at '%s'\n", opt_buf); | ||
6367 | return -EINVAL; | ||
6368 | } | ||
6369 | } | ||
6362 | 6370 | ||
6363 | ret = -ENOENT; | 6371 | ret = -ENOENT; |
6364 | spin_lock(&rbd_dev_list_lock); | 6372 | spin_lock(&rbd_dev_list_lock); |
@@ -6371,7 +6379,7 @@ static ssize_t do_rbd_remove(struct bus_type *bus, | |||
6371 | } | 6379 | } |
6372 | if (!ret) { | 6380 | if (!ret) { |
6373 | spin_lock_irq(&rbd_dev->lock); | 6381 | spin_lock_irq(&rbd_dev->lock); |
6374 | if (rbd_dev->open_count) | 6382 | if (rbd_dev->open_count && !force) |
6375 | ret = -EBUSY; | 6383 | ret = -EBUSY; |
6376 | else | 6384 | else |
6377 | already = test_and_set_bit(RBD_DEV_FLAG_REMOVING, | 6385 | already = test_and_set_bit(RBD_DEV_FLAG_REMOVING, |
@@ -6382,6 +6390,15 @@ static ssize_t do_rbd_remove(struct bus_type *bus, | |||
6382 | if (ret < 0 || already) | 6390 | if (ret < 0 || already) |
6383 | return ret; | 6391 | return ret; |
6384 | 6392 | ||
6393 | if (force) { | ||
6394 | /* | ||
6395 | * Prevent new IO from being queued and wait for existing | ||
6396 | * IO to complete/fail. | ||
6397 | */ | ||
6398 | blk_mq_freeze_queue(rbd_dev->disk->queue); | ||
6399 | blk_set_queue_dying(rbd_dev->disk->queue); | ||
6400 | } | ||
6401 | |||
6385 | down_write(&rbd_dev->lock_rwsem); | 6402 | down_write(&rbd_dev->lock_rwsem); |
6386 | if (__rbd_is_lock_owner(rbd_dev)) | 6403 | if (__rbd_is_lock_owner(rbd_dev)) |
6387 | rbd_unlock(rbd_dev); | 6404 | rbd_unlock(rbd_dev); |