Skip to content

Commit

Permalink
cls/rbd: add assert_snapc_seq method
Browse files Browse the repository at this point in the history
Signed-off-by: Mykola Golub <[email protected]>
  • Loading branch information
trociny authored and Jason Dillaman committed Aug 14, 2018
1 parent ad4809b commit 57ef57a
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/cls/rbd/cls_rbd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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",
Expand Down
17 changes: 17 additions & 0 deletions src/cls/rbd/cls_rbd_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions src/cls/rbd/cls_rbd_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
15 changes: 15 additions & 0 deletions src/cls/rbd/cls_rbd_types.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
19 changes: 19 additions & 0 deletions src/cls/rbd/cls_rbd_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
9 changes: 9 additions & 0 deletions src/objclass/class_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/objclass/objclass.h
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
59 changes: 59 additions & 0 deletions src/test/cls_rbd/test_cls_rbd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
13 changes: 13 additions & 0 deletions src/test/librados_test_stub/LibradosTestStub.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 57ef57a

Please sign in to comment.