]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
cls/rbd: add assert_snapc_seq method
authorMykola Golub <mgolub@suse.com>
Sun, 15 Jul 2018 09:21:08 +0000 (12:21 +0300)
committerJason Dillaman <dillaman@redhat.com>
Tue, 14 Aug 2018 22:29:44 +0000 (18:29 -0400)
Signed-off-by: Mykola Golub <mgolub@suse.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.cc
src/cls/rbd/cls_rbd_types.h
src/objclass/class_api.cc
src/objclass/objclass.h
src/test/cls_rbd/test_cls_rbd.cc
src/test/librados_test_stub/LibradosTestStub.cc

index 49855bc35520d9a32f94a88e4e8dff9fca0c95f0..bfc1ea3154bb8b7ae74764a589ba0ec3b7bbd83a 100644 (file)
@@ -3735,6 +3735,46 @@ int migration_remove(cls_method_context_t hctx, bufferlist *in,
   return 0;
 }
 
+/**
+ * Ensure writer snapc state
+ *
+ * Input:
+ * @param snap id (uint64_t) snap context sequence id
+ * @param state (cls::rbd::AssertSnapcSeqState) snap context state
+ *
+ * Output:
+ * @returns -ERANGE if assertion fails
+ * @returns 0 on success, negative error code on failure
+ */
+int assert_snapc_seq(cls_method_context_t hctx, bufferlist *in,
+                     bufferlist *out)
+{
+  uint64_t snapc_seq;
+  cls::rbd::AssertSnapcSeqState state;
+  try {
+    auto it = in->cbegin();
+    decode(snapc_seq, it);
+    decode(state, it);
+  } catch (const buffer::error &err) {
+    return -EINVAL;
+  }
+
+  uint64_t snapset_seq;
+  int r = cls_get_snapset_seq(hctx, &snapset_seq);
+  if (r < 0 && r != -ENOENT) {
+    return r;
+  }
+
+  switch (state) {
+  case cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ:
+    return (r == -ENOENT || snapc_seq > snapset_seq) ? 0 : -ERANGE;
+  case cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ:
+    return (r == -ENOENT || snapc_seq > snapset_seq) ? -ERANGE : 0;
+  default:
+    return -EOPNOTSUPP;
+  }
+}
+
 /****************************** Old format *******************************/
 
 int old_snapshots_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
@@ -6661,6 +6701,7 @@ CLS_INIT(rbd)
   cls_method_handle_t h_migration_set_state;
   cls_method_handle_t h_migration_get;
   cls_method_handle_t h_migration_remove;
+  cls_method_handle_t h_assert_snapc_seq;
   cls_method_handle_t h_old_snapshots_list;
   cls_method_handle_t h_old_snapshot_add;
   cls_method_handle_t h_old_snapshot_remove;
@@ -6838,6 +6879,10 @@ CLS_INIT(rbd)
   cls_register_cxx_method(h_class, "migration_remove",
                           CLS_METHOD_RD | CLS_METHOD_WR,
                           migration_remove, &h_migration_remove);
+  cls_register_cxx_method(h_class, "assert_snapc_seq",
+                          CLS_METHOD_RD | CLS_METHOD_WR,
+                          assert_snapc_seq,
+                          &h_assert_snapc_seq);
 
   /* methods for the rbd_children object */
   cls_register_cxx_method(h_class, "add_child",
index 98e9cea9967e73eadee5c0ba63881ee6a441c882..087ed597b23b19ba8d1212499d08ba4dbca454a4 100644 (file)
@@ -1667,6 +1667,23 @@ namespace librbd {
       op->exec("rbd", "migration_remove", bl);
     }
 
+    int assert_snapc_seq(librados::IoCtx *ioctx, const std::string &oid,
+                         uint64_t snapc_seq,
+                         cls::rbd::AssertSnapcSeqState state) {
+      librados::ObjectWriteOperation op;
+      assert_snapc_seq(&op, snapc_seq, state);
+      return ioctx->operate(oid, &op);
+    }
+
+    void assert_snapc_seq(librados::ObjectWriteOperation *op,
+                          uint64_t snapc_seq,
+                          cls::rbd::AssertSnapcSeqState state) {
+      bufferlist bl;
+      encode(snapc_seq, bl);
+      encode(state, bl);
+      op->exec("rbd", "assert_snapc_seq", bl);
+    }
+
     void mirror_uuid_get_start(librados::ObjectReadOperation *op) {
       bufferlist bl;
       op->exec("rbd", "mirror_uuid_get", bl);
index c96900e9864b8512fa136ce475c25cab034a837b..2acc5be47437ad659b777fc48b62fb69da5d1df3 100644 (file)
@@ -276,6 +276,13 @@ namespace librbd {
     int migration_remove(librados::IoCtx *ioctx, const std::string &oid);
     void migration_remove(librados::ObjectWriteOperation *op);
 
+    int assert_snapc_seq(librados::IoCtx *ioctx, const std::string &oid,
+                         uint64_t snapc_seq,
+                         cls::rbd::AssertSnapcSeqState state);
+    void assert_snapc_seq(librados::ObjectWriteOperation *op,
+                          uint64_t snapc_seq,
+                         cls::rbd::AssertSnapcSeqState state);
+
     // operations on rbd_id objects
     void get_id_start(librados::ObjectReadOperation *op);
     int get_id_finish(bufferlist::const_iterator *it, std::string *id);
index de90bcfcde404e99ac6d1dfaba2d176e6de1bd27..a4613c2d1ee08e1b55f08b66f3fc2cb6ac0c3740 100644 (file)
@@ -842,5 +842,20 @@ std::ostream& operator<<(std::ostream& os,
   return os;
 }
 
+std::ostream& operator<<(std::ostream& os, const AssertSnapcSeqState& state) {
+  switch (state) {
+  case ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ:
+    os << "gt";
+    break;
+  case ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ:
+    os << "le";
+    break;
+  default:
+    os << "unknown (" << static_cast<uint32_t>(state) << ")";
+    break;
+  }
+  return os;
+}
+
 } // namespace rbd
 } // namespace cls
index 8b866bac06d62f3756a0983b3234388f1990ef7f..cd8b01038bfa94980b065295f22794d94c710e37 100644 (file)
@@ -691,6 +691,25 @@ std::ostream& operator<<(std::ostream& os, const MigrationSpec& migration_spec);
 
 WRITE_CLASS_ENCODER(MigrationSpec);
 
+enum AssertSnapcSeqState {
+  ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ = 0,
+  ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ = 1,
+};
+
+inline void encode(const AssertSnapcSeqState &state, bufferlist& bl) {
+  using ceph::encode;
+  encode(static_cast<uint8_t>(state), bl);
+}
+
+inline void decode(AssertSnapcSeqState &state, bufferlist::const_iterator& it) {
+  uint8_t int_state;
+  using ceph::decode;
+  decode(int_state, it);
+  state = static_cast<AssertSnapcSeqState>(int_state);
+}
+
+std::ostream& operator<<(std::ostream& os, const AssertSnapcSeqState& state);
+
 } // namespace rbd
 } // namespace cls
 
index fd45c813f5bd081cbfa7b39d7f1231f40101cf14..3edfbf6244c513e9e8c8dfe350ff2624667b3488 100644 (file)
@@ -705,6 +705,15 @@ void cls_cxx_subop_version(cls_method_context_t hctx, string *s)
   *s = buf;
 }
 
