From 34413df326449ba2d114856405aaf71a9106cbe6 Mon Sep 17 00:00:00 2001 From: Mykola Golub Date: Thu, 18 Feb 2021 12:41:53 +0000 Subject: [PATCH] cls/rbd: add method to unlink image snapshot from group snapshot When no image snapshots are left the group snapshot will be automatically removed. Signed-off-by: Mykola Golub Signed-off-by: Prasanna Kumar Kalever --- src/cls/rbd/cls_rbd.cc | 64 ++++++++++++++++++++++++++++++++ src/cls/rbd/cls_rbd_client.cc | 18 +++++++++ src/cls/rbd/cls_rbd_client.h | 6 +++ src/cls/rbd/cls_rbd_types.h | 15 ++++++++ src/test/cls_rbd/test_cls_rbd.cc | 47 +++++++++++++++++++++++ 5 files changed, 150 insertions(+) diff --git a/src/cls/rbd/cls_rbd.cc b/src/cls/rbd/cls_rbd.cc index ff5638f8fe5ca..bb11907bf8e32 100644 --- a/src/cls/rbd/cls_rbd.cc +++ b/src/cls/rbd/cls_rbd.cc @@ -8763,6 +8763,66 @@ int group_snap_remove(cls_method_context_t hctx, return 0; } +/** + * Unlink image snapshot from group snapshot. + * + * Input: + * @param id Snapshot id + * @param image_snap ImageSnapshotSpec + * + * Output: + * @return 0 on success, negative error code on failure + */ +int group_snap_unlink(cls_method_context_t hctx, + bufferlist *in, bufferlist *out) +{ + CLS_LOG(20, "group_snap_unlink"); + std::string group_snap_id; + cls::rbd::ImageSnapshotSpec image_snap; + try { + auto iter = in->cbegin(); + decode(group_snap_id, iter); + decode(image_snap, iter); + } catch (const ceph::buffer::error &err) { + return -EINVAL; + } + + std::string group_snap_key = group::snap_key(group_snap_id); + bufferlist bl; + int r = cls_cxx_map_get_val(hctx, group_snap_key, &bl); + if (r < 0) { + return r; + } + cls::rbd::GroupSnapshot group_snap; + auto iter = bl.cbegin(); + try { + decode(group_snap, iter); + } catch (const ceph::buffer::error &err) { + CLS_ERR("error decoding snapshot: %s", group_snap_id.c_str()); + return -EIO; + } + if (group_snap.state != cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) { + CLS_LOG(20, "snap %s not complete", group_snap_id.c_str()); + return -ENOENT; + } + + auto &snaps = group_snap.snaps; + snaps.erase(std::remove(snaps.begin(), snaps.end(), image_snap), snaps.end()); + + if (snaps.empty()) { + CLS_LOG(20, "group_snap_unlink: removing snapshot with key %s", + group_snap_key.c_str()); + r = cls_cxx_map_remove_key(hctx, group_snap_key); + } else { + CLS_LOG(20, "group_snap_unlink: updating snapshot with key %s", + group_snap_key.c_str()); + bl.clear(); + encode(group_snap, bl); + r = cls_cxx_map_set_val(hctx, group_snap_key, &bl); + } + return r; +} + /** * Get group's snapshot by id. * @@ -9537,6 +9597,7 @@ CLS_INIT(rbd) cls_method_handle_t h_image_group_get; cls_method_handle_t h_group_snap_set; cls_method_handle_t h_group_snap_remove; + cls_method_handle_t h_group_snap_unlink; cls_method_handle_t h_group_snap_get_by_id; cls_method_handle_t h_group_snap_list; cls_method_handle_t h_group_snap_list_order; @@ -9962,6 +10023,9 @@ CLS_INIT(rbd) cls_register_cxx_method(h_class, "group_snap_remove", CLS_METHOD_RD | CLS_METHOD_WR, group_snap_remove, &h_group_snap_remove); + cls_register_cxx_method(h_class, "group_snap_unlink", + CLS_METHOD_RD | CLS_METHOD_WR, + group_snap_unlink, &h_group_snap_unlink); cls_register_cxx_method(h_class, "group_snap_get_by_id", CLS_METHOD_RD, group_snap_get_by_id, &h_group_snap_get_by_id); diff --git a/src/cls/rbd/cls_rbd_client.cc b/src/cls/rbd/cls_rbd_client.cc index e7f7bb6d27236..57b2528447295 100644 --- a/src/cls/rbd/cls_rbd_client.cc +++ b/src/cls/rbd/cls_rbd_client.cc @@ -3217,6 +3217,24 @@ int group_snap_remove(librados::IoCtx *ioctx, const std::string &oid, return ioctx->operate(oid, &op); } +void group_snap_unlink(librados::ObjectWriteOperation *op, + const std::string &group_snap_id, + const cls::rbd::ImageSnapshotSpec &image_snap) { + bufferlist bl; + encode(group_snap_id, bl); + encode(image_snap, bl); + op->exec("rbd", "group_snap_unlink", bl); +} + +int group_snap_unlink(librados::IoCtx *ioctx, const std::string &oid, + const std::string &group_snap_id, + const cls::rbd::ImageSnapshotSpec &image_snap) { + librados::ObjectWriteOperation op; + group_snap_unlink(&op, group_snap_id, image_snap); + + return ioctx->operate(oid, &op); +} + int group_snap_get_by_id(librados::IoCtx *ioctx, const std::string &oid, const std::string &snap_id, cls::rbd::GroupSnapshot *snapshot) { diff --git a/src/cls/rbd/cls_rbd_client.h b/src/cls/rbd/cls_rbd_client.h index 24590b43fcf51..ebe59cd364c7f 100644 --- a/src/cls/rbd/cls_rbd_client.h +++ b/src/cls/rbd/cls_rbd_client.h @@ -689,6 +689,12 @@ int group_snap_set(librados::IoCtx *ioctx, const std::string &oid, const cls::rbd::GroupSnapshot &snapshot); int group_snap_remove(librados::IoCtx *ioctx, const std::string &oid, const std::string &snap_id); +void group_snap_unlink(librados::ObjectWriteOperation *op, + const std::string &group_snap_id, + const cls::rbd::ImageSnapshotSpec &image_snap); +int group_snap_unlink(librados::IoCtx *ioctx, const std::string &oid, + const std::string &group_snap_id, + const cls::rbd::ImageSnapshotSpec &image_snap); int group_snap_get_by_id(librados::IoCtx *ioctx, const std::string &oid, const std::string &snap_id, cls::rbd::GroupSnapshot *snapshot); diff --git a/src/cls/rbd/cls_rbd_types.h b/src/cls/rbd/cls_rbd_types.h index 723a6fa0419ad..df112412cc6d1 100644 --- a/src/cls/rbd/cls_rbd_types.h +++ b/src/cls/rbd/cls_rbd_types.h @@ -1116,6 +1116,21 @@ struct ImageSnapshotSpec { void dump(ceph::Formatter *f) const; + inline bool operator==(const ImageSnapshotSpec& rhs) const { + return pool == rhs.pool && + image_id == rhs.image_id && + snap_id == rhs.snap_id; + } + inline bool operator<(const ImageSnapshotSpec& rhs) const { + if (pool != rhs.pool) { + return pool < rhs.pool; + } + if (image_id != rhs.image_id) { + return image_id < rhs.image_id; + } + return snap_id < rhs.snap_id; + } + static void generate_test_instances(std::list &o); }; WRITE_CLASS_ENCODER(ImageSnapshotSpec); diff --git a/src/test/cls_rbd/test_cls_rbd.cc b/src/test/cls_rbd/test_cls_rbd.cc index 7012bd76f6225..44b543a41110d 100644 --- a/src/test/cls_rbd/test_cls_rbd.cc +++ b/src/test/cls_rbd/test_cls_rbd.cc @@ -3335,6 +3335,53 @@ TEST_F(TestClsRbd, group_snap_remove_without_order) { ASSERT_EQ("snap_max_order", *keys.begin()); } +TEST_F(TestClsRbd, group_snap_unlink) { + librados::IoCtx ioctx; + ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx)); + + string image_id = "image_id_snap_unlink"; + + string group_id = "group_id_snap_unlink"; + ASSERT_EQ(0, ioctx.create(group_id, true)); + + string snap_id = "snap_id"; + cls::rbd::GroupSnapshot snap = {snap_id, + cls::rbd::UserGroupSnapshotNamespace{}, + "test_snapshot", + cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE}; + ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap)); + ASSERT_EQ(-ENOENT, group_snap_unlink(&ioctx, group_id, snap_id, {})); + + cls::rbd::GroupSnapshot read_snap; + ASSERT_EQ(0, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap)); + ASSERT_EQ(read_snap, snap); + + snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE; + ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap)); + ASSERT_EQ(0, group_snap_unlink(&ioctx, group_id, snap_id, {})); + ASSERT_EQ(-ENOENT, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap)); + + cls::rbd::ImageSnapshotSpec image_snap1 = {1, "image_id1", 1}; + cls::rbd::ImageSnapshotSpec image_snap2 = {1, "image_id2", 2}; + snap.snaps = {image_snap1, image_snap2}; + ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap)); + + ASSERT_EQ(0, group_snap_unlink(&ioctx, group_id, snap_id, {})); + ASSERT_EQ(0, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap)); + ASSERT_EQ(read_snap, snap); + + ASSERT_EQ(0, group_snap_unlink(&ioctx, group_id, snap_id, image_snap1)); + ASSERT_EQ(0, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap)); + ASSERT_EQ(read_snap.snaps, std::vector{image_snap2}); + + ASSERT_EQ(0, group_snap_unlink(&ioctx, group_id, snap_id, image_snap1)); + ASSERT_EQ(0, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap)); + ASSERT_EQ(read_snap.snaps, std::vector{image_snap2}); + + ASSERT_EQ(0, group_snap_unlink(&ioctx, group_id, snap_id, image_snap2)); + ASSERT_EQ(-ENOENT, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap)); +} + TEST_F(TestClsRbd, group_snap_get_by_id) { librados::IoCtx ioctx; -- 2.39.5