]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
cls_rbd: Add support for image flags
authorJason Dillaman <dillaman@redhat.com>
Thu, 6 Nov 2014 14:59:57 +0000 (09:59 -0500)
committerJason Dillaman <dillaman@redhat.com>
Thu, 29 Jan 2015 02:12:52 +0000 (21:12 -0500)
Image flags are an optional addition to the RBD image header
which can be used to preserve state.  The flags support
snapshot history.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/cls/rbd/cls_rbd.cc
src/cls/rbd/cls_rbd.h
src/cls/rbd/cls_rbd_client.cc
src/cls/rbd/cls_rbd_client.h
src/test/cls_rbd/test_cls_rbd.cc

index 50323e273f4c81ef8c127dfd468d5a5b9b230caa..fdd6bba2d4e09a2d8e8f485c11c43e77c49355de 100644 (file)
@@ -72,6 +72,8 @@ cls_method_handle_t h_get_protection_status;
 cls_method_handle_t h_set_protection_status;
 cls_method_handle_t h_get_stripe_unit_count;
 cls_method_handle_t h_set_stripe_unit_count;
+cls_method_handle_t h_get_flags;
+cls_method_handle_t h_set_flags;
 cls_method_handle_t h_remove_parent;
 cls_method_handle_t h_add_child;
 cls_method_handle_t h_remove_child;
@@ -715,6 +717,98 @@ int set_stripe_unit_count(cls_method_context_t hctx, bufferlist *in, bufferlist
   return 0;
 }
 
