// TODO support clone v2 parent namespaces
parent_io_ctx.set_namespace(dest_md_ctx.get_namespace());
- ImageCtx *src_parent_image_ctx =
- new ImageCtx("", parent_spec.image_id, nullptr, parent_io_ctx, false);
- r = src_parent_image_ctx->state->open(true);
- if (r < 0) {
- if (r != -ENOENT) {
- lderr(cct) << "failed to open source parent image: "
- << cpp_strerror(r) << dendl;
- }
- return r;
- }
-
- C_SaferCond cond;
- src_parent_image_ctx->state->snap_set(parent_spec.snap_id, &cond);
- r = cond.wait();
- if (r < 0) {
- if (r != -ENOENT) {
- lderr(cct) << "failed to set snapshot: " << cpp_strerror(r) << dendl;
- }
- return r;
- }
-
C_SaferCond ctx;
std::string dest_id = util::generate_image_id(dest_md_ctx);
auto *req = image::CloneRequest<I>::create(
- src_parent_image_ctx, dest_md_ctx, destname, dest_id, opts,
- "", "", src->op_work_queue, &ctx);
+ parent_io_ctx, parent_spec.image_id, "", parent_spec.snap_id, dest_md_ctx,
+ destname, dest_id, opts, "", "", src->op_work_queue, &ctx);
req->send();
r = ctx.wait();
- int close_r = src_parent_image_ctx->state->close();
- if (r == 0 && close_r < 0) {
- r = close_r;
- }
}
if (r < 0) {
lderr(cct) << "header creation failed" << dendl;
using util::create_async_context_callback;
template <typename I>
-CloneRequest<I>::CloneRequest(I *p_imctx, IoCtx &c_ioctx,
+CloneRequest<I>::CloneRequest(IoCtx& parent_io_ctx,
+ const std::string& parent_image_id,
+ const std::string& parent_snap_name,
+ uint64_t parent_snap_id,
+ IoCtx &c_ioctx,
const std::string &c_name,
const std::string &c_id,
ImageOptions c_options,
const std::string &non_primary_global_image_id,
const std::string &primary_mirror_uuid,
ContextWQ *op_work_queue, Context *on_finish)
- : m_p_imctx(p_imctx), m_ioctx(c_ioctx), m_name(c_name), m_id(c_id),
- m_opts(c_options),
- m_pspec(m_p_imctx->md_ctx.get_id(), m_p_imctx->id, m_p_imctx->snap_id),
+ : m_parent_io_ctx(parent_io_ctx), m_parent_image_id(parent_image_id),
+ m_parent_snap_name(parent_snap_name), m_parent_snap_id(parent_snap_id),
+ m_ioctx(c_ioctx), m_name(c_name), m_id(c_id), m_opts(c_options),
m_non_primary_global_image_id(non_primary_global_image_id),
m_primary_mirror_uuid(primary_mirror_uuid),
m_op_work_queue(op_work_queue), m_on_finish(on_finish),
m_opts.set(RBD_IMAGE_OPTION_FORMAT, static_cast<uint64_t>(2));
}
- ldout(m_cct, 20) << "clone " << &m_p_imctx->md_ctx << " name " << m_p_imctx->name
- << " snap " << m_p_imctx->snap_name << " to child " << &m_ioctx
- << " name " << m_name << " opts = " << &m_opts << dendl;
- return;
+ ldout(m_cct, 20) << "parent_pool_id=" << parent_io_ctx.get_id() << ", "
+ << "parent_image_id=" << parent_image_id << ", "
+ << "parent_snap=" << parent_snap_name << "/"
+ << parent_snap_id << " clone to "
+ << "pool_id=" << m_ioctx.get_id() << ", "
+ << "name=" << m_name << ", "
+ << "opts=" << m_opts << dendl;
}
template <typename I>
}
}
+ open_parent();
+}
+
+template <typename I>
+void CloneRequest<I>::open_parent() {
+ ldout(m_cct, 20) << dendl;
+
+ m_parent_image_ctx = I::create("", m_parent_image_id, "", m_parent_io_ctx, true);
+
+ Context *ctx = create_context_callback<
+ CloneRequest<I>, &CloneRequest<I>::handle_open_parent>(this);
+ m_parent_image_ctx->state->open(OPEN_FLAG_SKIP_OPEN_PARENT, ctx);
+}
+
+template <typename I>
+void CloneRequest<I>::handle_open_parent(int r) {
+ ldout(m_cct, 20) << "r=" << r << dendl;
+
+ if (r < 0) {
+ m_parent_image_ctx->destroy();
+ m_parent_image_ctx = nullptr;
+
+ lderr(m_cct) << "failed to open parent image: " << cpp_strerror(r) << dendl;
+ complete(r);
+ return;
+ }
+
+ set_parent_snap();
+}
+
+template <typename I>
+void CloneRequest<I>::set_parent_snap() {
+ assert((m_parent_snap_name.empty()) ^ (m_parent_snap_id == CEPH_NOSNAP));
+
+ if (m_parent_snap_id == CEPH_NOSNAP) {
+ // look up user snapshot by name
+ m_parent_image_ctx->snap_lock.get_read();
+ auto it = m_parent_image_ctx->snap_ids.find(
+ {cls::rbd::UserSnapshotNamespace{}, m_parent_snap_name});
+ if (it == m_parent_image_ctx->snap_ids.end()) {
+ m_parent_image_ctx->snap_lock.put_read();
+
+ lderr(m_cct) << "failed to located parent snapshot: " <<
+ m_parent_snap_name << dendl;
+ m_r_saved = -ENOENT;
+ close_parent();
+ return;
+ }
+
+ m_parent_snap_id = it->second;
+ m_parent_image_ctx->snap_lock.put_read();
+ }
+
+ ldout(m_cct, 20) << "parent_snap_id=" << m_parent_snap_id << dendl;
+
+ Context *ctx = create_context_callback<
+ CloneRequest<I>, &CloneRequest<I>::handle_set_parent_snap>(this);
+ m_parent_image_ctx->state->snap_set(m_parent_snap_id, ctx);
+}
+
+template <typename I>
+void CloneRequest<I>::handle_set_parent_snap(int r) {
+ ldout(m_cct, 20) << "r=" << r << dendl;
+
+ if (r < 0) {
+ lderr(m_cct) << "failed to set parent snapshot: " << cpp_strerror(r)
+ << dendl;
+
+ m_r_saved = r;
+ close_parent();
+ return;
+ }
+
+ m_pspec = {m_parent_io_ctx.get_id(), m_parent_image_id, m_parent_snap_id};
validate_parent();
}
void CloneRequest<I>::validate_parent() {
ldout(m_cct, 20) << dendl;
- if (m_p_imctx->operations_disabled) {
+ if (m_parent_image_ctx->operations_disabled) {
lderr(m_cct) << "image operations disabled due to unsupported op features"
<< dendl;
- complete(-EROFS);
+ m_r_saved = -EROFS;
+ close_parent();
return;
}
- if (m_p_imctx->snap_id == CEPH_NOSNAP) {
+ if (m_parent_image_ctx->snap_id == CEPH_NOSNAP) {
lderr(m_cct) << "image to be cloned must be a snapshot" << dendl;
- complete(-EINVAL);
+ m_r_saved = -EINVAL;
+ close_parent();
return;
}
- if (m_p_imctx->old_format) {
+ if (m_parent_image_ctx->old_format) {
lderr(m_cct) << "parent image must be in new format" << dendl;
- complete(-EINVAL);
+ m_r_saved = -EINVAL;
+ close_parent();
return;
}
- int r = 0;
+ m_parent_image_ctx->snap_lock.get_read();
+ uint64_t p_features = m_parent_image_ctx->features;
+ m_size = m_parent_image_ctx->get_image_size(m_parent_image_ctx->snap_id);
+
bool snap_protected;
- m_p_imctx->snap_lock.get_read();
- m_p_features = m_p_imctx->features;
- m_size = m_p_imctx->get_image_size(m_p_imctx->snap_id);
- r = m_p_imctx->is_snap_protected(m_p_imctx->snap_id, &snap_protected);
- m_p_imctx->snap_lock.put_read();
+ int r = m_parent_image_ctx->is_snap_protected(m_parent_image_ctx->snap_id, &snap_protected);
+ m_parent_image_ctx->snap_lock.put_read();
- if ((m_p_features & RBD_FEATURE_LAYERING) != RBD_FEATURE_LAYERING) {
+ if ((p_features & RBD_FEATURE_LAYERING) != RBD_FEATURE_LAYERING) {
lderr(m_cct) << "parent image must support layering" << dendl;
- complete(-ENOSYS);
+ m_r_saved = -ENOSYS;
+ close_parent();
return;
}
+ if (m_use_p_features) {
+ m_features = (p_features & ~RBD_FEATURES_IMPLICIT_ENABLE);
+ }
if (r < 0) {
lderr(m_cct) << "unable to locate parent's snapshot" << dendl;
- complete(r);
+ m_r_saved = r;
+ close_parent();
return;
}
if (m_clone_format == 1 && !snap_protected) {
lderr(m_cct) << "parent snapshot must be protected" << dendl;
- complete(-EINVAL);
+ m_r_saved = -EINVAL;
+ close_parent();
return;
}
void CloneRequest<I>::validate_child() {
ldout(m_cct, 20) << dendl;
+ if ((m_features & RBD_FEATURE_LAYERING) != RBD_FEATURE_LAYERING) {
+ lderr(m_cct) << "cloning image must support layering" << dendl;
+ m_r_saved = -ENOSYS;
+ close_parent();
+ return;
+ }
+
using klass = CloneRequest<I>;
librados::AioCompletion *comp = create_rados_callback<
klass, &klass::handle_validate_child>(this);
if (r != -ENOENT) {
lderr(m_cct) << "rbd image " << m_name << " already exists" << dendl;
- complete(r);
+ m_r_saved = r;
+ close_parent();
return;
}
void CloneRequest<I>::create_child() {
ldout(m_cct, 20) << dendl;
- if (m_use_p_features) {
- m_features = (m_p_features & ~RBD_FEATURES_IMPLICIT_ENABLE);
- }
-
- uint64_t order = m_p_imctx->order;
+ uint64_t order = m_parent_image_ctx->order;
if (m_opts.get(RBD_IMAGE_OPTION_ORDER, &order) != 0) {
m_opts.set(RBD_IMAGE_OPTION_ORDER, order);
}
- if ((m_features & RBD_FEATURE_LAYERING) != RBD_FEATURE_LAYERING) {
- lderr(m_cct) << "cloning image must support layering" << dendl;
- complete(-ENOSYS);
- return;
- }
m_opts.set(RBD_IMAGE_OPTION_FEATURES, m_features);
using klass = CloneRequest<I>;
Context *ctx = create_context_callback<
klass, &klass::handle_create_child>(this);
- RWLock::RLocker snap_locker(m_p_imctx->snap_lock);
+ RWLock::RLocker snap_locker(m_parent_image_ctx->snap_lock);
CreateRequest<I> *req = CreateRequest<I>::create(
m_ioctx, m_name, m_id, m_size, m_opts, m_non_primary_global_image_id,
m_primary_mirror_uuid, true, m_op_work_queue, ctx);
if (r < 0) {
lderr(m_cct) << "error creating child: " << cpp_strerror(r) << dendl;
- complete(r);
+ m_r_saved = r;
+ close_parent();
return;
}
open_child();
ldout(m_cct, 20) << "r=" << r << dendl;
if (r < 0) {
+ m_imctx->destroy();
+ m_imctx = nullptr;
+
lderr(m_cct) << "Error opening new image: " << cpp_strerror(r) << dendl;
m_r_saved = r;
remove_child();
ldout(m_cct, 20) << dendl;
librados::ObjectWriteOperation op;
- cls_client::child_attach(&op, m_p_imctx->snap_id,
+ cls_client::child_attach(&op, m_parent_image_ctx->snap_id,
{m_imctx->md_ctx.get_id(), m_imctx->id});
auto aio_comp = create_rados_callback<
CloneRequest<I>, &CloneRequest<I>::handle_v2_child_attach>(this);
- int r = m_p_imctx->md_ctx.aio_operate(m_p_imctx->header_oid, aio_comp, &op);
+ int r = m_parent_image_ctx->md_ctx.aio_operate(m_parent_image_ctx->header_oid, aio_comp, &op);
assert(r == 0);
aio_comp->release();
}
bool snap_protected = false;
if (r == 0) {
- m_p_imctx->snap_lock.get_read();
- r = m_p_imctx->is_snap_protected(m_p_imctx->snap_id, &snap_protected);
- m_p_imctx->snap_lock.put_read();
+ m_parent_image_ctx->snap_lock.get_read();
+ r = m_parent_image_ctx->is_snap_protected(m_parent_image_ctx->snap_id, &snap_protected);
+ m_parent_image_ctx->snap_lock.put_read();
}
if (r < 0 || !snap_protected) {
librados::AioCompletion *comp =
create_rados_callback<klass, &klass::handle_metadata_list>(this);
m_out_bl.clear();
- m_p_imctx->md_ctx.aio_operate(m_p_imctx->header_oid,
+ m_parent_image_ctx->md_ctx.aio_operate(m_parent_image_ctx->header_oid,
comp, &op, &m_out_bl);
comp->release();
}
if (r < 0) {
lderr(m_cct) << "couldn't close image: " << cpp_strerror(r) << dendl;
- complete(r);
- return;
+ if (m_r_saved == 0) {
+ m_r_saved = r;
+ }
}
- if (m_r_saved == 0) {
- complete(0);
- } else {
+ if (m_r_saved < 0) {
remove_child();
+ return;
}
+
+ close_parent();
}
template <typename I>
lderr(m_cct) << "Error removing failed clone: "
<< cpp_strerror(r) << dendl;
}
+
+ close_parent();
+}
+
+template <typename I>
+void CloneRequest<I>::close_parent() {
+ ldout(m_cct, 20) << dendl;
+ assert(m_parent_image_ctx != nullptr);
+
+ Context *ctx = create_async_context_callback(
+ *m_parent_image_ctx, create_context_callback<
+ CloneRequest<I>, &CloneRequest<I>::handle_close_parent>(this));
+ m_parent_image_ctx->state->close(ctx);
+}
+
+template <typename I>
+void CloneRequest<I>::handle_close_parent(int r) {
+ ldout(m_cct, 20) << "r=" << r << dendl;
+
+ m_parent_image_ctx->destroy();
+ m_parent_image_ctx = nullptr;
+
+ if (r < 0) {
+ lderr(m_cct) << "failed to close parent image: "
+ << cpp_strerror(r) << dendl;
+ if (m_r_saved == 0) {
+ m_r_saved = r;
+ }
+ }
+
complete(m_r_saved);
}
template <typename ImageCtxT = ImageCtx>
class CloneRequest {
public:
- static CloneRequest *create(ImageCtxT *p_imctx, IoCtx &c_ioctx,
- const std::string &c_name,
+ static CloneRequest *create(IoCtx& parent_io_ctx,
+ const std::string& parent_image_id,
+ const std::string& parent_snap_name,
+ uint64_t parent_snap_id,
+ IoCtx &c_ioctx, const std::string &c_name,
const std::string &c_id, ImageOptions c_options,
const std::string &non_primary_global_image_id,
const std::string &primary_mirror_uuid,
ContextWQ *op_work_queue, Context *on_finish) {
- return new CloneRequest(p_imctx, c_ioctx, c_name, c_id, c_options,
+ return new CloneRequest(parent_io_ctx, parent_image_id, parent_snap_name,
+ parent_snap_id, c_ioctx, c_name, c_id, c_options,
non_primary_global_image_id, primary_mirror_uuid,
op_work_queue, on_finish);
}
- CloneRequest(ImageCtxT *p_imctx, IoCtx &c_ioctx, const std::string &c_name,
+ CloneRequest(IoCtx& parent_io_ctx,
+ const std::string& parent_image_id,
+ const std::string& parent_snap_name,
+ uint64_t parent_snap_id,
+ IoCtx &c_ioctx, const std::string &c_name,
const std::string &c_id, ImageOptions c_options,
const std::string &non_primary_global_image_id,
const std::string &primary_mirror_uuid,
ContextWQ *op_work_queue, Context *on_finish);
void send();
+
private:
/**
* @verbatim
* <start>
* |
* v
- * VALIDATE CHILD
- * |
- * v
- * CREATE CHILD <finish>
+ * OPEN PARENT <finish>
* | ^
* v |
+ * SET PARENT SNAP * * * * * * * > CLOSE PARENT
+ * | * ^
+ * v * |
+ * VALIDATE CHILD * |
+ * | * |
+ * v * |
+ * CREATE CHILD * * * * * * * * |
+ * | |
+ * v |
* OPEN CHILD * * * * * * * * * * > REMOVE CHILD
* | ^
* v |
- * SET PARENT * * * * * * * * * * > CLOSE IMAGE
+ * SET PARENT * * * * * * * * * * > CLOSE CHILD
* | ^
* |\--------\ *
* | | *
* SET MIRROR ENABLED * * * * * * * * *
* |
* v
- * CLOSE IMAGE
+ * CLOSE CHILD
+ * |
+ * v
+ * CLOSE PARENT
* |
* v
* <finish>
* @endverbatim
*/
- ImageCtxT *m_p_imctx;
+ IoCtx &m_parent_io_ctx;
+ std::string m_parent_image_id;
+ std::string m_parent_snap_name;
+ uint64_t m_parent_snap_id;
+ ImageCtxT *m_parent_image_ctx;
+
IoCtx &m_ioctx;
std::string m_name;
std::string m_id;
CephContext *m_cct;
uint32_t m_clone_format = 2;
bool m_use_p_features;
- uint64_t m_p_features;
uint64_t m_features;
map<string, bufferlist> m_pairs;
std::string m_last_metadata_key;
int m_r_saved = 0;
void validate_options();
+
+ void open_parent();
+ void handle_open_parent(int r);
+
+ void set_parent_snap();
+ void handle_set_parent_snap(int r);
+
void validate_parent();
void validate_child();
void remove_child();
void handle_remove_child(int r);
+ void close_parent();
+ void handle_close_parent(int r);
+
void complete(int r);
};
opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit);
opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count);
- int r = clone(p_ioctx, p_name, p_snap_name, c_ioctx, c_name, opts);
+ int r = clone(p_ioctx, nullptr, p_name, p_snap_name, c_ioctx, nullptr,
+ c_name, opts, "", "");
opts.get(RBD_IMAGE_OPTION_ORDER, &order);
*c_order = order;
return r;
}
- int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
- IoCtx& c_ioctx, const char *c_name, ImageOptions& c_opts)
+ int clone(IoCtx& p_ioctx, const char *p_id, const char *p_name,
+ const char *p_snap_name, IoCtx& c_ioctx, const char *c_id,
+ const char *c_name, ImageOptions& c_opts,
+ const std::string &non_primary_global_image_id,
+ const std::string &primary_mirror_uuid)
{
+ assert((p_id == nullptr) ^ (p_name == nullptr));
+
CephContext *cct = (CephContext *)p_ioctx.cct();
- if (p_snap_name == NULL) {
+ if (p_snap_name == nullptr) {
lderr(cct) << "image to be cloned must be a snapshot" << dendl;
return -EINVAL;
}
return -EINVAL;
}
- // make sure parent snapshot exists
- ImageCtx *p_imctx = new ImageCtx(p_name, "", p_snap_name, p_ioctx, true);
- int r = p_imctx->state->open(0);
- if (r < 0) {
- lderr(cct) << "error opening parent image: "
- << cpp_strerror(r) << dendl;
- return r;
- }
-
- r = clone(p_imctx, c_ioctx, c_name, "", c_opts, "", "");
-
- int close_r = p_imctx->state->close();
- if (r == 0 && close_r < 0) {
- r = close_r;
- }
-
- if (r < 0) {
- return r;
+ int r;
+ std::string parent_id;
+ if (p_id == nullptr) {
+ r = cls_client::dir_get_id(&p_ioctx, RBD_DIRECTORY, p_name,
+ &parent_id);
+ if (r < 0) {
+ if (r != -ENOENT) {
+ lderr(cct) << "failed to retrieve parent image id: "
+ << cpp_strerror(r) << dendl;
+ }
+ return r;
+ }
+ } else {
+ parent_id = p_id;
}
- return 0;
- }
- int clone(ImageCtx *p_imctx, IoCtx& c_ioctx, const std::string &c_name,
- const std::string &c_id, ImageOptions& c_opts,
- const std::string &non_primary_global_image_id,
- const std::string &primary_mirror_uuid)
- {
- std::string id(c_id);
- if (id.empty()) {
- id = util::generate_image_id(c_ioctx);
+ std::string clone_id;
+ if (c_id == nullptr) {
+ clone_id = util::generate_image_id(c_ioctx);
+ } else {
+ clone_id = c_id;
}
- CephContext *cct = (CephContext *)c_ioctx.cct();
ldout(cct, 10) << __func__ << " "
<< "c_name=" << c_name << ", "
- << "c_id= " << c_id << ", "
+ << "c_id= " << clone_id << ", "
<< "c_opts=" << c_opts << dendl;
ThreadPool *thread_pool;
C_SaferCond cond;
auto *req = image::CloneRequest<>::create(
- p_imctx, c_ioctx, c_name, id, c_opts,
- non_primary_global_image_id, primary_mirror_uuid, op_work_queue, &cond);
+ p_ioctx, parent_id, p_snap_name, CEPH_NOSNAP, c_ioctx, c_name, clone_id,
+ c_opts, non_primary_global_image_id, primary_mirror_uuid, op_work_queue,
+ &cond);
req->send();
- return cond.wait();
+ r = cond.wait();
+ if (r < 0) {
+ return r;
+ }
+
+ return 0;
}
int rename(IoCtx& io_ctx, const char *srcname, const char *dstname)
IoCtx& c_ioctx, const char *c_name,
uint64_t features, int *c_order,
uint64_t stripe_unit, int stripe_count);
- int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
- IoCtx& c_ioctx, const char *c_name, ImageOptions& c_opts);
- int clone(ImageCtx *p_imctx, IoCtx& c_ioctx, const std::string &c_name,
- const std::string &c_id, ImageOptions& c_opts,
+ int clone(IoCtx& p_ioctx, const char *p_id, const char *p_name,
+ const char *p_snap_name, IoCtx& c_ioctx, const char *c_id,
+ const char *c_name, ImageOptions& c_opts,
const std::string &non_primary_global_image_id,
const std::string &primary_mirror_uuid);
int rename(librados::IoCtx& io_ctx, const char *srcname, const char *dstname);
{
TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioctx));
tracepoint(librbd, clone3_enter, p_ioctx.get_pool_name().c_str(), p_ioctx.get_id(), p_name, p_snap_name, c_ioctx.get_pool_name().c_str(), c_ioctx.get_id(), c_name, c_opts.opts);
- int r = librbd::clone(p_ioctx, p_name, p_snap_name, c_ioctx, c_name,
- c_opts);
+ int r = librbd::clone(p_ioctx, nullptr, p_name, p_snap_name, c_ioctx,
+ nullptr, c_name, c_opts, "", "");
tracepoint(librbd, clone3_exit, r);
return r;
}
TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioc));
tracepoint(librbd, clone3_enter, p_ioc.get_pool_name().c_str(), p_ioc.get_id(), p_name, p_snap_name, c_ioc.get_pool_name().c_str(), c_ioc.get_id(), c_name, c_opts);
librbd::ImageOptions c_opts_(c_opts);
- int r = librbd::clone(p_ioc, p_name, p_snap_name, c_ioc, c_name, c_opts_);
+ int r = librbd::clone(p_ioc, nullptr, p_name, p_snap_name, c_ioc, nullptr,
+ c_name, c_opts_, "", "");
tracepoint(librbd, clone3_exit, r);
return r;
}
.WillOnce(WithArg<1>(Invoke([this, r](Context* ctx) {
image_ctx->op_work_queue->queue(ctx, r);
})));
+ if (r < 0) {
+ EXPECT_CALL(mock_image_ctx, destroy());
+ }
+ }
+
+ void expect_snap_set(librbd::MockTestImageCtx &mock_image_ctx,
+ uint64_t snap_id, int r) {
+ EXPECT_CALL(*mock_image_ctx.state, snap_set(snap_id, _))
+ .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) {
+ image_ctx->op_work_queue->queue(on_finish, r);
+ })));
}
void expect_set_parent(MockImageCtx &mock_image_ctx, int r) {
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, false);
}
+ expect_close(mock_image_ctx, 0);
expect_close(mock_image_ctx, 0);
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, false);
}
+ expect_close(mock_image_ctx, 0);
expect_close(mock_image_ctx, 0);
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
InSequence seq;
expect_get_min_compat_client(1, 0);
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, false);
}
+ expect_close(mock_image_ctx, 0);
expect_close(mock_image_ctx, 0);
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
+TEST_F(TestMockImageCloneRequest, OpenParentError) {
+ REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
+
+ MockTestImageCtx mock_image_ctx(*image_ctx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_open(mock_image_ctx, -EINVAL);
+
+ C_SaferCond ctx;
+ ImageOptions clone_opts;
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
+ image_ctx->op_work_queue, &ctx);
+ req->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
+TEST_F(TestMockImageCloneRequest, SetParentSnapError) {
+ REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
+
+ MockTestImageCtx mock_image_ctx(*image_ctx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, -EINVAL);
+ expect_close(mock_image_ctx, 0);
+
+ C_SaferCond ctx;
+ ImageOptions clone_opts;
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
+ image_ctx->op_work_queue, &ctx);
+ req->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
TEST_F(TestMockImageCloneRequest, CreateError) {
REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
MockCreateRequest mock_create_request;
expect_create(mock_create_request, -EINVAL);
+ expect_close(mock_image_ctx, 0);
+
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(-EINVAL, ctx.wait());
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
MockRemoveRequest mock_remove_request;
expect_remove(mock_remove_request, 0);
+ expect_close(mock_image_ctx, 0);
+
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(-EINVAL, ctx.wait());
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
MockRemoveRequest mock_remove_request;
expect_remove(mock_remove_request, 0);
+ expect_close(mock_image_ctx, 0);
+
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(-EINVAL, ctx.wait());
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
MockRemoveRequest mock_remove_request;
expect_remove(mock_remove_request, 0);
+ expect_close(mock_image_ctx, 0);
+
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(-EINVAL, ctx.wait());
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
MockRemoveRequest mock_remove_request;
expect_remove(mock_remove_request, 0);
+ expect_close(mock_image_ctx, 0);
+
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(-EINVAL, ctx.wait());
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
MockRemoveRequest mock_remove_request;
expect_remove(mock_remove_request, 0);
+ expect_close(mock_image_ctx, 0);
+
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(-EINVAL, ctx.wait());
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
MockRemoveRequest mock_remove_request;
expect_remove(mock_remove_request, 0);
+ expect_close(mock_image_ctx, 0);
+
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(-EINVAL, ctx.wait());
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
MockRemoveRequest mock_remove_request;
expect_remove(mock_remove_request, 0);
+ expect_close(mock_image_ctx, 0);
+
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(-EINVAL, ctx.wait());
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
MockRemoveRequest mock_remove_request;
expect_remove(mock_remove_request, 0);
+ expect_close(mock_image_ctx, 0);
+
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(-EINVAL, ctx.wait());
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
expect_close(mock_image_ctx, -EINVAL);
+ MockRemoveRequest mock_remove_request;
+ expect_remove(mock_remove_request, 0);
+
+ expect_close(mock_image_ctx, 0);
+
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(-EINVAL, ctx.wait());
expect_op_work_queue(mock_image_ctx);
InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
expect_is_snap_protected(mock_image_ctx, true, 0);
MockRemoveRequest mock_remove_request;
expect_remove(mock_remove_request, -EPERM);
+ expect_close(mock_image_ctx, 0);
+
+ C_SaferCond ctx;
+ ImageOptions clone_opts;
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
+ image_ctx->op_work_queue, &ctx);
+ req->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
+TEST_F(TestMockImageCloneRequest, CloseParentError) {
+ REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
+
+ MockTestImageCtx mock_image_ctx(*image_ctx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_open(mock_image_ctx, 0);
+ expect_snap_set(mock_image_ctx, 123, 0);
+
+ expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
+ expect_is_snap_protected(mock_image_ctx, true, 0);
+
+ MockCreateRequest mock_create_request;
+ expect_create(mock_create_request, 0);
+
+ expect_open(mock_image_ctx, -EINVAL);
+
+ MockRemoveRequest mock_remove_request;
+ expect_remove(mock_remove_request, 0);
+
+ expect_close(mock_image_ctx, -EPERM);
+
C_SaferCond ctx;
ImageOptions clone_opts;
- auto req = new MockCloneRequest(&mock_image_ctx, m_ioctx, "clone name",
- "clone id", clone_opts, "", "",
+ auto req = new MockCloneRequest(m_ioctx, "parent id", "", 123, m_ioctx,
+ "clone name", "clone id", clone_opts, "", "",
image_ctx->op_work_queue, &ctx);
req->send();
ASSERT_EQ(-EINVAL, ctx.wait());
static CloneRequest *s_instance;
Context *on_finish = nullptr;
- static CloneRequest *create(librbd::MockTestImageCtx *p_imctx,
+ static CloneRequest *create(IoCtx &p_ioctx, const std::string &p_id,
+ const std::string &p_snap_name,
+ uint64_t p_snap_id,
IoCtx &c_ioctx, const std::string &c_name,
const std::string &c_id, ImageOptions c_options,
const std::string &non_primary_global_image_id,
const std::string &primary_mirror_uuid,
- MockContextWQ *op_work_queue, Context *on_finish) {
+ MockContextWQ *op_work_queue,
+ Context *on_finish) {
assert(s_instance != nullptr);
s_instance->on_finish = on_finish;
- s_instance->construct(p_imctx);
+ s_instance->construct();
return s_instance;
}
}
MOCK_METHOD0(send, void());
- MOCK_METHOD1(construct, void(librbd::MockTestImageCtx *p_imctx));
+ MOCK_METHOD0(construct, void());
};
CloneRequest<librbd::MockTestImageCtx>*
}));
}
- void expect_snap_set(librbd::MockTestImageCtx &mock_image_ctx,
- const std::string &snap_name, int r) {
- EXPECT_CALL(*mock_image_ctx.state, snap_set(_, _))
- .WillOnce(Invoke([this, &mock_image_ctx, snap_name, r](uint64_t snap_id, Context *on_finish) {
- RWLock::RLocker snap_locker(mock_image_ctx.snap_lock);
- auto id = mock_image_ctx.image_ctx->get_snap_id(
- cls::rbd::UserSnapshotNamespace{}, snap_name);
- ASSERT_EQ(snap_id, id);
- m_threads->work_queue->queue(on_finish, r);
- }));
- }
-
void expect_clone_image(MockCloneRequest &mock_clone_request,
- librbd::MockTestImageCtx &mock_parent_imctx,
int r) {
- EXPECT_CALL(mock_clone_request, construct(&mock_parent_imctx));
+ EXPECT_CALL(mock_clone_request, construct());
EXPECT_CALL(mock_clone_request, send())
.WillOnce(Invoke([this, &mock_clone_request, r]() {
m_threads->work_queue->queue(mock_clone_request.on_finish, r);
&remote_clone_image_ctx));
librbd::MockTestImageCtx mock_remote_parent_image_ctx(*m_remote_image_ctx);
- librbd::MockTestImageCtx mock_local_parent_image_ctx(*local_image_ctx);
librbd::MockTestImageCtx mock_remote_clone_image_ctx(*remote_clone_image_ctx);
MockCloneRequest mock_clone_request;
MockOpenImageRequest mock_open_image_request;
expect_open_image(mock_open_image_request, m_remote_io_ctx,
m_remote_image_ctx->id, mock_remote_parent_image_ctx, 0);
- expect_open_image(mock_open_image_request, m_local_io_ctx,
- "local parent id", mock_local_parent_image_ctx, 0);
- expect_snap_set(mock_local_parent_image_ctx, "snap", 0);
- expect_clone_image(mock_clone_request, mock_local_parent_image_ctx, 0);
- expect_close_image(mock_close_image_request, mock_local_parent_image_ctx, 0);
+ expect_clone_image(mock_clone_request, 0);
expect_close_image(mock_close_image_request, mock_remote_parent_image_ctx, 0);
C_SaferCond ctx;
ASSERT_EQ(-ENOENT, ctx.wait());
}
-TEST_F(TestMockImageReplayerCreateImageRequest, CloneOpenLocalParentError) {
- librbd::RBD rbd;
- librbd::ImageCtx *local_image_ctx;
- ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size));
- ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &local_image_ctx));
-
- std::string clone_image_name = get_temp_image_name();
- ASSERT_EQ(0, clone_image(m_remote_image_ctx, "snap", clone_image_name));
-
- librbd::ImageCtx *remote_clone_image_ctx;
- ASSERT_EQ(0, open_image(m_remote_io_ctx, clone_image_name,
- &remote_clone_image_ctx));
-
- librbd::MockTestImageCtx mock_remote_parent_image_ctx(*m_remote_image_ctx);
- librbd::MockTestImageCtx mock_local_parent_image_ctx(*local_image_ctx);
- librbd::MockTestImageCtx mock_remote_clone_image_ctx(*remote_clone_image_ctx);
- MockCloneRequest mock_clone_request;
- MockOpenImageRequest mock_open_image_request;
- MockCloseImageRequest mock_close_image_request;
-
- InSequence seq;
- expect_ioctx_create(m_remote_io_ctx);
- expect_ioctx_create(m_local_io_ctx);
- expect_get_parent_global_image_id(m_remote_io_ctx, "global uuid", 0);
- expect_mirror_image_get_image_id(m_local_io_ctx, "local parent id", 0);
-
- expect_open_image(mock_open_image_request, m_remote_io_ctx,
- m_remote_image_ctx->id, mock_remote_parent_image_ctx, 0);
- expect_open_image(mock_open_image_request, m_local_io_ctx,
- "local parent id", mock_local_parent_image_ctx, -ENOENT);
- expect_close_image(mock_close_image_request, mock_remote_parent_image_ctx, 0);
-
- C_SaferCond ctx;
- MockCreateImageRequest *request = create_request("global uuid", "remote uuid",
- "image name", "101241a7c4c9",
- mock_remote_clone_image_ctx,
- &ctx);
- request->send();
- ASSERT_EQ(-ENOENT, ctx.wait());
-}
-
-TEST_F(TestMockImageReplayerCreateImageRequest, CloneSnapSetError) {
- librbd::RBD rbd;
- librbd::ImageCtx *local_image_ctx;
- ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size));
- ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &local_image_ctx));
- snap_create(local_image_ctx, "snap");
-
- std::string clone_image_name = get_temp_image_name();
- ASSERT_EQ(0, clone_image(m_remote_image_ctx, "snap", clone_image_name));
-
- librbd::ImageCtx *remote_clone_image_ctx;
- ASSERT_EQ(0, open_image(m_remote_io_ctx, clone_image_name,
- &remote_clone_image_ctx));
-
- librbd::MockTestImageCtx mock_remote_parent_image_ctx(*m_remote_image_ctx);
- librbd::MockTestImageCtx mock_local_parent_image_ctx(*local_image_ctx);
- librbd::MockTestImageCtx mock_remote_clone_image_ctx(*remote_clone_image_ctx);
- MockCloneRequest mock_clone_request;
- MockOpenImageRequest mock_open_image_request;
- MockCloseImageRequest mock_close_image_request;
-
- InSequence seq;
- expect_ioctx_create(m_remote_io_ctx);
- expect_ioctx_create(m_local_io_ctx);
- expect_get_parent_global_image_id(m_remote_io_ctx, "global uuid", 0);
- expect_mirror_image_get_image_id(m_local_io_ctx, "local parent id", 0);
-
- expect_open_image(mock_open_image_request, m_remote_io_ctx,
- m_remote_image_ctx->id, mock_remote_parent_image_ctx, 0);
- expect_open_image(mock_open_image_request, m_local_io_ctx,
- "local parent id", mock_local_parent_image_ctx, 0);
- expect_snap_set(mock_local_parent_image_ctx, "snap", -ENOENT);
- expect_close_image(mock_close_image_request, mock_local_parent_image_ctx, 0);
- expect_close_image(mock_close_image_request, mock_remote_parent_image_ctx, 0);
-
- C_SaferCond ctx;
- MockCreateImageRequest *request = create_request("global uuid", "remote uuid",
- "image name", "101241a7c4c9",
- mock_remote_clone_image_ctx,
- &ctx);
- request->send();
- ASSERT_EQ(-ENOENT, ctx.wait());
-}
-
TEST_F(TestMockImageReplayerCreateImageRequest, CloneError) {
librbd::RBD rbd;
librbd::ImageCtx *local_image_ctx;
&remote_clone_image_ctx));
librbd::MockTestImageCtx mock_remote_parent_image_ctx(*m_remote_image_ctx);
- librbd::MockTestImageCtx mock_local_parent_image_ctx(*local_image_ctx);
librbd::MockTestImageCtx mock_remote_clone_image_ctx(*remote_clone_image_ctx);
MockCloneRequest mock_clone_request;
MockOpenImageRequest mock_open_image_request;
expect_open_image(mock_open_image_request, m_remote_io_ctx,
m_remote_image_ctx->id, mock_remote_parent_image_ctx, 0);
- expect_open_image(mock_open_image_request, m_local_io_ctx,
- "local parent id", mock_local_parent_image_ctx, 0);
- expect_snap_set(mock_local_parent_image_ctx, "snap", 0);
- expect_clone_image(mock_clone_request, mock_local_parent_image_ctx, -EINVAL);
- expect_close_image(mock_close_image_request, mock_local_parent_image_ctx, 0);
+ expect_clone_image(mock_clone_request, -EINVAL);
expect_close_image(mock_close_image_request, mock_remote_parent_image_ctx, 0);
C_SaferCond ctx;
ASSERT_EQ(-EINVAL, ctx.wait());
}
-TEST_F(TestMockImageReplayerCreateImageRequest, CloneLocalParentCloseError) {
- librbd::RBD rbd;
- librbd::ImageCtx *local_image_ctx;
- ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size));
- ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &local_image_ctx));
- snap_create(local_image_ctx, "snap");
-
- std::string clone_image_name = get_temp_image_name();
- ASSERT_EQ(0, clone_image(m_remote_image_ctx, "snap", clone_image_name));
-
- librbd::ImageCtx *remote_clone_image_ctx;
- ASSERT_EQ(0, open_image(m_remote_io_ctx, clone_image_name,
- &remote_clone_image_ctx));
-
- librbd::MockTestImageCtx mock_remote_parent_image_ctx(*m_remote_image_ctx);
- librbd::MockTestImageCtx mock_local_parent_image_ctx(*local_image_ctx);
- librbd::MockTestImageCtx mock_remote_clone_image_ctx(*remote_clone_image_ctx);
- MockCloneRequest mock_clone_request;
- MockOpenImageRequest mock_open_image_request;
- MockCloseImageRequest mock_close_image_request;
-
- InSequence seq;
- expect_ioctx_create(m_remote_io_ctx);
- expect_ioctx_create(m_local_io_ctx);
- expect_get_parent_global_image_id(m_remote_io_ctx, "global uuid", 0);
- expect_mirror_image_get_image_id(m_local_io_ctx, "local parent id", 0);
-
- expect_open_image(mock_open_image_request, m_remote_io_ctx,
- m_remote_image_ctx->id, mock_remote_parent_image_ctx, 0);
- expect_open_image(mock_open_image_request, m_local_io_ctx,
- "local parent id", mock_local_parent_image_ctx, 0);
- expect_snap_set(mock_local_parent_image_ctx, "snap", 0);
- expect_clone_image(mock_clone_request, mock_local_parent_image_ctx, 0);
- expect_close_image(mock_close_image_request, mock_local_parent_image_ctx, -EINVAL);
- expect_close_image(mock_close_image_request, mock_remote_parent_image_ctx, 0);
-
- C_SaferCond ctx;
- MockCreateImageRequest *request = create_request("global uuid", "remote uuid",
- "image name", "101241a7c4c9",
- mock_remote_clone_image_ctx,
- &ctx);
- request->send();
- ASSERT_EQ(0, ctx.wait());
-}
-
TEST_F(TestMockImageReplayerCreateImageRequest, CloneRemoteParentCloseError) {
librbd::RBD rbd;
librbd::ImageCtx *local_image_ctx;
&remote_clone_image_ctx));
librbd::MockTestImageCtx mock_remote_parent_image_ctx(*m_remote_image_ctx);
- librbd::MockTestImageCtx mock_local_parent_image_ctx(*local_image_ctx);
librbd::MockTestImageCtx mock_remote_clone_image_ctx(*remote_clone_image_ctx);
MockCloneRequest mock_clone_request;
MockOpenImageRequest mock_open_image_request;
expect_open_image(mock_open_image_request, m_remote_io_ctx,
m_remote_image_ctx->id, mock_remote_parent_image_ctx, 0);
- expect_open_image(mock_open_image_request, m_local_io_ctx,
- "local parent id", mock_local_parent_image_ctx, 0);
- expect_snap_set(mock_local_parent_image_ctx, "snap", 0);
- expect_clone_image(mock_clone_request, mock_local_parent_image_ctx, 0);
- expect_close_image(mock_close_image_request, mock_local_parent_image_ctx, 0);
+ expect_clone_image(mock_clone_request, 0);
expect_close_image(mock_close_image_request, mock_remote_parent_image_ctx, -EINVAL);
C_SaferCond ctx;
std::string clone_id = librbd::util::generate_image_id(m_local_io_ctx);
librbd::ImageOptions clone_opts;
clone_opts.set(RBD_IMAGE_OPTION_FEATURES, ictx->features);
- EXPECT_EQ(0, librbd::clone(ictx, m_local_io_ctx, "clone1", clone_id,
- clone_opts, GLOBAL_CLONE_IMAGE_ID,
- m_remote_mirror_uuid));
+ EXPECT_EQ(0, librbd::clone(m_local_io_ctx, m_local_image_id.c_str(),
+ nullptr, "snap1", m_local_io_ctx,
+ clone_id.c_str(), "clone1", clone_opts,
+ GLOBAL_CLONE_IMAGE_ID, m_remote_mirror_uuid));
cls::rbd::MirrorImage mirror_image(
GLOBAL_CLONE_IMAGE_ID, MirrorImageState::MIRROR_IMAGE_STATE_ENABLED);
return;
}
- open_local_parent_image();
+ clone_image();
}
template <typename I>
-void CreateImageRequest<I>::open_local_parent_image() {
+void CreateImageRequest<I>::clone_image() {
dout(20) << dendl;
- Context *ctx = create_context_callback<
- CreateImageRequest<I>,
- &CreateImageRequest<I>::handle_open_local_parent_image>(this);
- OpenImageRequest<I> *request = OpenImageRequest<I>::create(
- m_local_parent_io_ctx, &m_local_parent_image_ctx,
- m_local_parent_spec.image_id, true, ctx);
- request->send();
-}
-
-template <typename I>
-void CreateImageRequest<I>::handle_open_local_parent_image(int r) {
- dout(20) << ": r=" << r << dendl;
- if (r < 0) {
- derr << ": failed to open local parent image " << m_parent_pool_name << "/"
- << m_local_parent_spec.image_id << dendl;
- m_ret_val = r;
- close_remote_parent_image();
- return;
- }
-
- set_local_parent_snap();
-}
-
-template <typename I>
-void CreateImageRequest<I>::set_local_parent_snap() {
std::string snap_name;
cls::rbd::SnapshotNamespace snap_namespace;
{
}
}
- if (snap_name.empty()) {
- dout(15) << ": failed to locate remote parent snapshot" << dendl;
- m_ret_val = -ENOENT;
- close_local_parent_image();
- return;
- }
-
- m_local_parent_spec.snap_id = CEPH_NOSNAP;
- {
- RWLock::RLocker local_snap_locker(m_local_parent_image_ctx->snap_lock);
- auto it = m_local_parent_image_ctx->snap_ids.find(
- {snap_namespace, snap_name});
- if (it != m_local_parent_image_ctx->snap_ids.end()) {
- m_local_parent_spec.snap_id = it->second;
- }
- }
-
- if (m_local_parent_spec.snap_id == CEPH_NOSNAP) {
- dout(15) << ": failed to locate local parent snapshot" << dendl;
- m_ret_val = -ENOENT;
- close_local_parent_image();
- return;
- }
-
- dout(15) << ": local_snap_id=" << m_local_parent_spec.snap_id << dendl;
-
- Context *ctx = create_context_callback<
- CreateImageRequest<I>,
- &CreateImageRequest<I>::handle_set_local_parent_snap>(this);
- m_local_parent_image_ctx->state->snap_set(m_local_parent_spec.snap_id, ctx);
-}
-
-template <typename I>
-void CreateImageRequest<I>::handle_set_local_parent_snap(int r) {
- dout(20) << ": r=" << r << dendl;
- if (r < 0) {
- derr << ": failed to set parent snapshot " << m_local_parent_spec.snap_id
- << ": " << cpp_strerror(r) << dendl;
- m_ret_val = r;
- close_local_parent_image();
- return;
- }
-
- clone_image();
-}
-
-template <typename I>
-void CreateImageRequest<I>::clone_image() {
- dout(20) << dendl;
-
librbd::ImageOptions opts;
populate_image_options(&opts);
using klass = CreateImageRequest<I>;
- Context *ctx = create_context_callback<klass, &klass::handle_clone_image>(this);
+ Context *ctx = create_context_callback<
+ klass, &klass::handle_clone_image>(this);
librbd::image::CloneRequest<I> *req = librbd::image::CloneRequest<I>::create(
- m_local_parent_image_ctx, m_local_io_ctx, m_local_image_name,
- m_local_image_id, opts, m_global_image_id, m_remote_mirror_uuid,
- m_remote_image_ctx->op_work_queue, ctx);
+ m_local_parent_io_ctx, m_local_parent_spec.image_id, snap_name, CEPH_NOSNAP,
+ m_local_io_ctx, m_local_image_name, m_local_image_id, opts,
+ m_global_image_id, m_remote_mirror_uuid, m_remote_image_ctx->op_work_queue,
+ ctx);
req->send();
}
dout(20) << ": r=" << r << dendl;
if (r < 0) {
derr << ": failed to clone image " << m_parent_pool_name << "/"
- << m_local_parent_image_ctx->name << " to "
+ << m_remote_parent_spec.image_id << " to "
<< m_local_image_name << dendl;
m_ret_val = r;
}
- close_local_parent_image();
-}
-
-template <typename I>
-void CreateImageRequest<I>::close_local_parent_image() {
- dout(20) << dendl;
- Context *ctx = create_context_callback<
- CreateImageRequest<I>,
- &CreateImageRequest<I>::handle_close_local_parent_image>(this);
- CloseImageRequest<I> *request = CloseImageRequest<I>::create(
- &m_local_parent_image_ctx, ctx);
- request->send();
-}
-
-template <typename I>
-void CreateImageRequest<I>::handle_close_local_parent_image(int r) {
- dout(20) << ": r=" << r << dendl;
- if (r < 0) {
- derr << ": error encountered closing local parent image: "
- << cpp_strerror(r) << dendl;
- }
-
close_remote_parent_image();
}
* OPEN_REMOTE_PARENT * * * * * * * | * * * *
* | | * *
* v | *
- * OPEN_LOCAL_PARENT * * * * * * * | *
- * | * | *
- * v * | *
- * SET_LOCAL_PARENT_SNAP * | *
- * | * * | *
- * v * * | *
- * CLONE_IMAGE * * | *
- * | * * | *
- * v v * | *
- * CLOSE_LOCAL_PARENT * | *
- * | * | *
- * v * | *
- * CLOSE_REMOTE_PARENT < * * * * * | *
+ * CLONE_IMAGE | *
+ * | | *
+ * v | *
+ * CLOSE_REMOTE_PARENT | *
* | v *
* \------------------------> <finish> < * *
* @endverbatim
librbd::ParentSpec m_remote_parent_spec;
librados::IoCtx m_local_parent_io_ctx;
- ImageCtxT *m_local_parent_image_ctx = nullptr;
librbd::ParentSpec m_local_parent_spec;
bufferlist m_out_bl;
void open_remote_parent_image();
void handle_open_remote_parent_image(int r);
- void open_local_parent_image();
- void handle_open_local_parent_image(int r);
-
- void set_local_parent_snap();
- void handle_set_local_parent_snap(int r);
-
void clone_image();
void handle_clone_image(int r);
- void close_local_parent_image();
- void handle_close_local_parent_image(int r);
-
void close_remote_parent_image();
void handle_close_remote_parent_image(int r);