]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
cls/rbd: add method to unlink image snapshot from group snapshot
authorMykola Golub <mgolub@suse.com>
Thu, 18 Feb 2021 12:41:53 +0000 (12:41 +0000)
committerIlya Dryomov <idryomov@gmail.com>
Sun, 28 Sep 2025 18:24:58 +0000 (20:24 +0200)
When no image snapshots are left the group snapshot will be
automatically removed.

Signed-off-by: Mykola Golub <mgolub@suse.com>
Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
src/cls/rbd/cls_rbd.cc
src/cls/rbd/cls_rbd_client.cc
src/cls/rbd/cls_rbd_client.h
src/cls/rbd/cls_rbd_types.h
src/test/cls_rbd/test_cls_rbd.cc

index 1513a62131df544722aaf93514f0d24463049523..165383ed422c26ccd83f9d420df30cadb3ea3d71 100644 (file)
@@ -8764,6 +8764,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.
  *
@@ -9538,6 +9598,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;
@@ -9963,6 +10024,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);
index 6612c868bc6a286304d9fe999e9122fa1eb1a968..e565c94e02d0a9d9f843c705a5462d783f7391e9 100644 (file)
@@ -3216,6 +3216,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) {
index 24590b43fcf516588da2d25ec050e8c9e89425c1..ebe59cd364c7fc5c18ee197bf48512c37abd8da9 100644 (file)
@@ -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);
index 723a6fa0419ad5fa0b99dd459aa6357de987a568..df112412cc6d1ae3384ec0f95d2d4918390100db 100644 (file)
@@ -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<ImageSnapshotSpec *> &o);
 };
 WRITE_CLASS_ENCODER(ImageSnapshotSpec);
index 853ae873bde57f4a98cbe85ec1873d789a41badb..331de059d3b6cc7b1eb3fdd5cc8a972e8c6f87d8 100644 (file)
@@ -3328,6 +3328,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<cls::rbd::ImageSnapshotSpec>{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<cls::rbd::ImageSnapshotSpec>{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;