Commit 0276dca6 authored by Mike Christie's avatar Mike Christie Committed by Ilya Dryomov

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: default avatarMike Christie <mchristi@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent 0d6d1e9c
......@@ -6,7 +6,7 @@ Description:
Being used for adding and removing rbd block devices.
Usage: <mon ip addr> <options> <pool name> <rbd image name> [snap name]
Usage: <mon ip addr> <options> <pool name> <rbd image name> [<snap name>]
$ echo "192.168.0.1 name=admin rbd foo" > /sys/bus/rbd/add
......@@ -14,9 +14,13 @@ The snapshot name can be "-" or omitted to map the image read/write. A <dev-id>
will be assigned for any registered block device. If snapshot is used, it will
be mapped read-only.
Removal of a device:
Usage: <dev-id> [force]
$ echo <dev-id> > /sys/bus/rbd/remove
$ echo 2 > /sys/bus/rbd/remove
Optional "force" argument which when passed will wait for running requests and
then unmap the image. Requests sent to the driver after initiating the removal
will be failed. (August 2016, since 4.9.)
What: /sys/bus/rbd/add_single_major
Date: December 2013
......
......@@ -6347,18 +6347,26 @@ static ssize_t do_rbd_remove(struct bus_type *bus,
struct rbd_device *rbd_dev = NULL;
struct list_head *tmp;
int dev_id;
unsigned long ul;
char opt_buf[6];
bool already = false;
bool force = false;
int ret;
ret = kstrtoul(buf, 10, &ul);
if (ret)
return ret;
/* convert to int; abort if we lost anything in the conversion */
dev_id = (int)ul;
if (dev_id != ul)
dev_id = -1;
opt_buf[0] = '\0';
sscanf(buf, "%d %5s", &dev_id, opt_buf);
if (dev_id < 0) {
pr_err("dev_id out of range\n");
return -EINVAL;
}
if (opt_buf[0] != '\0') {
if (!strcmp(opt_buf, "force")) {
force = true;
} else {
pr_err("bad remove option at '%s'\n", opt_buf);
return -EINVAL;
}
}
ret = -ENOENT;
spin_lock(&rbd_dev_list_lock);
......@@ -6371,7 +6379,7 @@ static ssize_t do_rbd_remove(struct bus_type *bus,
}
if (!ret) {
spin_lock_irq(&rbd_dev->lock);
if (rbd_dev->open_count)
if (rbd_dev->open_count && !force)
ret = -EBUSY;
else
already = test_and_set_bit(RBD_DEV_FLAG_REMOVING,
......@@ -6382,6 +6390,15 @@ static ssize_t do_rbd_remove(struct bus_type *bus,
if (ret < 0 || already)
return ret;
if (force) {
/*
* Prevent new IO from being queued and wait for existing
* IO to complete/fail.
*/
blk_mq_freeze_queue(rbd_dev->disk->queue);
blk_set_queue_dying(rbd_dev->disk->queue);
}
down_write(&rbd_dev->lock_rwsem);
if (__rbd_is_lock_owner(rbd_dev))
rbd_unlock(rbd_dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment