From 620f5e1455fdcb05cd3873c1e260141849829e35 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 7 Oct 2016 12:32:43 +0200 Subject: [PATCH] rbd: expose rbd unmap options Reuse rbd map -o infrastructure to expose rbd unmap options in a similar fashion. Currently it's just one bool option, but we may need more in the future. Signed-off-by: Ilya Dryomov --- doc/man/8/rbd.rst | 27 ++++++++++++------- src/include/krbd.h | 6 +++-- src/krbd.cc | 35 ++++++++++++++++-------- src/test/cli/rbd/help.t | 2 ++ src/test/librbd/fsx.cc | 2 +- src/tools/rbd/action/Kernel.cc | 49 +++++++++++++++++++++++++++++++--- 6 files changed, 94 insertions(+), 27 deletions(-) diff --git a/doc/man/8/rbd.rst b/doc/man/8/rbd.rst index 9cc522242eb3..215ca9acb62a 100644 --- a/doc/man/8/rbd.rst +++ b/doc/man/8/rbd.rst @@ -122,11 +122,12 @@ Parameters Make json or xml formatted output more human-readable. -.. option:: -o map-options, --options map-options +.. option:: -o krbd-options, --options krbd-options - Specifies which options to use when mapping an image. map-options is - a comma-separated string of options (similar to mount(8) mount options). - See map options section below for more details. + Specifies which options to use when mapping or unmapping an image via the + rbd kernel driver. krbd-options is a comma-separated list of options + (similar to mount(8) mount options). See kernel rbd (krbd) options section + below for more details. .. option:: --read-only @@ -326,10 +327,10 @@ Commands Remove any previously set limit on the number of snapshots allowed on an image. -:command:`map` [-o | --options *map-options* ] [--read-only] *image-spec* | *snap-spec* +:command:`map` [-o | --options *krbd-options* ] [--read-only] *image-spec* | *snap-spec* Maps the specified image to a block device via the rbd kernel module. -:command:`unmap` *image-spec* | *snap-spec* | *device-path* +:command:`unmap` [-o | --options *krbd-options* ] *image-spec* | *snap-spec* | *device-path* Unmaps the block device that was mapped via the rbd kernel module. :command:`showmapped` @@ -421,14 +422,14 @@ By default, [*stripe_unit*] is the same as the object size and [*stripe_count*] used. -Map options -=========== +Kernel rbd (krbd) options +========================= Most of these options are useful mainly for debugging and benchmarking. The default values are set in the kernel and may therefore depend on the version of the running kernel. -libceph (per client instance) options: +Per client instance `rbd map` options: * fsid=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee - FSID that should be assumed by the client. @@ -467,7 +468,7 @@ libceph (per client instance) options: * osd_idle_ttl=x - OSD idle TTL (default is 60 seconds). -Mapping (per block device) options: +Per mapping (block device) `rbd map` options: * rw - Map the image read-write (default). @@ -478,6 +479,12 @@ Mapping (per block device) options: * lock_on_read - Acquire exclusive lock on reads, in addition to writes and discards (since 4.9). +`rbd unmap` options: + +* force - Force the unmapping of a block device that is open (since 4.9). The + driver will wait for running requests to complete and then unmap; requests + sent to the driver after initiating the unmap will be failed. + Examples ======== diff --git a/src/include/krbd.h b/src/include/krbd.h index 75206cded658..c6f3c9d037c0 100644 --- a/src/include/krbd.h +++ b/src/include/krbd.h @@ -27,9 +27,11 @@ void krbd_destroy(struct krbd_ctx *ctx); int krbd_map(struct krbd_ctx *ctx, const char *pool, const char *image, const char *snap, const char *options, char **pdevnode); -int krbd_unmap(struct krbd_ctx *ctx, const char *devnode); +int krbd_unmap(struct krbd_ctx *ctx, const char *devnode, + const char *options); int krbd_unmap_by_spec(struct krbd_ctx *ctx, const char *pool, - const char *image, const char *snap); + const char *image, const char *snap, + const char *options); #ifdef __cplusplus } diff --git a/src/krbd.cc b/src/krbd.cc index 99fbf208dc69..f1827f75901a 100644 --- a/src/krbd.cc +++ b/src/krbd.cc @@ -453,6 +453,16 @@ out_enm: return r; } +static string build_unmap_buf(const string& id, const char *options) +{ + string buf(id); + if (strcmp(options, "") != 0) { + buf += " "; + buf += options; + } + return buf; +} + static int wait_for_udev_remove(struct udev_monitor *mon, dev_t devno) { for (;;) { @@ -480,7 +490,7 @@ static int wait_for_udev_remove(struct udev_monitor *mon, dev_t devno) return 0; } -static int do_unmap(struct udev *udev, dev_t devno, const string& id) +static int do_unmap(struct udev *udev, dev_t devno, const string& buf) { struct udev_monitor *mon; int r; @@ -504,7 +514,7 @@ static int do_unmap(struct udev *udev, dev_t devno, const string& id) * Try to circumvent this with a retry before turning to udev. */ for (int tries = 0; ; tries++) { - r = sysfs_write_rbd_remove(id); + r = sysfs_write_rbd_remove(buf); if (r >= 0) { break; } else if (r == -EBUSY && tries < 2) { @@ -536,7 +546,8 @@ out_mon: return r; } -static int unmap_image(struct krbd_ctx *ctx, const char *devnode) +static int unmap_image(struct krbd_ctx *ctx, const char *devnode, + const char *options) { struct stat sb; dev_t wholedevno; @@ -568,12 +579,12 @@ static int unmap_image(struct krbd_ctx *ctx, const char *devnode) return r; } - return do_unmap(ctx->udev, wholedevno, id); + return do_unmap(ctx->udev, wholedevno, build_unmap_buf(id, options)); } static int unmap_image(struct krbd_ctx *ctx, const char *pool, - const char *image, const char *snap) - + const char *image, const char *snap, + const char *options) { dev_t devno; string id; @@ -592,7 +603,7 @@ static int unmap_image(struct krbd_ctx *ctx, const char *pool, return r; } - return do_unmap(ctx->udev, devno, id); + return do_unmap(ctx->udev, devno, build_unmap_buf(id, options)); } static bool dump_one_image(Formatter *f, TextTable *tbl, @@ -730,15 +741,17 @@ extern "C" int krbd_map(struct krbd_ctx *ctx, const char *pool, return r; } -extern "C" int krbd_unmap(struct krbd_ctx *ctx, const char *devnode) +extern "C" int krbd_unmap(struct krbd_ctx *ctx, const char *devnode, + const char *options) { - return unmap_image(ctx, devnode); + return unmap_image(ctx, devnode, options); } extern "C" int krbd_unmap_by_spec(struct krbd_ctx *ctx, const char *pool, - const char *image, const char *snap) + const char *image, const char *snap, + const char *options) { - return unmap_image(ctx, pool, image, snap); + return unmap_image(ctx, pool, image, snap, options); } int krbd_showmapped(struct krbd_ctx *ctx, Formatter *f) diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index 358606da3788..2af8912fa636 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -1382,6 +1382,7 @@ rbd help unmap usage: rbd unmap [--pool ] [--image ] [--snap ] + [--options ] Unmap a rbd device that was used by the kernel. @@ -1395,6 +1396,7 @@ -p [ --pool ] arg pool name --image arg image name --snap arg snapshot name + -o [ --options ] arg unmap options rbd help watch usage: rbd watch [--pool ] [--image ] diff --git a/src/test/librbd/fsx.cc b/src/test/librbd/fsx.cc index de3b9f96e77d..5666d9305e8e 100644 --- a/src/test/librbd/fsx.cc +++ b/src/test/librbd/fsx.cc @@ -827,7 +827,7 @@ krbd_close(struct rbd_ctx *ctx) return ret; } - ret = krbd_unmap(krbd, ctx->krbd_name); + ret = krbd_unmap(krbd, ctx->krbd_name, ""); if (ret < 0) { prt("krbd_unmap(%s) failed\n", ctx->krbd_name); return ret; diff --git a/src/tools/rbd/action/Kernel.cc b/src/tools/rbd/action/Kernel.cc index 3ebece6156da..ee640062ce8a 100644 --- a/src/tools/rbd/action/Kernel.cc +++ b/src/tools/rbd/action/Kernel.cc @@ -27,7 +27,7 @@ namespace po = boost::program_options; namespace { -std::map map_options; +std::map map_options; // used for both map and unmap } // anonymous namespace @@ -140,6 +140,27 @@ static int parse_map_options(char *options) return 0; } +static int parse_unmap_options(char *options) +{ + for (char *this_char = strtok(options, ", "); + this_char != NULL; + this_char = strtok(NULL, ",")) { + char *value_char; + + if ((value_char = strchr(this_char, '=')) != NULL) + *value_char++ = '\0'; + + if (!strcmp(this_char, "force")) { + put_map_option("force", this_char); + } else { + std::cerr << "rbd: unknown unmap option '" << this_char << "'" << std::endl; + return -EINVAL; + } + } + + return 0; +} + static int do_kernel_showmapped(Formatter *f) { struct krbd_ctx *krbd; @@ -239,16 +260,24 @@ static int do_kernel_unmap(const char *dev, const char *poolname, const char *imgname, const char *snapname) { struct krbd_ctx *krbd; + std::ostringstream oss; int r; r = krbd_create_from_context(g_ceph_context, &krbd); if (r < 0) return r; + for (auto it = map_options.cbegin(); it != map_options.cend(); ++it) { + if (it != map_options.cbegin()) + oss << ","; + oss << it->second; + } + if (dev) - r = krbd_unmap(krbd, dev); + r = krbd_unmap(krbd, dev, oss.str().c_str()); else - r = krbd_unmap_by_spec(krbd, poolname, imgname, snapname); + r = krbd_unmap_by_spec(krbd, poolname, imgname, snapname, + oss.str().c_str()); krbd_destroy(krbd); return r; @@ -345,6 +374,8 @@ void get_unmap_arguments(po::options_description *positional, at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE); at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE); at::add_snap_option(options, at::ARGUMENT_MODIFIER_NONE); + options->add_options() + ("options,o", po::value(), "unmap options"); } int execute_unmap(const po::variables_map &vm) { @@ -374,6 +405,18 @@ int execute_unmap(const po::variables_map &vm) { return -EINVAL; } + if (vm.count("options")) { + char *cli_unmap_options = strdup(vm["options"].as().c_str()); + BOOST_SCOPE_EXIT( (cli_unmap_options) ) { + free(cli_unmap_options); + } BOOST_SCOPE_EXIT_END; + + if (parse_unmap_options(cli_unmap_options)) { + std::cerr << "rbd: couldn't parse unmap options" << std::endl; + return -EINVAL; + } + } + utils::init_context(); r = do_kernel_unmap(device_name.empty() ? nullptr : device_name.c_str(), -- 2.47.3