+/**
+ * get the image flags
+ *
+ * Input:
+ * @param snap_id which snapshot to query, to CEPH_NOSNAP (uint64_t)
+ *
+ * Output:
+ * @param flags image flags
+ *
+ * @returns 0 on success, negative error code upon failure
+ */
+int get_flags(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+  uint64_t snap_id;
+  bufferlist::iterator iter = in->begin();
+  try {
+    ::decode(snap_id, iter);
+  } catch (const buffer::error &err) {
+    return -EINVAL;
+  }
+
+  CLS_LOG(20, "get_flags snap_id=%llu", (unsigned long long)snap_id);
+
+  uint64_t flags = 0;
+  if (snap_id == CEPH_NOSNAP) {
+    int r = read_key(hctx, "flags", &flags);
+    if (r < 0 && r != -ENOENT) {
+      CLS_ERR("failed to read flags off disk: %s", cpp_strerror(r).c_str());
+      return r;
+    }
+  } else {
+    cls_rbd_snap snap;
+    string snapshot_key;
+    key_from_snap_id(snap_id, &snapshot_key);
+    int r = read_key(hctx, snapshot_key, &snap);
+    if (r < 0) {
+      return r;
+    }
+    flags = snap.flags;
+  }
+
+  ::encode(flags, *out);
+  return 0;
+}
+
+/**
+ * set the image flags
+ *
+ * Input:
+ * @params flags image flags
+ * @params mask image flag mask
+ *
+ * Output:
+ * none
+ *
+ * @returns 0 on success, negative error code upon failure
+ */
+int set_flags(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+  uint64_t flags;
+  uint64_t mask;
+  bufferlist::iterator iter = in->begin();
+  try {
+    ::decode(flags, iter);
+    ::decode(mask, iter);
+  } catch (const buffer::error &err) {
+    return -EINVAL;
+  }
+
+  // check that size exists to make sure this is a header object
+  // that was created correctly
+  uint64_t orig_flags = 0;
+  int r = read_key(hctx, "flags", &orig_flags);
+  if (r < 0 && r != -ENOENT) {
+    CLS_ERR("Could not read image's flags off disk: %s",
+            cpp_strerror(r).c_str());
+    return r;
+  }
+
+  flags = (orig_flags & ~mask) | (flags & mask);
+  CLS_LOG(20, "set_flags flags=%llu orig_flags=%llu", (unsigned long long)flags,
+          (unsigned long long)orig_flags);
+
+  bufferlist flagsbl;
+  ::encode(flags, flagsbl);
+  r = cls_cxx_map_set_val(hctx, "flags", &flagsbl);
+  if (r < 0) {
+    CLS_ERR("error updating flags: %d", r);
+    return r;
+  }
+  return 0;
+}
 
 /**
  * get the current parent, if any
@@ -1251,6 +1345,11 @@ int snapshot_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
     CLS_ERR("Could not read image's features off disk: %s", cpp_strerror(r).c_str());
     return r;
   }
+  r = read_key(hctx, "flags", &snap_meta.flags);
+  if (r < 0 && r != -ENOENT) {
+    CLS_ERR("Could not read image's flags off disk: %s", cpp_strerror(r).c_str());
+    return r;
+  }
 
   int max_read = RBD_MAX_KEYS_READ;
   string last_read = RBD_SNAP_KEY_PREFIX;
@@ -2234,6 +2333,12 @@ void __cls_init()
   cls_register_cxx_method(h_class, "set_stripe_unit_count",
                          CLS_METHOD_RD | CLS_METHOD_WR,
                          set_stripe_unit_count, &h_set_stripe_unit_count);
+  cls_register_cxx_method(h_class, "get_flags",
+                          CLS_METHOD_RD,
+                          get_flags, &h_get_flags);
+  cls_register_cxx_method(h_class, "set_flags",
+                          CLS_METHOD_RD | CLS_METHOD_WR,
+                          set_flags, &h_set_flags);
 
   /* methods for the rbd_children object */
   cls_register_cxx_method(h_class, "add_child",
index b0f6e1502ffbf3c01c9e4d8b070b1c8e00e502c1..5f79d5a83656969cf4d3058a087753af7299e9f1 100644 (file)
@@ -63,6 +63,7 @@ struct cls_rbd_snap {
   uint64_t features;
   uint8_t protection_status;
   cls_rbd_parent parent;
+  uint64_t flags;
 
   /// true if we have a parent
   bool has_parent() const {
@@ -70,20 +71,22 @@ struct cls_rbd_snap {
   }
 
   cls_rbd_snap() : id(CEPH_NOSNAP), image_size(0), features(0),
-                  protection_status(RBD_PROTECTION_STATUS_UNPROTECTED)
+                  protection_status(RBD_PROTECTION_STATUS_UNPROTECTED),
+                   flags(0)
     {}
   void encode(bufferlist& bl) const {
-    ENCODE_START(3, 1, bl);
+    ENCODE_START(4, 1, bl);
     ::encode(id, bl);
     ::encode(name, bl);
     ::encode(image_size, bl);
     ::encode(features, bl);
     ::encode(parent, bl);
     ::encode(protection_status, bl);
+    ::encode(flags, bl);
     ENCODE_FINISH(bl);
   }
   void decode(bufferlist::iterator& p) {
-    DECODE_START(3, p);
+    DECODE_START(4, p);
     ::decode(id, p);
     ::decode(name, p);
     ::decode(image_size, p);
@@ -94,6 +97,9 @@ struct cls_rbd_snap {
     if (struct_v >= 3) {
       ::decode(protection_status, p);
     }
+    if (struct_v >= 4) {
+      ::decode(flags, p);
+    }
     DECODE_FINISH(p);
   }
   void dump(Formatter *f) const {
@@ -127,6 +133,7 @@ struct cls_rbd_snap {
     t->name = "snap";
     t->image_size = 123456;
     t->features = 123;
+    t->flags = 31;
     o.push_back(t);
     t = new cls_rbd_snap;
     t->id = 2;
@@ -138,6 +145,7 @@ struct cls_rbd_snap {
     t->parent.snapid = 456;
     t->parent.overlap = 12345;
     t->protection_status = RBD_PROTECTION_STATUS_PROTECTED;
+    t->flags = 14;
     o.push_back(t);
   }
 };
index aa91178fbf47161d16f0df2baaa791fa0ad9162d..7b144ffe7ea75815077b211bdcc6946dd2df8435 100644 (file)
@@ -244,6 +244,38 @@ namespace librbd {
       return ioctx->exec(oid, "rbd", "set_parent", inbl, outbl);
     }
 
+    int get_flags(librados::IoCtx *ioctx, const std::string &oid,
+                  snapid_t snap_id, uint64_t *flags)
+    {
+      bufferlist inbl;
+      ::encode(snap_id, inbl);
+
+      bufferlist outbl;
+      int r = ioctx->exec(oid, "rbd", "get_flags", inbl, outbl);
+      if (r < 0) {
+        return r;
+      }
+
+      try {
+        bufferlist::iterator iter = outbl.begin();
+        ::decode(*flags, iter);
+      } catch (const buffer::error &err) {
+        return -EBADMSG;
+      }
+      return 0;
+    }
+
+    int set_flags(librados::IoCtx *ioctx, const std::string &oid,
+                  uint64_t flags, uint64_t mask)
+    {
+      bufferlist inbl;
+      ::encode(flags, inbl);
+      ::encode(mask, inbl);
+
+      bufferlist outbl;
+      return ioctx->exec(oid, "rbd", "set_flags", inbl, outbl);
+    }
+
     int remove_parent(librados::IoCtx *ioctx, const std::string &oid)
     {
       librados::ObjectWriteOperation op;
index 131b03099469b661d32c8a1efe849d3d7d04df95..d78175fb67cf8930412556f66f50563e9a93e1be 100644 (file)
@@ -47,6 +47,10 @@ namespace librbd {
                   uint64_t *parent_overlap);
     int set_parent(librados::IoCtx *ioctx, const std::string &oid,
                   parent_spec pspec, uint64_t parent_overlap);
+    int get_flags(librados::IoCtx *ioctx, const std::string &oid,
+                  snapid_t snap_id, uint64_t *flags);
+    int set_flags(librados::IoCtx *ioctx, const std::string &oid,
+                  uint64_t flags, uint64_t mask);
     int remove_parent(librados::IoCtx *ioctx, const std::string &oid);
     void remove_parent(librados::ObjectWriteOperation *op);
     int add_child(librados::IoCtx *ioctx, const std::string &oid,
index 663c9332bc2fbfd6a5a311319507cfbb4f284318..e5f52c21ca39d126a3a6f6e51550fcd65dfffe4b 100644 (file)
@@ -52,6 +52,8 @@ using ::librbd::cls_client::get_mutable_metadata;
 using ::librbd::cls_client::object_map_load;
 using ::librbd::cls_client::object_map_resize;
 using ::librbd::cls_client::object_map_update;
+using ::librbd::cls_client::get_flags;
+using ::librbd::cls_client::set_flags;
 
 static char *random_buf(size_t len)
 {
@@ -1021,3 +1023,33 @@ TEST_F(TestClsRbd, object_map_load_enoent)
 
   ioctx.close();
 }
+
+TEST_F(TestClsRbd, flags)
+{
+  librados::IoCtx ioctx;
+  ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+  string oid = get_temp_image_name();
+  ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid));
+
+  uint64_t flags;
+  ASSERT_EQ(0, get_flags(&ioctx, oid, CEPH_NOSNAP, &flags));
+  ASSERT_EQ(0U, flags);
+
+  ASSERT_EQ(0, set_flags(&ioctx, oid, 3, 2));
+  ASSERT_EQ(0, get_flags(&ioctx, oid, CEPH_NOSNAP, &flags));
+  ASSERT_EQ(2U, flags);
+
+  uint64_t snap_id = 10;
+  ASSERT_EQ(-ENOENT, get_flags(&ioctx, oid, snap_id, &flags));
+  ASSERT_EQ(0, snapshot_add(&ioctx, oid, snap_id, "snap"));
+
+  ASSERT_EQ(0, set_flags(&ioctx, oid, 31, 4));
+  ASSERT_EQ(0, get_flags(&ioctx, oid, CEPH_NOSNAP, &flags));
+  ASSERT_EQ(6U, flags);
+
+  ASSERT_EQ(0, get_flags(&ioctx, oid, snap_id, &flags));
+  ASSERT_EQ(2U, flags);
+
+  ioctx.close();
+}