aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <mchristi@redhat.com>2016-08-18 12:38:45 -0400
committerIlya Dryomov <idryomov@gmail.com>2016-08-24 17:49:17 -0400
commit0276dca6c1ecb9a665645ff573e70685a57759af (patch)
tree36498244b9e8de7e3d51cc494d32d4979ae94191
parent0d6d1e9c2e970c26e8a1ec4932ffffacec90e0b4 (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-rbd10
-rw-r--r--drivers/block/rbd.c35
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
7Being used for adding and removing rbd block devices. 7Being used for adding and removing rbd block devices.
8 8
9Usage: <mon ip addr> <options> <pool name> <rbd image name> [snap name] 9Usage: <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>
14will be assigned for any registered block device. If snapshot is used, it will 14will be assigned for any registered block device. If snapshot is used, it will
15be mapped read-only. 15be mapped read-only.
16 16
17Removal of a device: 17Usage: <dev-id> [force]
18 18
19 $ echo <dev-id> > /sys/bus/rbd/remove 19 $ echo 2 > /sys/bus/rbd/remove
20
21Optional "force" argument which when passed will wait for running requests and
22then unmap the image. Requests sent to the driver after initiating the removal
23will be failed. (August 2016, since 4.9.)
20 24
21What: /sys/bus/rbd/add_single_major 25What: /sys/bus/rbd/add_single_major
22Date: December 2013 26Date: 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);