From: Jason Dillaman Date: Thu, 6 Nov 2014 14:59:57 +0000 (-0500) Subject: cls_rbd: Add support for image flags X-Git-Tag: v0.93~143^2~8 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=8571e4764c901fb04daeac59ca2d121b6c18f441;p=ceph.git cls_rbd: Add support for image flags 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 --- diff --git a/src/cls/rbd/cls_rbd.cc b/src/cls/rbd/cls_rbd.cc index 50323e273f4c..fdd6bba2d4e0 100644 --- a/src/cls/rbd/cls_rbd.cc +++ b/src/cls/rbd/cls_rbd.cc @@ -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", diff --git a/src/cls/rbd/cls_rbd.h b/src/cls/rbd/cls_rbd.h index b0f6e1502ffb..5f79d5a83656 100644 --- a/src/cls/rbd/cls_rbd.h +++ b/src/cls/rbd/cls_rbd.h @@ -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); } }; diff --git a/src/cls/rbd/cls_rbd_client.cc b/src/cls/rbd/cls_rbd_client.cc index aa91178fbf47..7b144ffe7ea7 100644 --- a/src/cls/rbd/cls_rbd_client.cc +++ b/src/cls/rbd/cls_rbd_client.cc @@ -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; diff --git a/src/cls/rbd/cls_rbd_client.h b/src/cls/rbd/cls_rbd_client.h index 131b03099469..d78175fb67cf 100644 --- a/src/cls/rbd/cls_rbd_client.h +++ b/src/cls/rbd/cls_rbd_client.h @@ -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, diff --git a/src/test/cls_rbd/test_cls_rbd.cc b/src/test/cls_rbd/test_cls_rbd.cc index 663c9332bc2f..e5f52c21ca39 100644 --- a/src/test/cls_rbd/test_cls_rbd.cc +++ b/src/test/cls_rbd/test_cls_rbd.cc @@ -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(); +}