From: Victor Denisov Date: Wed, 21 Sep 2016 04:30:56 +0000 (-0700) Subject: cls_rbd: Add snapshot namespaces data structures X-Git-Tag: v11.1.0~532^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=ca31b7a744034f1abfe80f18af9d8fbf2a373f1d;p=ceph.git cls_rbd: Add snapshot namespaces data structures Signed-off-by: Victor Denisov --- diff --git a/src/cls/rbd/cls_rbd.cc b/src/cls/rbd/cls_rbd.cc index 316165fd3717..9cff72f885cb 100644 --- a/src/cls/rbd/cls_rbd.cc +++ b/src/cls/rbd/cls_rbd.cc @@ -86,6 +86,7 @@ cls_method_handle_t h_get_snapcontext; cls_method_handle_t h_get_object_prefix; cls_method_handle_t h_get_data_pool; cls_method_handle_t h_get_snapshot_name; +cls_method_handle_t h_get_snapshot_namespace; cls_method_handle_t h_snapshot_add; cls_method_handle_t h_snapshot_remove; cls_method_handle_t h_snapshot_rename; @@ -1537,12 +1538,53 @@ int get_snapshot_name(cls_method_context_t hctx, bufferlist *in, bufferlist *out return 0; } +/** + * Retrieve namespace of a snapshot. + * + * Input: + * @param snap_id id of the snapshot (uint64_t) + * + * Output: + * @param SnapshotNamespace + * @returns 0 on success, negative error code on failure. + */ +int get_snapshot_namespace(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_snapshot_namespace snap_id=%" PRIu64, snap_id); + + if (snap_id == CEPH_NOSNAP) { + return -EINVAL; + } + + 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; + } + + ::encode(snap.snapshot_namespace, *out); + + return 0; +} + /** * Adds a snapshot to an rbd header. Ensures the id and name are unique. * * Input: * @param snap_name name of the snapshot (string) * @param snap_id id of the snapshot (uint64_t) + * @param snap_namespace namespace of the snapshot (cls::rbd::SnapshotNamespaceOnDisk) * * Output: * @returns 0 on success, negative error code on failure. @@ -1559,6 +1601,9 @@ int snapshot_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out) bufferlist::iterator iter = in->begin(); ::decode(snap_meta.name, iter); ::decode(snap_meta.id, iter); + if (!iter.end()) { + ::decode(snap_meta.snapshot_namespace, iter); + } } catch (const buffer::error &err) { return -EINVAL; } @@ -4781,6 +4826,9 @@ void __cls_init() cls_register_cxx_method(h_class, "get_snapshot_name", CLS_METHOD_RD, get_snapshot_name, &h_get_snapshot_name); + cls_register_cxx_method(h_class, "get_snapshot_namespace", + CLS_METHOD_RD, + get_snapshot_namespace, &h_get_snapshot_namespace); cls_register_cxx_method(h_class, "snapshot_add", CLS_METHOD_RD | CLS_METHOD_WR, snapshot_add, &h_snapshot_add); diff --git a/src/cls/rbd/cls_rbd.h b/src/cls/rbd/cls_rbd.h index 710b54213ff8..c8bd6dab6d72 100644 --- a/src/cls/rbd/cls_rbd.h +++ b/src/cls/rbd/cls_rbd.h @@ -7,6 +7,7 @@ #include "include/buffer_fwd.h" #include "common/Formatter.h" #include "librbd/parent_types.h" +#include "cls/rbd/cls_rbd_types.h" /// information about our parent image, if any struct cls_rbd_parent { @@ -64,6 +65,7 @@ struct cls_rbd_snap { uint8_t protection_status; cls_rbd_parent parent; uint64_t flags; + cls::rbd::SnapshotNamespaceOnDisk snapshot_namespace; /// true if we have a parent bool has_parent() const { @@ -75,7 +77,7 @@ struct cls_rbd_snap { flags(0) {} void encode(bufferlist& bl) const { - ENCODE_START(4, 1, bl); + ENCODE_START(5, 1, bl); ::encode(id, bl); ::encode(name, bl); ::encode(image_size, bl); @@ -83,10 +85,11 @@ struct cls_rbd_snap { ::encode(parent, bl); ::encode(protection_status, bl); ::encode(flags, bl); + ::encode(snapshot_namespace, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& p) { - DECODE_START(4, p); + DECODE_START(5, p); ::decode(id, p); ::decode(name, p); ::decode(image_size, p); @@ -100,6 +103,11 @@ struct cls_rbd_snap { if (struct_v >= 4) { ::decode(flags, p); } + if (struct_v >= 5) { + ::decode(snapshot_namespace, p); + } else { + snapshot_namespace = cls::rbd::SnapshotNamespaceOnDisk(cls::rbd::UserSnapshotNamespace()); + } DECODE_FINISH(p); } void dump(Formatter *f) const { diff --git a/src/cls/rbd/cls_rbd_client.cc b/src/cls/rbd/cls_rbd_client.cc index f9835701ffa9..44d3572f693f 100644 --- a/src/cls/rbd/cls_rbd_client.cc +++ b/src/cls/rbd/cls_rbd_client.cc @@ -481,11 +481,12 @@ namespace librbd { } void snapshot_add(librados::ObjectWriteOperation *op, snapid_t snap_id, - const std::string &snap_name) + const std::string &snap_name, const cls::rbd::SnapshotNamespace &snap_namespace) { bufferlist bl; ::encode(snap_name, bl); ::encode(snap_id, bl); + ::encode(cls::rbd::SnapshotNamespaceOnDisk(snap_namespace), bl); op->exec("rbd", "snapshot_add", bl); } @@ -550,7 +551,8 @@ namespace librbd { std::vector *names, std::vector *sizes, std::vector *parents, - std::vector *protection_statuses) { + std::vector *protection_statuses) + { names->resize(ids.size()); sizes->resize(ids.size()); parents->resize(ids.size()); @@ -598,6 +600,52 @@ namespace librbd { protection_statuses); } + void snap_namespace_list_start(librados::ObjectReadOperation *op, + const std::vector &ids) + { + for (vector::const_iterator it = ids.begin(); + it != ids.end(); ++it) { + snapid_t snap_id = it->val; + bufferlist bl; + ::encode(snap_id, bl); + op->exec("rbd", "get_snapshot_namespace", bl); + } + } + + int snap_namespace_list_finish(bufferlist::iterator *it, + const std::vector &ids, + std::vector *namespaces) + { + namespaces->resize(ids.size()); + try { + for (size_t i = 0; i < namespaces->size(); ++i) { + cls::rbd::SnapshotNamespaceOnDisk e; + ::decode(e, *it); + (*namespaces)[i] = e.snapshot_namespace; + } + } catch (const buffer::error &err) { + return -EBADMSG; + } + return 0; + } + + int snap_namespace_list(librados::IoCtx *ioctx, const std::string &oid, + const std::vector &ids, + std::vector *namespaces) + { + librados::ObjectReadOperation op; + snap_namespace_list_start(&op, ids); + + bufferlist out_bl; + int r = ioctx->operate(oid, &op, &out_bl); + if (r < 0) { + return r; + } + + bufferlist::iterator it = out_bl.begin(); + return snap_namespace_list_finish(&it, ids, namespaces); + } + void old_snapshot_add(librados::ObjectWriteOperation *op, snapid_t snap_id, const std::string &snap_name) { diff --git a/src/cls/rbd/cls_rbd_client.h b/src/cls/rbd/cls_rbd_client.h index 5c5ba3f4c599..d16033d19356 100644 --- a/src/cls/rbd/cls_rbd_client.h +++ b/src/cls/rbd/cls_rbd_client.h @@ -104,7 +104,8 @@ namespace librbd { int get_children(librados::IoCtx *ioctx, const std::string &oid, parent_spec pspec, set& children); void snapshot_add(librados::ObjectWriteOperation *op, snapid_t snap_id, - const std::string &snap_name); + const std::string &snap_name, + const cls::rbd::SnapshotNamespace &snap_namespace); void snapshot_remove(librados::ObjectWriteOperation *op, snapid_t snap_id); void snapshot_rename(librados::ObjectWriteOperation *op, snapid_t src_snap_id, @@ -127,6 +128,15 @@ namespace librbd { std::vector *parents, std::vector *protection_statuses); + void snap_namespace_list_start(librados::ObjectReadOperation *op, + const std::vector &ids); + int snap_namespace_list_finish(bufferlist::iterator *it, + const std::vector &ids, + std::vector *namespaces); + int snap_namespace_list(librados::IoCtx *ioctx, const std::string &oid, + const std::vector &ids, + std::vector *namespaces); + int copyup(librados::IoCtx *ioctx, const std::string &oid, bufferlist data); int get_protection_status(librados::IoCtx *ioctx, const std::string &oid, diff --git a/src/cls/rbd/cls_rbd_types.cc b/src/cls/rbd/cls_rbd_types.cc index efbe47fd92ba..ace0abc15ac4 100644 --- a/src/cls/rbd/cls_rbd_types.cc +++ b/src/cls/rbd/cls_rbd_types.cc @@ -1,6 +1,7 @@ // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab +#include #include "cls/rbd/cls_rbd_types.h" #include "common/Formatter.h" @@ -316,5 +317,136 @@ bool GroupSpec::is_valid() const { return (!group_id.empty()) && (pool_id != -1); } +void GroupSnapshotNamespace::encode(bufferlist& bl) const { + ::encode(group_pool, bl); + ::encode(group_id, bl); + ::encode(snapshot_id, bl); +} + +void GroupSnapshotNamespace::decode(bufferlist::iterator& it) { + ::decode(group_pool, it); + ::decode(group_id, it); + ::decode(snapshot_id, it); +} + +void GroupSnapshotNamespace::dump(Formatter *f) const { + f->dump_int("group_pool", group_pool); + f->dump_string("group_id", group_id); + f->dump_int("snapshot_id", snapshot_id); +} + +class EncodeSnapshotNamespaceVisitor : public boost::static_visitor { +public: + explicit EncodeSnapshotNamespaceVisitor(bufferlist &bl) : m_bl(bl) { + } + + template + inline void operator()(const T& t) const { + ::encode(static_cast(T::SNAPSHOT_NAMESPACE_TYPE), m_bl); + t.encode(m_bl); + } + +private: + bufferlist &m_bl; +}; + +class DecodeSnapshotNamespaceVisitor : public boost::static_visitor { +public: + DecodeSnapshotNamespaceVisitor(bufferlist::iterator &iter) + : m_iter(iter) { + } + + template + inline void operator()(T& t) const { + t.decode(m_iter); + } +private: + bufferlist::iterator &m_iter; +}; + +class DumpSnapshotNamespaceVisitor : public boost::static_visitor { +public: + explicit DumpSnapshotNamespaceVisitor(Formatter *formatter, const std::string &key) + : m_formatter(formatter), m_key(key) {} + + template + inline void operator()(const T& t) const { + auto type = T::SNAPSHOT_NAMESPACE_TYPE; + m_formatter->dump_string(m_key.c_str(), stringify(type)); + t.dump(m_formatter); + } +private: + ceph::Formatter *m_formatter; + std::string m_key; +}; + +class GetTypeVisitor : public boost::static_visitor { +public: + template + inline SnapshotNamespaceType operator()(const T&) const { + return static_cast(T::SNAPSHOT_NAMESPACE_TYPE); + } +}; + + +SnapshotNamespaceType SnapshotNamespaceOnDisk::get_namespace_type() const { + return static_cast(boost::apply_visitor(GetTypeVisitor(), + snapshot_namespace)); +} + +void SnapshotNamespaceOnDisk::encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + boost::apply_visitor(EncodeSnapshotNamespaceVisitor(bl), snapshot_namespace); + ENCODE_FINISH(bl); +} + +void SnapshotNamespaceOnDisk::decode(bufferlist::iterator &p) +{ + DECODE_START(1, p); + uint32_t snap_type; + ::decode(snap_type, p); + switch (snap_type) { + case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_USER: + snapshot_namespace = UserSnapshotNamespace(); + break; + case cls::rbd::SNAPSHOT_NAMESPACE_TYPE_GROUP: + snapshot_namespace = GroupSnapshotNamespace(); + break; + default: + snapshot_namespace = UnknownSnapshotNamespace(); + break; + } + boost::apply_visitor(DecodeSnapshotNamespaceVisitor(p), snapshot_namespace); + DECODE_FINISH(p); +} + +void SnapshotNamespaceOnDisk::dump(Formatter *f) const { + boost::apply_visitor(DumpSnapshotNamespaceVisitor(f, "snapshot_namespace_type"), snapshot_namespace); +} + +void SnapshotNamespaceOnDisk::generate_test_instances(std::list &o) { + o.push_back(new SnapshotNamespaceOnDisk(UserSnapshotNamespace())); + o.push_back(new SnapshotNamespaceOnDisk(GroupSnapshotNamespace(0, "10152ae8944a", 1))); + o.push_back(new SnapshotNamespaceOnDisk(GroupSnapshotNamespace(5, "1018643c9869", 3))); +} + +std::ostream& operator<<(std::ostream& os, const UserSnapshotNamespace& ns) { + os << "[user]"; + return os; +} + +std::ostream& operator<<(std::ostream& os, const GroupSnapshotNamespace& ns) { + os << "[group" + << " group_pool=" << ns.group_pool + << " group_id=" << ns.group_id + << " snapshot_id=" << ns.snapshot_id << "]"; + return os; +} + +std::ostream& operator<<(std::ostream& os, const UnknownSnapshotNamespace& ns) { + os << "[unknown]"; + return os; +} + } // namespace rbd } // namespace cls diff --git a/src/cls/rbd/cls_rbd_types.h b/src/cls/rbd/cls_rbd_types.h index 547e99632505..d2a48a2d0c19 100644 --- a/src/cls/rbd/cls_rbd_types.h +++ b/src/cls/rbd/cls_rbd_types.h @@ -4,6 +4,7 @@ #ifndef CEPH_CLS_RBD_TYPES_H #define CEPH_CLS_RBD_TYPES_H +#include #include "include/int_types.h" #include "include/buffer.h" #include "include/encoding.h" @@ -217,6 +218,98 @@ struct GroupSpec { WRITE_CLASS_ENCODER(GroupSpec); +enum SnapshotNamespaceType { + SNAPSHOT_NAMESPACE_TYPE_USER = 0, + SNAPSHOT_NAMESPACE_TYPE_GROUP = 1 +}; + +struct UserSnapshotNamespace { + static const uint32_t SNAPSHOT_NAMESPACE_TYPE = SNAPSHOT_NAMESPACE_TYPE_USER; + + UserSnapshotNamespace() {} + + void encode(bufferlist& bl) const {} + void decode(bufferlist::iterator& it) {} + + void dump(Formatter *f) const {} + + inline bool operator==(const UserSnapshotNamespace& usn) const { + return true; + } + +}; + +std::ostream& operator<<(std::ostream& os, const UserSnapshotNamespace& ns); + +struct GroupSnapshotNamespace { + static const uint32_t SNAPSHOT_NAMESPACE_TYPE = SNAPSHOT_NAMESPACE_TYPE_GROUP; + + GroupSnapshotNamespace() {} + + GroupSnapshotNamespace(int64_t _group_pool, + const string &_group_id, + const snapid_t &_snapshot_id) :group_pool(_group_pool), + group_id(_group_id), + snapshot_id(_snapshot_id) {} + + int64_t group_pool; + string group_id; + snapid_t snapshot_id; + + void encode(bufferlist& bl) const; + void decode(bufferlist::iterator& it); + + void dump(Formatter *f) const; + + inline bool operator==(const GroupSnapshotNamespace& gsn) const { + return group_pool == gsn.group_pool && + group_id == gsn.group_id && + snapshot_id == gsn.snapshot_id; + } + +}; + +std::ostream& operator<<(std::ostream& os, const GroupSnapshotNamespace& ns); + +struct UnknownSnapshotNamespace { + static const uint32_t SNAPSHOT_NAMESPACE_TYPE = static_cast(-1); + + UnknownSnapshotNamespace() {} + + void encode(bufferlist& bl) const {} + void decode(bufferlist::iterator& it) {} + void dump(Formatter *f) const {} + inline bool operator==(const UnknownSnapshotNamespace& gsn) const { + return true; + } +}; + +std::ostream& operator<<(std::ostream& os, const UnknownSnapshotNamespace& ns); + +typedef boost::variant SnapshotNamespace; + + +struct SnapshotNamespaceOnDisk { + + SnapshotNamespaceOnDisk() : snapshot_namespace(UnknownSnapshotNamespace()) {} + SnapshotNamespaceOnDisk(const SnapshotNamespace &sn) : snapshot_namespace(sn) {} + + SnapshotNamespace snapshot_namespace; + + SnapshotNamespaceType get_namespace_type() const; + + void encode(bufferlist& bl) const; + void decode(bufferlist::iterator& it); + void dump(Formatter *f) const; + + static void generate_test_instances(std::list &o); + + inline bool operator==(const SnapshotNamespaceOnDisk& gsn) const { + return snapshot_namespace == gsn.snapshot_namespace; + } +}; +WRITE_CLASS_ENCODER(SnapshotNamespaceOnDisk); + } // namespace rbd } // namespace cls diff --git a/src/test/cls_rbd/test_cls_rbd.cc b/src/test/cls_rbd/test_cls_rbd.cc index 7de1c4298e49..1e0e3ceb9ea5 100644 --- a/src/test/cls_rbd/test_cls_rbd.cc +++ b/src/test/cls_rbd/test_cls_rbd.cc @@ -29,7 +29,7 @@ using ::librbd::parent_spec; static int snapshot_add(librados::IoCtx *ioctx, const std::string &oid, uint64_t snap_id, const std::string &snap_name) { librados::ObjectWriteOperation op; - ::librbd::cls_client::snapshot_add(&op, snap_id, snap_name); + ::librbd::cls_client::snapshot_add(&op, snap_id, snap_name, cls::rbd::UserSnapshotNamespace()); return ioctx->operate(oid, &op); } @@ -753,6 +753,7 @@ TEST_F(TestClsRbd, parents) TEST_F(TestClsRbd, snapshots) { + cls::rbd::SnapshotNamespace userSnapNamespace = cls::rbd::UserSnapshotNamespace(); librados::IoCtx ioctx; ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx)); @@ -762,6 +763,7 @@ TEST_F(TestClsRbd, snapshots) ASSERT_EQ(0, create_image(&ioctx, oid, 10, 22, 0, oid, -1)); vector snap_names; + vector snap_namespaces; vector snap_sizes; SnapContext snapc; vector parents; @@ -772,7 +774,9 @@ TEST_F(TestClsRbd, snapshots) ASSERT_EQ(0u, snapc.seq); ASSERT_EQ(0, snapshot_list(&ioctx, oid, snapc.snaps, &snap_names, &snap_sizes, &parents, &protection_status)); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); ASSERT_EQ(0u, snap_names.size()); + ASSERT_EQ(0u, snap_namespaces.size()); ASSERT_EQ(0u, snap_sizes.size()); ASSERT_EQ(0, snapshot_add(&ioctx, oid, 0, "snap1")); @@ -782,8 +786,11 @@ TEST_F(TestClsRbd, snapshots) ASSERT_EQ(0u, snapc.seq); ASSERT_EQ(0, snapshot_list(&ioctx, oid, snapc.snaps, &snap_names, &snap_sizes, &parents, &protection_status)); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); ASSERT_EQ(1u, snap_names.size()); ASSERT_EQ("snap1", snap_names[0]); + ASSERT_EQ(1u, snap_namespaces.size()); + ASSERT_EQ(userSnapNamespace, snap_namespaces[0]); ASSERT_EQ(10u, snap_sizes[0]); // snap with same id and name @@ -794,8 +801,11 @@ TEST_F(TestClsRbd, snapshots) ASSERT_EQ(0u, snapc.seq); ASSERT_EQ(0, snapshot_list(&ioctx, oid, snapc.snaps, &snap_names, &snap_sizes, &parents, &protection_status)); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); ASSERT_EQ(1u, snap_names.size()); ASSERT_EQ("snap1", snap_names[0]); + ASSERT_EQ(1u, snap_namespaces.size()); + ASSERT_EQ(userSnapNamespace, snap_namespaces[0]); ASSERT_EQ(10u, snap_sizes[0]); // snap with same id, different name @@ -806,8 +816,11 @@ TEST_F(TestClsRbd, snapshots) ASSERT_EQ(0u, snapc.seq); ASSERT_EQ(0, snapshot_list(&ioctx, oid, snapc.snaps, &snap_names, &snap_sizes, &parents, &protection_status)); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); ASSERT_EQ(1u, snap_names.size()); ASSERT_EQ("snap1", snap_names[0]); + ASSERT_EQ(1u, snap_namespaces.size()); + ASSERT_EQ(userSnapNamespace, snap_namespaces[0]); ASSERT_EQ(10u, snap_sizes[0]); // snap with different id, same name @@ -818,8 +831,11 @@ TEST_F(TestClsRbd, snapshots) ASSERT_EQ(0u, snapc.seq); ASSERT_EQ(0, snapshot_list(&ioctx, oid, snapc.snaps, &snap_names, &snap_sizes, &parents, &protection_status)); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); ASSERT_EQ(snap_names.size(), 1u); ASSERT_EQ(snap_names[0], "snap1"); + ASSERT_EQ(1u, snap_namespaces.size()); + ASSERT_EQ(userSnapNamespace, snap_namespaces[0]); ASSERT_EQ(snap_sizes[0], 10u); // snap with different id, different name @@ -831,19 +847,27 @@ TEST_F(TestClsRbd, snapshots) ASSERT_EQ(1u, snapc.seq); ASSERT_EQ(0, snapshot_list(&ioctx, oid, snapc.snaps, &snap_names, &snap_sizes, &parents, &protection_status)); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); ASSERT_EQ(2u, snap_names.size()); + ASSERT_EQ(2u, snap_namespaces.size()); ASSERT_EQ("snap2", snap_names[0]); + ASSERT_EQ(userSnapNamespace, snap_namespaces[0]); ASSERT_EQ(10u, snap_sizes[0]); ASSERT_EQ("snap1", snap_names[1]); + ASSERT_EQ(userSnapNamespace, snap_namespaces[1]); ASSERT_EQ(10u, snap_sizes[1]); ASSERT_EQ(0, snapshot_rename(&ioctx, oid, 0, "snap1-rename")); ASSERT_EQ(0, snapshot_list(&ioctx, oid, snapc.snaps, &snap_names, &snap_sizes, &parents, &protection_status)); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); ASSERT_EQ(2u, snap_names.size()); + ASSERT_EQ(2u, snap_namespaces.size()); ASSERT_EQ("snap2", snap_names[0]); + ASSERT_EQ(userSnapNamespace, snap_namespaces[0]); ASSERT_EQ(10u, snap_sizes[0]); ASSERT_EQ("snap1-rename", snap_names[1]); + ASSERT_EQ(userSnapNamespace, snap_namespaces[1]); ASSERT_EQ(10u, snap_sizes[1]); ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 0)); ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc)); @@ -852,8 +876,11 @@ TEST_F(TestClsRbd, snapshots) ASSERT_EQ(1u, snapc.seq); ASSERT_EQ(0, snapshot_list(&ioctx, oid, snapc.snaps, &snap_names, &snap_sizes, &parents, &protection_status)); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); ASSERT_EQ(1u, snap_names.size()); + ASSERT_EQ(1u, snap_namespaces.size()); ASSERT_EQ("snap2", snap_names[0]); + ASSERT_EQ(userSnapNamespace, snap_namespaces[0]); ASSERT_EQ(10u, snap_sizes[0]); uint64_t size; @@ -872,10 +899,14 @@ TEST_F(TestClsRbd, snapshots) ASSERT_EQ(large_snap_id, snapc.seq); ASSERT_EQ(0, snapshot_list(&ioctx, oid, snapc.snaps, &snap_names, &snap_sizes, &parents, &protection_status)); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); ASSERT_EQ(2u, snap_names.size()); + ASSERT_EQ(2u, snap_namespaces.size()); ASSERT_EQ("snap3", snap_names[0]); + ASSERT_EQ(userSnapNamespace, snap_namespaces[0]); ASSERT_EQ(0u, snap_sizes[0]); ASSERT_EQ("snap2", snap_names[1]); + ASSERT_EQ(userSnapNamespace, snap_namespaces[1]); ASSERT_EQ(10u, snap_sizes[1]); ASSERT_EQ(0, get_size(&ioctx, oid, large_snap_id, &size, &order)); @@ -893,8 +924,11 @@ TEST_F(TestClsRbd, snapshots) ASSERT_EQ(large_snap_id, snapc.seq); ASSERT_EQ(0, snapshot_list(&ioctx, oid, snapc.snaps, &snap_names, &snap_sizes, &parents, &protection_status)); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); ASSERT_EQ(1u, snap_names.size()); + ASSERT_EQ(1u, snap_namespaces.size()); ASSERT_EQ("snap2", snap_names[0]); + ASSERT_EQ(userSnapNamespace, snap_namespaces[0]); ASSERT_EQ(10u, snap_sizes[0]); ASSERT_EQ(-ENOENT, snapshot_remove(&ioctx, oid, large_snap_id)); @@ -904,12 +938,49 @@ TEST_F(TestClsRbd, snapshots) ASSERT_EQ(large_snap_id, snapc.seq); ASSERT_EQ(0, snapshot_list(&ioctx, oid, snapc.snaps, &snap_names, &snap_sizes, &parents, &protection_status)); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); ASSERT_EQ(0u, snap_names.size()); + ASSERT_EQ(0u, snap_namespaces.size()); ASSERT_EQ(0u, snap_sizes.size()); ioctx.close(); } +TEST_F(TestClsRbd, snapshots_namespaces) +{ + cls::rbd::SnapshotNamespace groupSnapNamespace = cls::rbd::GroupSnapshotNamespace(5, "1018643c9869", 3); + 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, 10, 22, 0, oid, -1)); + + vector snap_names; + vector snap_namespaces; + SnapContext snapc; + + ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc)); + ASSERT_EQ(0u, snapc.snaps.size()); + ASSERT_EQ(0u, snapc.seq); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); + ASSERT_EQ(0u, snap_namespaces.size()); + + ASSERT_EQ(0, snapshot_add(&ioctx, oid, 0, "snap1")); + + librados::ObjectWriteOperation op; + ::librbd::cls_client::snapshot_add(&op, 0, "snap1", groupSnapNamespace); + int r = ioctx.operate(oid, &op); + ASSERT_EQ(0, r); + + ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc)); + ASSERT_EQ(1u, snapc.snaps.size()); + ASSERT_EQ(0u, snapc.snaps[0]); + ASSERT_EQ(0u, snapc.seq); + ASSERT_EQ(0, snap_namespace_list(&ioctx, oid, snapc.snaps, &snap_namespaces)); + ASSERT_EQ(groupSnapNamespace, snap_namespaces[0]); +} + TEST_F(TestClsRbd, snapid_race) { librados::IoCtx ioctx;