]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: add feature enable/disable support
authorJason Dillaman <dillaman@redhat.com>
Thu, 12 Mar 2015 16:10:32 +0000 (12:10 -0400)
committerJason Dillaman <dillaman@redhat.com>
Mon, 6 Apr 2015 17:14:35 +0000 (13:14 -0400)
Mutable image features can now be enabled/disabled via
the rbd CLI.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
man/8/rbd.rst
src/rbd.cc
src/test/cli/rbd/help.t

index c33593e95d604285ae98f2378b9d31535f50ac17..9e9aea0e4837ae9fdb92b03a1a00af727753dfa9 100644 (file)
@@ -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.
index 3d86a92be6a0f427406c79e2d0713c50e9918856..50a044aa18388878e59beb3f008a3dc5a746c00e 100644 (file)
@@ -76,6 +76,13 @@ map<string, string> map_options; // -o / --options map
 
 #define dout_subsys ceph_subsys_rbd
 
+static std::map<uint64_t, std::string> 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 <image-name> <feature>      disable the specified image feature\n"
+"  feature enable <image-name> <feature>       enable the specified image feature\n"
 "  lock list <image-name>                      show locks held on an image\n"
 "  lock add <image-name> <id> [--shared <tag>] take a lock called id on an image\n"
 "  lock remove <image-name> <id> <locker>      release a lock on an image\n"
@@ -158,9 +167,8 @@ void usage()
 "  --image-format <format-number>     format to use when creating an image\n"
 "                                     format 1 is the original format (default)\n"
 "                                     format 2 supports cloning\n"
-"  --image-features <features>        optional format 2 features to enable\n"
-"                                     +1 layering support, +2 striping v2,\n"
-"                                     +4 exclusive lock, +8 object map\n"
+"  --image-feature <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>      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 <map-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<uint64_t, std::string>::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<uint64_t, std::string> 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<uint64_t, std::string>::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<const char*> 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;
 }
index 541ba9abea208930ef7852c5036d2a03d41f97eb..679a89756e3fca49a9f474922d12def0e540d0ce 100644 (file)
@@ -53,6 +53,8 @@
                                                 mapped by the kernel
     showmapped                                  show the rbd images mapped
                                                 by the kernel
+    feature disable <image-name> <feature>      disable the specified image feature
+    feature enable <image-name> <feature>       enable the specified image feature
     lock list <image-name>                      show locks held on an image
     lock add <image-name> <id> [--shared <tag>] take a lock called id on an image
     lock remove <image-name> <id> <locker>      release a lock on an image
@@ -78,9 +80,8 @@
     --image-format <format-number>     format to use when creating an image
                                        format 1 is the original format (default)
                                        format 2 supports cloning
-    --image-features <features>        optional format 2 features to enable
-                                       +1 layering support, +2 striping v2,
-                                       +4 exclusive lock, +8 object map
+    --image-feature <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>      size (in bytes) of a block of data
@@ -95,3 +96,9 @@
     -o, --options <map-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