From: Jason Dillaman Date: Thu, 12 Mar 2015 16:10:32 +0000 (-0400) Subject: rbd: add feature enable/disable support X-Git-Tag: v9.0.0~37^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=3a7b28d9a2de365d515ea1380ee9e4f867504e10;p=ceph.git rbd: add feature enable/disable support Mutable image features can now be enabled/disabled via the rbd CLI. Signed-off-by: Jason Dillaman --- diff --git a/man/8/rbd.rst b/man/8/rbd.rst index c33593e95d60..9e9aea0e4837 100644 --- a/man/8/rbd.rst +++ b/man/8/rbd.rst @@ -123,16 +123,16 @@ Parameters Map the image read-only. Equivalent to -o ro. -.. option:: --image-features features +.. option:: --image-feature feature - Specifies which RBD format 2 features are to be enabled when creating - an image. The numbers from the desired features below should be added - to compute the parameter value: + Specifies which RBD format 2 feature should be enabled when creating + an image. Multiple features can be enabled by repeating this option + multiple times. The following features are supported: - +1: layering support - +2: striping v2 support - +4: exclusive locking support - +8: object map support + layering: layering support + striping: striping v2 support + exclusive-lock: exclusive locking support + object-map: object map support (requires exclusive-lock) .. option:: --image-shared @@ -294,6 +294,14 @@ Commands :command:`status` [*image-name*] Show the status of the image, including which clients have it open. +:command:`feature` disable [*image-name*] [*feature*] + Disables the specified feature on the specified image. Multiple features can + be specified. + +:command:`feature` enable [*image-name*] [*feature*] + Enables the specified feature on the specified image. Multiple features can + be specified. + :command:`lock` list [*image-name*] Show locks held on the image. The first column is the locker to use with the `lock remove` command. diff --git a/src/rbd.cc b/src/rbd.cc index 3d86a92be6a0..50a044aa1838 100644 --- a/src/rbd.cc +++ b/src/rbd.cc @@ -76,6 +76,13 @@ map map_options; // -o / --options map #define dout_subsys ceph_subsys_rbd +static std::map feature_mapping = + boost::assign::map_list_of( + RBD_FEATURE_LAYERING, "layering")( + RBD_FEATURE_STRIPINGV2, "striping")( + RBD_FEATURE_EXCLUSIVE_LOCK, "exclusive-lock")( + RBD_FEATURE_OBJECT_MAP, "object-map"); + void usage() { cout << @@ -133,6 +140,8 @@ void usage() " mapped by the kernel\n" " showmapped show the rbd images mapped\n" " by the kernel\n" +" feature disable disable the specified image feature\n" +" feature enable enable the specified image feature\n" " lock list show locks held on an image\n" " lock add [--shared ] take a lock called id on an image\n" " lock remove release a lock on an image\n" @@ -158,9 +167,8 @@ void usage() " --image-format format to use when creating an image\n" " format 1 is the original format (default)\n" " format 2 supports cloning\n" -" --image-features optional format 2 features to enable\n" -" +1 layering support, +2 striping v2,\n" -" +4 exclusive lock, +8 object map\n" +" --image-feature optional format 2 feature to enable.\n" +" use multiple times to enable multiple features\n" " --image-shared image will be used concurrently (disables\n" " RBD exclusive lock and dependent features)\n" " --stripe-unit size (in bytes) of a block of data\n" @@ -174,7 +182,27 @@ void usage() " --no-progress do not show progress for long-running commands\n" " -o, --options options to use when mapping an image\n" " --read-only set device readonly when mapping image\n" -" --allow-shrink allow shrinking of an image when resizing\n"; +" --allow-shrink allow shrinking of an image when resizing\n" +"\n" +"Supported image features:\n" +" "; + +for (std::map::const_iterator it = feature_mapping.begin(); + it != feature_mapping.end(); ++it) { + if (it != feature_mapping.begin()) { + cout << ", "; + } + cout << it->second; + if ((it->first & RBD_FEATURES_MUTABLE) != 0) { + cout << " (*)"; + } + if ((it->first & g_conf->rbd_default_features) != 0) { + cout << " (+)"; + } +} +cout << "\n\n" + << " (*) supports enabling/disabling on existing images\n" + << " (+) enabled by default for new images if features are not specified\n"; } static void format_bitmask(Formatter *f, const std::string &name, @@ -212,12 +240,7 @@ static void format_bitmask(Formatter *f, const std::string &name, static void format_features(Formatter *f, uint64_t features) { - std::map mapping = boost::assign::map_list_of( - RBD_FEATURE_LAYERING, "layering")( - RBD_FEATURE_STRIPINGV2, "striping")( - RBD_FEATURE_EXCLUSIVE_LOCK, "exclusive")( - RBD_FEATURE_OBJECT_MAP, "object map"); - format_bitmask(f, "feature", mapping, features); + format_bitmask(f, "feature", feature_mapping, features); } static void format_flags(Formatter *f, uint64_t flags) @@ -227,6 +250,17 @@ static void format_flags(Formatter *f, uint64_t flags) format_bitmask(f, "flag", mapping, flags); } +static bool decode_feature(const char* feature_name, uint64_t *feature) { + for (std::map::const_iterator it = feature_mapping.begin(); + it != feature_mapping.end(); ++it) { + if (strcmp(feature_name, it->second.c_str()) == 0) { + *feature = it->first; + return true; + } + } + return false; +} + struct MyProgressContext : public librbd::ProgressContext { const char *operation; int last_pc; @@ -2494,6 +2528,14 @@ static int parse_map_options(char *options) return 0; } +enum CommandType{ + COMMAND_TYPE_NONE, + COMMAND_TYPE_SNAP, + COMMAND_TYPE_LOCK, + COMMAND_TYPE_METADATA, + COMMAND_TYPE_FEATURE +}; + enum { OPT_NO_CMD = 0, OPT_LIST, @@ -2523,6 +2565,8 @@ enum { OPT_MAP, OPT_UNMAP, OPT_SHOWMAPPED, + OPT_FEATURE_DISABLE, + OPT_FEATURE_ENABLE, OPT_LOCK_LIST, OPT_LOCK_ADD, OPT_LOCK_REMOVE, @@ -2534,9 +2578,11 @@ enum { OPT_METADATA_REMOVE, }; -static int get_cmd(const char *cmd, bool snapcmd, bool lockcmd, bool metacmd) +static int get_cmd(const char *cmd, CommandType command_type) { - if (!snapcmd && !lockcmd) { + switch (command_type) + { + case COMMAND_TYPE_NONE: if (strcmp(cmd, "ls") == 0 || strcmp(cmd, "list") == 0) return OPT_LIST; @@ -2584,7 +2630,8 @@ static int get_cmd(const char *cmd, bool snapcmd, bool lockcmd, bool metacmd) return OPT_UNMAP; if (strcmp(cmd, "bench-write") == 0) return OPT_BENCH_WRITE; - } else if (snapcmd) { + break; + case COMMAND_TYPE_SNAP: if (strcmp(cmd, "create") == 0 || strcmp(cmd, "add") == 0) return OPT_SNAP_CREATE; @@ -2603,7 +2650,8 @@ static int get_cmd(const char *cmd, bool snapcmd, bool lockcmd, bool metacmd) return OPT_SNAP_PROTECT; if (strcmp(cmd, "unprotect") == 0) return OPT_SNAP_UNPROTECT; - } else if (metacmd) { + break; + case COMMAND_TYPE_METADATA: if (strcmp(cmd, "list") == 0) return OPT_METADATA_LIST; if (strcmp(cmd, "set") == 0) @@ -2612,7 +2660,8 @@ static int get_cmd(const char *cmd, bool snapcmd, bool lockcmd, bool metacmd) return OPT_METADATA_GET; if (strcmp(cmd, "remove") == 0) return OPT_METADATA_REMOVE; - } else { + break; + case COMMAND_TYPE_LOCK: if (strcmp(cmd, "ls") == 0 || strcmp(cmd, "list") == 0) return OPT_LOCK_LIST; @@ -2621,6 +2670,14 @@ static int get_cmd(const char *cmd, bool snapcmd, bool lockcmd, bool metacmd) if (strcmp(cmd, "remove") == 0 || strcmp(cmd, "rm") == 0) return OPT_LOCK_REMOVE; + break; + case COMMAND_TYPE_FEATURE: + if (strcmp(cmd, "disable") == 0) { + return OPT_FEATURE_DISABLE; + } else if (strcmp(cmd, "enable") == 0) { + return OPT_FEATURE_ENABLE; + } + break; } return OPT_NO_CMD; @@ -2670,7 +2727,7 @@ int main(int argc, const char **argv) output_format_specified = false; int format = 1; - uint64_t features = g_conf->rbd_default_features; + uint64_t features = 0; bool shared = false; const char *imgname = NULL, *snapname = NULL, *destname = NULL, @@ -2680,6 +2737,7 @@ int main(int argc, const char **argv) *fromsnapname = NULL, *first_diff = NULL, *second_diff = NULL, *key = NULL, *value = NULL; char *cli_map_options = NULL; + std::vector feature_names; bool lflag = false; int pretty_format = 0; long long stripe_unit = 0, stripe_count = 0; @@ -2772,7 +2830,16 @@ int main(int argc, const char **argv) progress = false; } else if (ceph_argparse_flag(args, i , "--allow-shrink", (char *)NULL)) { resize_allow_shrink = true; + } else if (ceph_argparse_witharg(args, i, &val, "--image-feature", (char *)NULL)) { + uint64_t feature; + if (!decode_feature(val.c_str(), &feature)) { + cerr << "rbd: invalid image feature: " << val << std::endl; + return EXIT_FAILURE; + } + features |= feature; } else if (ceph_argparse_witharg(args, i, &val, "--image-features", (char *)NULL)) { + cerr << "rbd: using --image-features for specifying the rbd image format is" + << " deprecated, use --image-feature instead" << std::endl; features = strict_strtol(val.c_str(), 10, &parse_err); if (!parse_err.empty()) { cerr << "rbd: error parsing --image-features: " << parse_err @@ -2800,6 +2867,12 @@ int main(int argc, const char **argv) } } + if (features != 0 && !format_specified) { + format = 2; + format_specified = true; + } else if (features == 0) { + features = g_conf->rbd_default_features; + } if (shared) { features &= ~(RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_OBJECT_MAP); } @@ -2822,23 +2895,30 @@ int main(int argc, const char **argv) cerr << "rbd: which snap command do you want?" << std::endl; return EXIT_FAILURE; } - opt_cmd = get_cmd(*i, true, false, false); + opt_cmd = get_cmd(*i, COMMAND_TYPE_SNAP); } else if (strcmp(*i, "lock") == 0) { i = args.erase(i); if (i == args.end()) { cerr << "rbd: which lock command do you want?" << std::endl; return EXIT_FAILURE; } - opt_cmd = get_cmd(*i, false, true, false); + opt_cmd = get_cmd(*i, COMMAND_TYPE_LOCK); } else if (strcmp(*i, "image-meta") == 0) { i = args.erase(i); if (i == args.end()) { cerr << "rbd: which image-meta command do you want?" << std::endl; return EXIT_FAILURE; } - opt_cmd = get_cmd(*i, false, false, true); + opt_cmd = get_cmd(*i, COMMAND_TYPE_METADATA); + } else if (strcmp(*i, "feature") == 0) { + i = args.erase(i); + if (i == args.end()) { + cerr << "rbd: which feature command do you want?" << std::endl; + return EXIT_FAILURE; + } + opt_cmd = get_cmd(*i, COMMAND_TYPE_FEATURE); } else { - opt_cmd = get_cmd(*i, false, false, false); + opt_cmd = get_cmd(*i, COMMAND_TYPE_NONE); } if (opt_cmd == OPT_NO_CMD) { cerr << "rbd: error parsing command '" << *i << "'; -h or --help for usage" << std::endl; @@ -2921,6 +3001,14 @@ if (!set_conf_param(v, p1, p2, p3)) { \ case OPT_METADATA_REMOVE: SET_CONF_PARAM(v, &imgname, &key, NULL); break; + case OPT_FEATURE_DISABLE: + case OPT_FEATURE_ENABLE: + if (imgname == NULL) { + imgname = v; + } else { + feature_names.push_back(v); + } + break; default: assert(0); break; @@ -3030,6 +3118,24 @@ if (!set_conf_param(v, p1, p2, p3)) { \ return EXIT_FAILURE; } + if (opt_cmd == OPT_FEATURE_DISABLE || opt_cmd == OPT_FEATURE_ENABLE) { + if (feature_names.empty()) { + cerr << "rbd: at least one feature name must be specified" << std::endl; + return EXIT_FAILURE; + } + + features = 0; + for (size_t i = 0; i < feature_names.size(); ++i) { + uint64_t feature; + if (!decode_feature(feature_names[i], &feature)) { + cerr << "rbd: invalid feature name specified: " << feature_names[i] + << std::endl; + return EXIT_FAILURE; + } + features |= feature; + } + } + // do this unconditionally so we can parse pool/image@snapshot into // the relevant parts set_pool_image_name(imgname, (char **)&poolname, @@ -3148,11 +3254,11 @@ if (!set_conf_param(v, p1, p2, p3)) { \ opt_cmd == OPT_INFO || opt_cmd == OPT_SNAP_LIST || opt_cmd == OPT_IMPORT_DIFF || opt_cmd == OPT_EXPORT || opt_cmd == OPT_EXPORT_DIFF || opt_cmd == OPT_COPY || - opt_cmd == OPT_DIFF || + opt_cmd == OPT_DIFF || opt_cmd == OPT_STATUS || opt_cmd == OPT_CHILDREN || opt_cmd == OPT_LOCK_LIST || opt_cmd == OPT_METADATA_SET || opt_cmd == OPT_METADATA_LIST || opt_cmd == OPT_METADATA_REMOVE || opt_cmd == OPT_METADATA_GET || - opt_cmd == OPT_STATUS)) { + opt_cmd == OPT_FEATURE_DISABLE || opt_cmd == OPT_FEATURE_ENABLE)) { if (opt_cmd == OPT_INFO || opt_cmd == OPT_SNAP_LIST || opt_cmd == OPT_EXPORT || opt_cmd == OPT_EXPORT || opt_cmd == OPT_COPY || @@ -3597,7 +3703,16 @@ if (!set_conf_param(v, p1, p2, p3)) { \ return -r; } break; - } + case OPT_FEATURE_DISABLE: + case OPT_FEATURE_ENABLE: + r = image.update_features(features, opt_cmd == OPT_FEATURE_ENABLE); + if (r < 0) { + cerr << "rbd: failed to update image features: " << cpp_strerror(r) + << std::endl; + return -r; + } + break; + } return 0; } diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index 541ba9abea20..679a89756e3f 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -53,6 +53,8 @@ mapped by the kernel showmapped show the rbd images mapped by the kernel + feature disable disable the specified image feature + feature enable enable the specified image feature lock list show locks held on an image lock add [--shared ] take a lock called id on an image lock remove release a lock on an image @@ -78,9 +80,8 @@ --image-format format to use when creating an image format 1 is the original format (default) format 2 supports cloning - --image-features optional format 2 features to enable - +1 layering support, +2 striping v2, - +4 exclusive lock, +8 object map + --image-feature optional format 2 feature to enable. + use multiple times to enable multiple features --image-shared image will be used concurrently (disables RBD exclusive lock and dependent features) --stripe-unit size (in bytes) of a block of data @@ -95,3 +96,9 @@ -o, --options options to use when mapping an image --read-only set device readonly when mapping image --allow-shrink allow shrinking of an image when resizing + + Supported image features: + layering (+), striping (+), exclusive-lock (*), object-map (*) + + (*) supports enabling/disabling on existing images + (+) enabled by default for new images if features are not specified