#define RBD_MAX_IMAGE_NAME_SIZE 96
#define RBD_MAX_BLOCK_NAME_SIZE 24
+#define RBD_SNAP_CREATE_SKIP_QUIESCE 1 << 0
+#define RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR 1 << 1
+
#define RBD_SNAP_REMOVE_UNPROTECT 1 << 0
#define RBD_SNAP_REMOVE_FLATTEN 1 << 1
#define RBD_SNAP_REMOVE_FORCE (RBD_SNAP_REMOVE_UNPROTECT | RBD_SNAP_REMOVE_FLATTEN)
CEPH_RBD_API void rbd_snap_list_end(rbd_snap_info_t *snaps);
CEPH_RBD_API int rbd_snap_exists(rbd_image_t image, const char *snapname, bool *exists);
CEPH_RBD_API int rbd_snap_create(rbd_image_t image, const char *snapname);
+CEPH_RBD_API int rbd_snap_create2(rbd_image_t image, const char *snap_name,
+ uint32_t flags, librbd_progress_fn_t cb,
+ void *cbdata);
CEPH_RBD_API int rbd_snap_remove(rbd_image_t image, const char *snapname);
CEPH_RBD_API int rbd_snap_remove2(rbd_image_t image, const char *snap_name,
uint32_t flags, librbd_progress_fn_t cb,
bool snap_exists(const char *snapname) CEPH_RBD_DEPRECATED;
int snap_exists2(const char *snapname, bool *exists);
int snap_create(const char *snapname);
+ int snap_create2(const char *snapname, uint32_t flags, ProgressContext& pctx);
int snap_remove(const char *snapname);
int snap_remove2(const char *snapname, uint32_t flags, ProgressContext& pctx);
int snap_remove_by_id(uint64_t snap_id);
void ImageWatcher<I>::notify_snap_create(uint64_t request_id,
const cls::rbd::SnapshotNamespace &snap_namespace,
const std::string &snap_name,
+ uint64_t flags,
ProgressContext &prog_ctx,
Context *on_finish) {
ceph_assert(ceph_mutex_is_locked(m_image_ctx.owner_lock));
notify_async_request(async_request_id,
new SnapCreatePayload(async_request_id, snap_namespace,
- snap_name),
+ snap_name, flags),
prog_ctx, on_finish);
}
ldout(m_image_ctx.cct, 10) << this << " remote snap_create request: "
<< payload.async_request_id << " "
<< payload.snap_namespace << " "
- << payload.snap_name << dendl;
+ << payload.snap_name << " "
+ << payload.flags << dendl;
m_image_ctx.operations->execute_snap_create(payload.snap_namespace,
payload.snap_name,
- ctx, 0, false, *prog_ctx);
+ ctx, 0, payload.flags,
+ *prog_ctx);
}
return complete;
} else if (r < 0) {
void notify_snap_create(uint64_t request_id,
const cls::rbd::SnapshotNamespace &snap_namespace,
const std::string &snap_name,
+ uint64_t flags,
ProgressContext &prog_ctx,
Context *on_finish);
void notify_snap_rename(const snapid_t &src_snap_id,
template <typename I>
int Operations<I>::snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
- const std::string& snap_name) {
+ const std::string& snap_name, uint64_t flags,
+ ProgressContext &prog_ctx) {
if (m_image_ctx.read_only) {
return -EROFS;
}
}
C_SaferCond ctx;
- snap_create(snap_namespace, snap_name, &ctx);
+ snap_create(snap_namespace, snap_name, flags, prog_ctx, &ctx);
r = ctx.wait();
if (r < 0) {
template <typename I>
void Operations<I>::snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
- const std::string& snap_name,
- Context *on_finish) {
+ const std::string& snap_name, uint64_t flags,
+ ProgressContext &prog_ctx, Context *on_finish) {
CephContext *cct = m_image_ctx.cct;
ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
<< dendl;
}
m_image_ctx.image_lock.unlock_shared();
- auto prog_ctx = new NoOpProgressContext();
- on_finish = new LambdaContext(
- [prog_ctx, on_finish](int r) {
- delete prog_ctx;
- on_finish->complete(r);
- });
-
uint64_t request_id = ++m_async_request_seq;
C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
m_image_ctx, "snap_create", exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
true,
boost::bind(&Operations<I>::execute_snap_create, this, snap_namespace, snap_name,
- _1, 0, 0, boost::ref(*prog_ctx)),
+ _1, 0, flags, boost::ref(prog_ctx)),
boost::bind(&ImageWatcher<I>::notify_snap_create, m_image_ctx.image_watcher,
- request_id, snap_namespace, snap_name, boost::ref(*prog_ctx),
- _1),
+ request_id, snap_namespace, snap_name, flags,
+ boost::ref(prog_ctx), _1),
{-EEXIST}, on_finish);
req->send();
}
Context *on_finish, uint64_t journal_op_tid);
int snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
- const std::string& snap_name);
+ const std::string& snap_name, uint64_t flags,
+ ProgressContext& prog_ctx);
void snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
- const std::string& snap_name, Context *on_finish);
+ const std::string& snap_name, uint64_t flags,
+ ProgressContext& prog_ctx, Context *on_finish);
void execute_snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
const std::string &snap_name, Context *on_finish,
uint64_t journal_op_tid, uint64_t flags,
};
enum SnapCreateFlag {
- SNAP_CREATE_FLAG_SKIP_OBJECT_MAP = 1 << 0,
- SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE = 1 << 1,
+ SNAP_CREATE_FLAG_SKIP_OBJECT_MAP = 1 << 0,
+ SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE = 1 << 1,
+ SNAP_CREATE_FLAG_IGNORE_NOTIFY_QUIESCE_ERROR = 1 << 2,
};
struct MigrationInfo {
using ceph::encode;
SnapPayloadBase::encode(bl);
encode(async_request_id, bl);
+ encode(flags, bl);
}
void SnapCreatePayload::decode(__u8 version, bufferlist::const_iterator &iter) {
}
if (version >= 7) {
decode(async_request_id, iter);
+ decode(flags, iter);
}
}
async_request_id.dump(f);
f->close_section();
SnapPayloadBase::dump(f);
+ f->dump_unsigned("flags", flags);
}
void SnapRenamePayload::encode(bufferlist &bl) const {
o.push_back(new NotifyMessage(new ResizePayload(123, true, AsyncRequestId(ClientId(0, 1), 2))));
o.push_back(new NotifyMessage(new SnapCreatePayload(AsyncRequestId(ClientId(0, 1), 2),
cls::rbd::UserSnapshotNamespace(),
- "foo")));
+ "foo", 1)));
o.push_back(new NotifyMessage(new SnapRemovePayload(cls::rbd::UserSnapshotNamespace(), "foo")));
o.push_back(new NotifyMessage(new SnapProtectPayload(cls::rbd::UserSnapshotNamespace(), "foo")));
o.push_back(new NotifyMessage(new SnapUnprotectPayload(cls::rbd::UserSnapshotNamespace(), "foo")));
struct SnapCreatePayload : public SnapPayloadBase {
AsyncRequestId async_request_id;
+ uint64_t flags = 0;
SnapCreatePayload() {}
SnapCreatePayload(const AsyncRequestId &id,
const cls::rbd::SnapshotNamespace &snap_namespace,
- const std::string &name)
- : SnapPayloadBase(snap_namespace, name), async_request_id(id) {
+ const std::string &name, uint64_t flags)
+ : SnapPayloadBase(snap_namespace, name), async_request_id(id),
+ flags(flags) {
}
NotifyOp get_notify_op() const override {
#include "librbd/Operations.h"
#include "librbd/Utils.h"
#include "librbd/api/Image.h"
-#include <boost/variant.hpp>
#include "include/Context.h"
#include "common/Cond.h"
+#include <bitset>
+#include <boost/variant.hpp>
+
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
#define dout_prefix *_dout << "librbd::api::Snapshot: " << __func__ << ": "
return 0;
}
+template <typename I>
+int Snapshot<I>::create(I *ictx, const char *snap_name, uint32_t flags,
+ ProgressContext& pctx) {
+ ldout(ictx->cct, 20) << "snap_create " << ictx << " " << snap_name
+ << " flags: " << flags << dendl;
+
+ uint64_t internal_flags = 0;
+
+ if (flags & RBD_SNAP_CREATE_SKIP_QUIESCE) {
+ internal_flags |= SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE;
+ flags &= ~RBD_SNAP_CREATE_SKIP_QUIESCE;
+ } else if (flags & RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR) {
+ internal_flags |= SNAP_CREATE_FLAG_IGNORE_NOTIFY_QUIESCE_ERROR;
+ flags &= ~RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR;
+ }
+
+ if (flags != 0) {
+ lderr(ictx->cct) << "invalid snap create flags: " << std::bitset<32>(flags)
+ << dendl;
+ return -EINVAL;
+ }
+
+ return ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
+ snap_name, internal_flags, pctx);
+}
+
template <typename I>
int Snapshot<I>::remove(I *ictx, const char *snap_name, uint32_t flags,
ProgressContext& pctx) {
static int exists(ImageCtxT *ictx, const cls::rbd::SnapshotNamespace& snap_namespace,
const char *snap_name, bool *exists);
+ static int create(ImageCtxT *ictx, const char *snap_name, uint32_t flags,
+ ProgressContext& pctx);
+
static int remove(ImageCtxT *ictx, const char *snap_name, uint32_t flags, ProgressContext& pctx);
static int get_limit(ImageCtxT *ictx, uint64_t *limit);
handle_create_snap(r);
finish_op_ctx->complete(0);
});
+ uint64_t flags = SNAP_CREATE_FLAG_SKIP_OBJECT_MAP |
+ SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE;
std::shared_lock owner_locker{m_dst_image_ctx->owner_lock};
m_dst_image_ctx->operations->execute_snap_create(
- m_snap_namespace, m_snap_name.c_str(), ctx, 0U,
- SNAP_CREATE_FLAG_SKIP_OBJECT_MAP, m_prog_ctx);
+ m_snap_namespace, m_snap_name.c_str(), ctx, 0U, flags, m_prog_ctx);
}
template <typename I>
image_ctx.operations->execute_snap_create(event.snap_namespace,
event.snap_name,
on_op_complete,
- event.op_tid, 0,
+ event.op_tid,
+ SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE,
no_op_progress_callback);
}
{
ImageCtx *ictx = (ImageCtx *)ctx;
tracepoint(librbd, snap_create_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
- int r = ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- snap_name);
+ librbd::NoOpProgressContext prog_ctx;
+ int r = librbd::api::Snapshot<>::create(ictx, snap_name, 0, prog_ctx);
+ tracepoint(librbd, snap_create_exit, r);
+ return r;
+ }
+
+ int Image::snap_create2(const char *snap_name, uint32_t flags,
+ ProgressContext& prog_ctx)
+ {
+ ImageCtx *ictx = (ImageCtx *)ctx;
+ tracepoint(librbd, snap_create_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
+ int r = librbd::api::Snapshot<>::create(ictx, snap_name, flags, prog_ctx);
tracepoint(librbd, snap_create_exit, r);
return r;
}
{
librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
tracepoint(librbd, snap_create_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
- int r = ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- snap_name);
+ librbd::NoOpProgressContext prog_ctx;
+ int r = librbd::api::Snapshot<>::create(ictx, snap_name, 0, prog_ctx);
+ tracepoint(librbd, snap_create_exit, r);
+ return r;
+}
+
+extern "C" int rbd_snap_create2(rbd_image_t image, const char *snap_name,
+ uint32_t flags, librbd_progress_fn_t cb,
+ void *cbdata)
+{
+ librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+ tracepoint(librbd, snap_create_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
+ librbd::CProgressContext prog_ctx(cb, cbdata);
+ int r = librbd::api::Snapshot<>::create(ictx, snap_name, flags, prog_ctx);
tracepoint(librbd, snap_create_exit, r);
return r;
}
auto ctx = create_context_callback<
CreateNonPrimaryRequest<I>,
&CreateNonPrimaryRequest<I>::handle_create_snapshot>(this);
- m_image_ctx->operations->snap_create(ns, m_snap_name, ctx);
+ m_image_ctx->operations->snap_create(ns, m_snap_name, 0, m_prog_ctx, ctx);
}
template <typename I>
#include "include/buffer.h"
#include "cls/rbd/cls_rbd_types.h"
#include "librbd/Types.h"
+#include "librbd/internal.h"
#include "librbd/mirror/snapshot/Types.h"
#include <string>
std::string m_snap_name;
bufferlist m_out_bl;
+ NoOpProgressContext m_prog_ctx;
bool is_orphan() const {
return m_primary_mirror_uuid.empty();
auto ctx = create_context_callback<
CreatePrimaryRequest<I>,
&CreatePrimaryRequest<I>::handle_create_snapshot>(this);
- m_image_ctx->operations->snap_create(ns, m_snap_name, ctx);
+ m_image_ctx->operations->snap_create(ns, m_snap_name, 0, m_prog_ctx, ctx);
}
template <typename I>
#include "include/buffer.h"
#include "include/rados/librados.hpp"
#include "cls/rbd/cls_rbd_types.h"
+#include "librbd/internal.h"
#include "librbd/mirror/snapshot/Types.h"
#include <string>
std::string m_snap_name;
bufferlist m_out_bl;
+ NoOpProgressContext m_prog_ctx;
void get_mirror_peers();
void handle_get_mirror_peers(int r);
m_snap_namespace(snap_namespace), m_snap_name(snap_name),
m_skip_object_map(flags & SNAP_CREATE_FLAG_SKIP_OBJECT_MAP),
m_skip_notify_quiesce(flags & SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE),
+ m_ignore_notify_quiesce_error(flags & SNAP_CREATE_FLAG_IGNORE_NOTIFY_QUIESCE_ERROR),
m_prog_ctx(prog_ctx) {
}
CephContext *cct = image_ctx.cct;
ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
- if (*result < 0) {
+ if (*result < 0 && !m_ignore_notify_quiesce_error) {
lderr(cct) << "failed to notify quiesce: " << cpp_strerror(*result)
<< dendl;
save_result(result);
Context *SnapshotCreateRequest<I>::send_notify_unquiesce() {
I &image_ctx = this->m_image_ctx;
CephContext *cct = image_ctx.cct;
- ldout(cct, 5) << this << " " << __func__ << dendl;
if (m_writes_blocked) {
image_ctx.io_image_dispatcher->unblock_writes();
return this->create_context_finisher(m_ret_val);
}
+ ldout(cct, 5) << this << " " << __func__ << dendl;
+
image_ctx.image_watcher->notify_unquiesce(
m_request_id, create_context_callback<
SnapshotCreateRequest<I>,
std::string m_snap_name;
bool m_skip_object_map;
bool m_skip_notify_quiesce;
+ bool m_ignore_notify_quiesce_error;
ProgressContext &m_prog_ctx;
uint64_t m_request_id = 0;
int create_snap(librbd::ImageCtx *image_ctx, const char* snap_name,
librados::snap_t *snap_id) {
+ NoOpProgressContext prog_ctx;
int r = image_ctx->operations->snap_create(
- cls::rbd::UserSnapshotNamespace(), snap_name);
+ cls::rbd::UserSnapshotNamespace(), snap_name, 0, prog_ctx);
if (r < 0) {
return r;
}
int create_snap(librbd::ImageCtx *image_ctx, const char* snap_name,
librados::snap_t *snap_id) {
+ NoOpProgressContext prog_ctx;
int r = image_ctx->operations->snap_create(
- cls::rbd::UserSnapshotNamespace(), snap_name);
+ cls::rbd::UserSnapshotNamespace(), snap_name, 0, prog_ctx);
if (r < 0) {
return r;
}
int create_snap(librbd::ImageCtx *image_ctx,
const cls::rbd::SnapshotNamespace& snap_ns,
const std::string &snap_name, bool protect) {
- int r = image_ctx->operations->snap_create(snap_ns, snap_name.c_str());
+ NoOpProgressContext prog_ctx;
+ int r = image_ctx->operations->snap_create(snap_ns, snap_name.c_str(), 0,
+ prog_ctx);
if (r < 0) {
return r;
}
void expect_snap_create(librbd::MockTestImageCtx &mock_image_ctx,
const std::string &snap_name, uint64_t snap_id, int r) {
+ uint64_t flags = SNAP_CREATE_FLAG_SKIP_OBJECT_MAP |
+ SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE;
EXPECT_CALL(*mock_image_ctx.operations,
- execute_snap_create(_, StrEq(snap_name), _, 0,
- SNAP_CREATE_FLAG_SKIP_OBJECT_MAP, _))
+ execute_snap_create(_, StrEq(snap_name), _, 0, flags, _))
.WillOnce(DoAll(InvokeWithoutArgs([&mock_image_ctx, snap_id, snap_name]() {
inject_snap(mock_image_ctx, snap_id, snap_name);
}),
#include "librbd/Operations.h"
#include "librbd/image/AttachChildRequest.h"
#include "librbd/image/RefreshRequest.h"
+#include "librbd/internal.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
TestMockFixture::SetUp();
ASSERT_EQ(0, open_image(m_image_name, &image_ctx));
+ NoOpProgressContext prog_ctx;
ASSERT_EQ(0, image_ctx->operations->snap_create(
- cls::rbd::UserSnapshotNamespace{}, "snap"));
+ cls::rbd::UserSnapshotNamespace{}, "snap", 0, prog_ctx));
if (is_feature_enabled(RBD_FEATURE_LAYERING)) {
ASSERT_EQ(0, image_ctx->operations->snap_protect(
cls::rbd::UserSnapshotNamespace{}, "snap"));
ASSERT_EQ(0, _rados.conf_set("rbd_default_clone_format", "2"));
ASSERT_EQ(0, open_image(m_image_name, &image_ctx));
+ NoOpProgressContext prog_ctx;
ASSERT_EQ(0, image_ctx->operations->snap_create(
- cls::rbd::UserSnapshotNamespace{}, "snap"));
+ cls::rbd::UserSnapshotNamespace{}, "snap", 0, prog_ctx));
if (is_feature_enabled(RBD_FEATURE_LAYERING)) {
ASSERT_EQ(0, image_ctx->operations->snap_protect(
cls::rbd::UserSnapshotNamespace{}, "snap"));
"snap"));
}
- // verify lock ordering constraints
+ // verify lock ordering constraints
+ librbd::NoOpProgressContext no_op_progress;
ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "snap2"));
+ "snap2", 0, no_op_progress));
}
TEST_F(TestJournalReplay, SnapProtect) {
ASSERT_EQ(0, open_image(m_image_name, &ictx));
ASSERT_EQ(0, when_acquired_lock(ictx));
+ librbd::NoOpProgressContext no_op_progress;
ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "snap"));
+ "snap", 0, no_op_progress));
// get current commit position
int64_t initial_tag;
// verify lock ordering constraints
ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "snap2"));
+ "snap2", 0, no_op_progress));
ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
"snap2"));
}
ASSERT_EQ(0, open_image(m_image_name, &ictx));
ASSERT_EQ(0, when_acquired_lock(ictx));
+ librbd::NoOpProgressContext no_op_progress;
ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "snap"));
+ "snap", 0, no_op_progress));
uint64_t snap_id;
{
std::shared_lock image_locker{ictx->image_lock};
// verify lock ordering constraints
ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "snap2"));
+ "snap2", 0, no_op_progress));
ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
"snap2"));
ASSERT_EQ(0, ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(),
ASSERT_EQ(0, open_image(m_image_name, &ictx));
ASSERT_EQ(0, when_acquired_lock(ictx));
+ librbd::NoOpProgressContext no_op_progress;
ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "snap"));
+ "snap", 0, no_op_progress));
uint64_t snap_id;
{
std::shared_lock image_locker{ictx->image_lock};
ASSERT_EQ(0, open_image(m_image_name, &ictx));
ASSERT_EQ(0, when_acquired_lock(ictx));
+ librbd::NoOpProgressContext no_op_progress;
ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "snap"));
+ "snap", 0, no_op_progress));
// get current commit position
int64_t initial_tag;
ASSERT_EQ(initial_entry + 2, current_entry);
// verify lock ordering constraints
- librbd::NoOpProgressContext no_op_progress;
ASSERT_EQ(0, ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(),
"snap",
no_op_progress));
ASSERT_EQ(0, open_image(m_image_name, &ictx));
ASSERT_EQ(0, when_acquired_lock(ictx));
+ librbd::NoOpProgressContext no_op_progress;
ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "snap"));
+ "snap", 0, no_op_progress));
// get current commit position
int64_t initial_tag;
// verify lock ordering constraints
ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "snap"));
+ "snap", 0, no_op_progress));
ASSERT_EQ(0, ictx->operations->snap_remove(cls::rbd::UserSnapshotNamespace(),
"snap"));
}
librbd::ImageCtx *ictx;
ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ librbd::NoOpProgressContext no_op_progress;
ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "snap"));
+ "snap", 0, no_op_progress));
ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
"snap"));
void expect_snap_create(MockReplayImageCtx &mock_image_ctx,
Context **on_finish, const char *snap_name,
uint64_t op_tid) {
- EXPECT_CALL(*mock_image_ctx.operations, execute_snap_create(_, StrEq(snap_name), _,
- op_tid, 0, _))
+ EXPECT_CALL(*mock_image_ctx.operations,
+ execute_snap_create(_, StrEq(snap_name), _, op_tid,
+ SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE, _))
.WillOnce(DoAll(SaveArg<2>(on_finish),
NotifyInvoke(&m_invoke_lock, &m_invoke_cond)));
}
}
void expect_create_snapshot(MockTestImageCtx &mock_image_ctx, int r) {
- EXPECT_CALL(*mock_image_ctx.operations, snap_create(_, _, _))
- .WillOnce(WithArg<2>(CompleteContext(
+ EXPECT_CALL(*mock_image_ctx.operations, snap_create(_, _, _, _, _))
+ .WillOnce(WithArg<4>(CompleteContext(
r, mock_image_ctx.image_ctx->op_work_queue)));
}
}
void expect_create_snapshot(MockTestImageCtx &mock_image_ctx, int r) {
- EXPECT_CALL(*mock_image_ctx.operations, snap_create(_, _, _))
+ EXPECT_CALL(*mock_image_ctx.operations, snap_create(_, _, _, _, _))
.WillOnce(DoAll(
Invoke([this, &mock_image_ctx, r](
const cls::rbd::SnapshotNamespace &ns,
const std::string& snap_name,
+ uint64_t flags,
+ ProgressContext &prog_ctx,
Context *on_finish) {
if (r != 0) {
return;
}
snap_create(mock_image_ctx, ns, snap_name);
}),
- WithArg<2>(CompleteContext(
+ WithArg<4>(CompleteContext(
r, mock_image_ctx.image_ctx->op_work_queue))
));
}
ProgressContext &prog_ctx,
Context *on_finish,
uint64_t journal_op_tid));
- MOCK_METHOD3(snap_create, void(const cls::rbd::SnapshotNamespace &snapshot_namespace,
+ MOCK_METHOD5(snap_create, void(const cls::rbd::SnapshotNamespace &snapshot_namespace,
const std::string &snap_name,
+ uint64_t flags,
+ ProgressContext &prog_ctx,
Context *on_finish));
MOCK_METHOD6(execute_snap_create, void(const cls::rbd::SnapshotNamespace &snapshot_namespace,
const std::string &snap_name,
expect_op_work_queue(mock_image_ctx);
::testing::InSequence seq;
- expect_notify_quiesce(mock_image_ctx, 0);
+ expect_notify_quiesce(mock_image_ctx, -EINVAL);
expect_block_writes(mock_image_ctx);
expect_allocate_snap_id(mock_image_ctx, 0);
expect_snap_create(mock_image_ctx, 0);
librbd::NoOpProgressContext prog_ctx;
MockSnapshotCreateRequest *req = new MockSnapshotCreateRequest(
mock_image_ctx, &cond_ctx, cls::rbd::UserSnapshotNamespace(),
- "snap1", 0, 0, prog_ctx);
+ "snap1", 0, SNAP_CREATE_FLAG_IGNORE_NOTIFY_QUIESCE_ERROR, prog_ctx);
{
std::shared_lock owner_locker{mock_image_ctx.owner_lock};
req->send();
librbd::ImageCtx *ictx;
ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ NoOpProgressContext prog_ctx;
ASSERT_EQ(0, ictx->operations->snap_create(
- {cls::rbd::TrashSnapshotNamespace{}}, "snap1"));
+ {cls::rbd::TrashSnapshotNamespace{}}, "snap1", 0, prog_ctx));
ASSERT_EQ(0, ictx->state->refresh_if_required());
MockImageCtx mock_image_ctx(*ictx);
std::shared_lock l{ictx->owner_lock};
C_SaferCond ctx;
ictx->image_watcher->notify_snap_create(0, cls::rbd::UserSnapshotNamespace(),
- "snap", *progress_context, &ctx);
+ "snap", 0, *progress_context, &ctx);
ASSERT_EQ(0, ctx.wait());
}
};
C_SaferCond notify_ctx;
librbd::NoOpProgressContext prog_ctx;
ictx->image_watcher->notify_snap_create(0, cls::rbd::UserSnapshotNamespace(),
- "snap", prog_ctx, ¬ify_ctx);
+ "snap", 0, prog_ctx, ¬ify_ctx);
ASSERT_EQ(-EEXIST, notify_ctx.wait());
NotifyOps expected_notify_ops;
int TestFixture::snap_create(librbd::ImageCtx &ictx,
const std::string &snap_name) {
+ librbd::NoOpProgressContext prog_ctx;
return ictx.operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- snap_name.c_str());
+ snap_name.c_str(), 0, prog_ctx);
}
int TestFixture::snap_protect(librbd::ImageCtx &ictx,
ASSERT_EQ(0, open_image(clone_name, &ictx2));
ASSERT_EQ(0, ictx2->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "snap1"));
+ "snap1", 0, no_op));
bufferlist write_full_bl;
write_full_bl.append(std::string(1 << ictx2->order, '2'));
struct Watcher : public librbd::QuiesceWatchCtx {
librbd::Image ℑ
int r;
- mutex m_lock;
- condition_variable m_cond;
size_t quiesce_count = 0;
size_t unquiesce_count = 0;
}
void handle_quiesce() override {
- lock_guard<mutex> locker(m_lock);
quiesce_count++;
image.quiesce_complete(r);
- m_cond.notify_one();
}
void handle_unquiesce() override {
- lock_guard<mutex> locker(m_lock);
unquiesce_count++;
- m_cond.notify_one();
- }
-
- void wait_for_unquiesce_count(size_t count) {
- unique_lock<mutex> locker(m_lock);
- ASSERT_TRUE(m_cond.wait_for(locker, seconds(60),
- [this, count] {
- return this->unquiesce_count == count;
- }));
}
} watcher1(image1, -EINVAL), watcher2(image2, 0);
uint64_t handle1, handle2;
ASSERT_EQ(0, image2.quiesce_watch(&watcher2, &handle2));
ASSERT_EQ(-EINVAL, image1.snap_create("snap1"));
- ASSERT_EQ(1U, watcher2.quiesce_count);
- watcher2.wait_for_unquiesce_count(1U);
ASSERT_EQ(1U, watcher1.quiesce_count);
ASSERT_EQ(0U, watcher1.unquiesce_count);
+ ASSERT_EQ(1U, watcher2.quiesce_count);
+ ASSERT_EQ(1U, watcher2.unquiesce_count);
- ASSERT_EQ(-EINVAL, image2.snap_create("snap2"));
- ASSERT_EQ(2U, watcher2.quiesce_count);
- watcher2.wait_for_unquiesce_count(2U);
+ PrintProgress prog_ctx;
+ ASSERT_EQ(0, image2.snap_create2("snap2",
+ RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR,
+ prog_ctx));
ASSERT_EQ(2U, watcher1.quiesce_count);
ASSERT_EQ(0U, watcher1.unquiesce_count);
+ ASSERT_EQ(2U, watcher2.quiesce_count);
+ ASSERT_EQ(2U, watcher2.unquiesce_count);
ASSERT_EQ(0, image1.quiesce_unwatch(handle1));
ASSERT_EQ(3U, watcher2.quiesce_count);
ASSERT_EQ(3U, watcher2.unquiesce_count);
+ ASSERT_EQ(0, image2.snap_create2("snap4", RBD_SNAP_CREATE_SKIP_QUIESCE,
+ prog_ctx));
+ ASSERT_EQ(3U, watcher2.quiesce_count);
+ ASSERT_EQ(3U, watcher2.unquiesce_count);
+
ASSERT_EQ(0, image2.quiesce_unwatch(handle2));
+ ASSERT_EQ(0, image1.snap_remove("snap2"));
ASSERT_EQ(0, image1.snap_remove("snap3"));
+ ASSERT_EQ(0, image1.snap_remove("snap4"));
}
ASSERT_EQ(0, rbd.remove(ioctx, name.c_str()));
}
void snap_create(librbd::ImageCtx *image_ctx, const std::string &snap_name) {
+ librbd::NoOpProgressContext prog_ctx;
ASSERT_EQ(0, image_ctx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- snap_name.c_str()));
+ snap_name, 0, prog_ctx));
ASSERT_EQ(0, image_ctx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
- snap_name.c_str()));
+ snap_name));
ASSERT_EQ(0, image_ctx->state->refresh());
}
}
void snap_create(librbd::ImageCtx *image_ctx, const std::string &snap_name) {
+ librbd::NoOpProgressContext prog_ctx;
ASSERT_EQ(0, image_ctx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- snap_name.c_str()));
+ snap_name, 0, prog_ctx));
ASSERT_EQ(0, image_ctx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
- snap_name.c_str()));
+ snap_name));
ASSERT_EQ(0, image_ctx->state->refresh());
}
}
void expect_snap_create(librbd::MockTestImageCtx &mock_remote_image_ctx, int r) {
- EXPECT_CALL(*mock_remote_image_ctx.operations, snap_create(_, _, _))
- .WillOnce(WithArg<2>(CompleteContext(r)));
+ EXPECT_CALL(*mock_remote_image_ctx.operations, snap_create(_, _, _, _, _))
+ .WillOnce(WithArg<4>(CompleteContext(r)));
}
MockSyncPointCreateRequest *create_request(librbd::MockTestImageCtx &mock_remote_image_ctx,
ictx->set_journal_policy(new librbd::journal::DisabledPolicy());
}
+ librbd::NoOpProgressContext prog_ctx;
EXPECT_EQ(0, ictx->operations->snap_create(
- cls::rbd::UserSnapshotNamespace(), snap_name.c_str()));
+ cls::rbd::UserSnapshotNamespace(), snap_name, 0, prog_ctx));
if (protect) {
EXPECT_EQ(0, ictx->operations->snap_protect(
- cls::rbd::UserSnapshotNamespace(), snap_name.c_str()));
+ cls::rbd::UserSnapshotNamespace(), snap_name));
}
EXPECT_EQ(0, ictx->state->close());
ictx->set_journal_policy(new librbd::journal::DisabledPolicy());
}
+ librbd::NoOpProgressContext prog_ctx;
EXPECT_EQ(0, ictx->operations->snap_create(
- cls::rbd::UserSnapshotNamespace(), "snap1"));
+ cls::rbd::UserSnapshotNamespace(), "snap1", 0, prog_ctx));
EXPECT_EQ(0, ictx->operations->snap_protect(
cls::rbd::UserSnapshotNamespace(), "snap1"));
EXPECT_EQ(0, librbd::api::Image<>::snap_set(
librbd::ImageCtx *ictx;
this->open_image(this->m_local_ioctx, this->m_image_name, false, &ictx);
ictx->features &= ~RBD_FEATURE_JOURNALING;
+ librbd::NoOpProgressContext prog_ctx;
ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "foo"));
+ "foo", 0, prog_ctx));
ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
"foo"));
ASSERT_EQ(0, librbd::cls_client::add_child(&ictx->md_ctx, RBD_CHILDREN,
librbd::ImageCtx *ictx;
this->open_image(this->m_local_ioctx, this->m_image_name, false, &ictx);
ictx->features &= ~RBD_FEATURE_JOURNALING;
+ librbd::NoOpProgressContext prog_ctx;
ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- "foo"));
+ "foo", 0, prog_ctx));
ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
"foo"));
ASSERT_EQ(0, librbd::cls_client::add_child(&ictx->md_ctx, RBD_CHILDREN,
this->open_remote_image(&remote_image_ctx);
// create a protected snapshot
+ librbd::NoOpProgressContext prog_ctx;
ASSERT_EQ(0, remote_image_ctx->operations->snap_create(
- cls::rbd::UserSnapshotNamespace{}, "snap1"));
+ cls::rbd::UserSnapshotNamespace{}, "snap1", 0, prog_ctx));
ASSERT_EQ(0, remote_image_ctx->operations->snap_protect(
cls::rbd::UserSnapshotNamespace{}, "snap1"));
this->flush(remote_image_ctx);
this->open_remote_image(&remote_image_ctx);
// create an unprotected snapshot
+ librbd::NoOpProgressContext prog_ctx;
ASSERT_EQ(0, remote_image_ctx->operations->snap_create(
- cls::rbd::UserSnapshotNamespace{}, "snap1"));
+ cls::rbd::UserSnapshotNamespace{}, "snap1", 0, prog_ctx));
this->flush(remote_image_ctx);
this->create_replayer();
this->open_remote_image(&remote_image_ctx);
// create a user snapshot
+ librbd::NoOpProgressContext prog_ctx;
ASSERT_EQ(0, remote_image_ctx->operations->snap_create(
- cls::rbd::UserSnapshotNamespace{}, "snap1"));
+ cls::rbd::UserSnapshotNamespace{}, "snap1", 0, prog_ctx));
this->flush(remote_image_ctx);
this->create_replayer();
this->open_remote_image(&remote_image_ctx);
// create a user snapshot
+ librbd::NoOpProgressContext prog_ctx;
ASSERT_EQ(0, remote_image_ctx->operations->snap_create(
- cls::rbd::UserSnapshotNamespace{}, "snap1"));
+ cls::rbd::UserSnapshotNamespace{}, "snap1", 0, prog_ctx));
this->flush(remote_image_ctx);
this->create_replayer();
librbd::ImageCtx *ictx = new librbd::ImageCtx(parent_image_name.c_str(),
"", "", pioctx, false);
ictx->state->open(0);
+ librbd::NoOpProgressContext prog_ctx;
EXPECT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- snap_name.c_str()));
+ snap_name, 0, prog_ctx));
EXPECT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
- snap_name.c_str()));
+ snap_name));
ictx->state->close();
}
#include "librbd/ImageCtx.h"
#include "librbd/ImageState.h"
#include "librbd/Operations.h"
+#include "librbd/internal.h"
#include "test/librados/test_cxx.h"
#include "tools/rbd_mirror/Threads.h"
int TestFixture::create_snap(librbd::ImageCtx *image_ctx, const char* snap_name,
librados::snap_t *snap_id) {
+ librbd::NoOpProgressContext prog_ctx;
int r = image_ctx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
- snap_name);
+ snap_name, 0, prog_ctx);
if (r < 0) {
return r;
}
SyncPointCreateRequest<I>, &SyncPointCreateRequest<I>::handle_create_snap>(
this);
m_remote_image_ctx->operations->snap_create(
- cls::rbd::UserSnapshotNamespace(), sync_point.snap_name.c_str(), ctx);
+ cls::rbd::UserSnapshotNamespace(), sync_point.snap_name.c_str(),
+ librbd::SNAP_CREATE_FLAG_SKIP_NOTIFY_QUIESCE, m_prog_ctx, ctx);
}
template <typename I>
#ifndef RBD_MIRROR_IMAGE_SYNC_SYNC_POINT_CREATE_REQUEST_H
#define RBD_MIRROR_IMAGE_SYNC_SYNC_POINT_CREATE_REQUEST_H
+#include "librbd/internal.h"
#include "Types.h"
#include <string>
Context *m_on_finish;
SyncPoints m_sync_points_copy;
+ librbd::NoOpProgressContext m_prog_ctx;
void send_update_sync_points();
void handle_update_sync_points(int r);