+int cls_get_snapset_seq(cls_method_context_t hctx, uint64_t *snap_seq) {
+  PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx;
+  if (!ctx->new_obs.exists) {
+    return -ENOENT;
+  }
+  *snap_seq = ctx->obc->ssc->snapset.seq;
+  return 0;
+}
+
 int cls_log(int level, const char *format, ...)
 {
    int size = 256;
index d36867de5488fa288b94e77c8cd806abaf98fd86..df2017d9f5d2224f6aac2308827ccc3be61bbd4e 100644 (file)
@@ -160,6 +160,8 @@ extern uint64_t cls_get_client_features(cls_method_context_t hctx);
 /* helpers */
 extern void cls_cxx_subop_version(cls_method_context_t hctx, string *s);
 
+extern int cls_get_snapset_seq(cls_method_context_t hctx, uint64_t *snap_seq);
+
 /* These are also defined in rados.h and librados.h. Keep them in sync! */
 #define CEPH_OSD_TMAP_HDR 'h'
 #define CEPH_OSD_TMAP_SET 's'
index f8a386d5162ca2468405c53458db1dd88d74e0fb..30e0c2881e6f0328c1546907c170ebee0af1551b 100644 (file)
@@ -2879,3 +2879,62 @@ TEST_F(TestClsRbd, migration_v1)
 
   ioctx.close();
 }
+
+TEST_F(TestClsRbd, assert_snapc_seq)
+{
+  librados::IoCtx ioctx;
+  ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+  string oid = get_temp_image_name();
+
+  ASSERT_EQ(0,
+            assert_snapc_seq(&ioctx, oid, 0,
+                             cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ));
+  ASSERT_EQ(-ERANGE,
+            assert_snapc_seq(&ioctx, oid, 0,
+                             cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ));
+
+  ASSERT_EQ(0, ioctx.create(oid, true));
+
+  uint64_t snapc_seq = 0;
+
+  ASSERT_EQ(-ERANGE,
+            assert_snapc_seq(&ioctx, oid, snapc_seq,
+                             cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ));
+  ASSERT_EQ(0,
+            assert_snapc_seq(&ioctx, oid, snapc_seq,
+                             cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ));
+
+  std::vector<uint64_t> snaps;
+  snaps.push_back(CEPH_NOSNAP);
+  ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&snaps.back()));
+  snapc_seq = snaps[0];
+
+  ASSERT_EQ(0,
+            assert_snapc_seq(&ioctx, oid, snapc_seq,
+                             cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ));
+  ASSERT_EQ(-ERANGE,
+            assert_snapc_seq(&ioctx, oid, snapc_seq,
+                             cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ));
+
+  ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(snaps[0], snaps));
+  bufferlist bl;
+  bl.append("foo");
+  ASSERT_EQ(0, ioctx.write(oid, bl, bl.length(), 0));
+
+  ASSERT_EQ(-ERANGE,
+            assert_snapc_seq(&ioctx, oid, snapc_seq,
+                             cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ));
+  ASSERT_EQ(0,
+            assert_snapc_seq(&ioctx, oid, snapc_seq,
+                             cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ));
+
+  ASSERT_EQ(0,
+            assert_snapc_seq(&ioctx, oid, snapc_seq + 1,
+                             cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ));
+  ASSERT_EQ(-ERANGE,
+            assert_snapc_seq(&ioctx, oid, snapc_seq + 1,
+                             cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ));
+
+  ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(snapc_seq));
+}
index 49bc1be67958aaef46831d74b6594ee9b3173633..87b17fda82ff59681cc3b06523fc2914a63c2f20 100644 (file)
@@ -1355,6 +1355,19 @@ uint64_t cls_get_client_features(cls_method_context_t hctx) {
   return CEPH_FEATURES_SUPPORTED_DEFAULT;
 }
 
+int cls_get_snapset_seq(cls_method_context_t hctx, uint64_t *snap_seq) {
+  librados::TestClassHandler::MethodContext *ctx =
+    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
+  librados::snap_set_t snapset;
+  int r = ctx->io_ctx_impl->list_snaps(ctx->oid, &snapset);
+  if (r < 0) {
+    return r;
+  }
+
+  *snap_seq = snapset.seq;
+  return 0;
+}
+
 int cls_log(int level, const char *format, ...) {
   int size = 256;
   va_list ap;