const std::string &mirror_uuid,
::journal::MockJournaler *journaler,
librbd::journal::MirrorPeerClientMeta *client_meta,
- Context *on_finish,
+ ContextWQ *work_queue, Context *on_finish,
ProgressContext *progress_ctx = nullptr) {
assert(s_instance != nullptr);
return s_instance;
static SnapshotCreateRequest* s_instance;
static SnapshotCreateRequest* create(librbd::MockImageCtx* image_ctx,
const std::string &snap_name,
- uint64_t size, Context *on_finish) {
+ uint64_t size,
+ const librbd::parent_spec &parent_spec,
+ uint64_t parent_overlap,
+ Context *on_finish) {
assert(s_instance != nullptr);
s_instance->on_finish = on_finish;
return s_instance;
return new MockSnapshotCopyRequest(&mock_local_image_ctx,
&mock_remote_image_ctx, &m_snap_map,
&mock_journaler, &m_client_meta,
- on_finish);
+ m_threads->work_queue, on_finish);
}
int create_snap(librbd::ImageCtx *image_ctx, const std::string &snap_name,
.WillOnce(Return(r));
}
+ void expect_remove_parent(librbd::MockImageCtx &mock_image_ctx, int r) {
+ EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+ exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("remove_parent"), _, _, _))
+ .WillOnce(Return(r));
+ }
+
+ void expect_set_parent(librbd::MockImageCtx &mock_image_ctx, int r) {
+ EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
+ exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("set_parent"), _, _, _))
+ .WillOnce(Return(r));
+ }
+
void expect_snap_create(librbd::MockImageCtx &mock_image_ctx,
const std::string &snap_name, uint64_t snap_id, int r) {
EXPECT_CALL(*mock_image_ctx.operations, execute_snap_create(StrEq(snap_name), _, 0, true))
MockSnapshotCreateRequest *create_request(librbd::MockImageCtx &mock_local_image_ctx,
const std::string &snap_name,
- uint64_t size, Context *on_finish) {
+ uint64_t size,
+ const librbd::parent_spec &spec,
+ uint64_t parent_overlap,
+ Context *on_finish) {
return new MockSnapshotCreateRequest(&mock_local_image_ctx, snap_name, size,
- on_finish);
+ spec, parent_overlap, on_finish);
}
librbd::ImageCtx *m_local_image_ctx;
C_SaferCond ctx;
MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
- "snap1", 123,
+ "snap1", 123, {}, 0,
&ctx);
request->send();
ASSERT_EQ(0, ctx.wait());
C_SaferCond ctx;
MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
- "snap1", 123,
+ "snap1", 123, {}, 0,
&ctx);
request->send();
ASSERT_EQ(-EINVAL, ctx.wait());
}
-TEST_F(TestMockImageSyncSnapshotCreateRequest, SnapCreate) {
+TEST_F(TestMockImageSyncSnapshotCreateRequest, RemoveParent) {
+ librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ mock_local_image_ctx.parent_md.spec.pool_id = 213;
+
+ InSequence seq;
+ expect_remove_parent(mock_local_image_ctx, 0);
+ expect_snap_create(mock_local_image_ctx, "snap1", 10, 0);
+ expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
+
+ C_SaferCond ctx;
+ MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
+ "snap1",
+ m_local_image_ctx->size,
+ {}, 0, &ctx);
+ request->send();
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockImageSyncSnapshotCreateRequest, RemoveParentError) {
+ librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ mock_local_image_ctx.parent_md.spec.pool_id = 213;
+
+ InSequence seq;
+ expect_remove_parent(mock_local_image_ctx, -EINVAL);
+
+ C_SaferCond ctx;
+ MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
+ "snap1",
+ m_local_image_ctx->size,
+ {}, 0, &ctx);
+ request->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
+TEST_F(TestMockImageSyncSnapshotCreateRequest, RemoveSetParent) {
+ librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ mock_local_image_ctx.parent_md.spec.pool_id = 213;
+
+ InSequence seq;
+ expect_remove_parent(mock_local_image_ctx, 0);
+ expect_set_parent(mock_local_image_ctx, 0);
+ expect_snap_create(mock_local_image_ctx, "snap1", 10, 0);
+ expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
+
+ C_SaferCond ctx;
+ MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
+ "snap1",
+ m_local_image_ctx->size,
+ {123, "test", 0}, 0,
+ &ctx);
+ request->send();
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockImageSyncSnapshotCreateRequest, SetParentSpec) {
librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
InSequence seq;
+ expect_set_parent(mock_local_image_ctx, 0);
expect_snap_create(mock_local_image_ctx, "snap1", 10, 0);
expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
"snap1",
m_local_image_ctx->size,
+ {123, "test", 0}, 0,
&ctx);
request->send();
ASSERT_EQ(0, ctx.wait());
}
+TEST_F(TestMockImageSyncSnapshotCreateRequest, SetParentOverlap) {
+ librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ mock_local_image_ctx.parent_md.spec = {123, "test", 0};
+
+ InSequence seq;
+ expect_set_parent(mock_local_image_ctx, 0);
+ expect_snap_create(mock_local_image_ctx, "snap1", 10, 0);
+ expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
+
+ C_SaferCond ctx;
+ MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
+ "snap1",
+ m_local_image_ctx->size,
+ mock_local_image_ctx.parent_md.spec,
+ 123, &ctx);
+ request->send();
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockImageSyncSnapshotCreateRequest, SetParentError) {
+ librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+
+ InSequence seq;
+ expect_set_parent(mock_local_image_ctx, -ESTALE);
+
+ C_SaferCond ctx;
+ MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
+ "snap1",
+ m_local_image_ctx->size,
+ {123, "test", 0}, 0,
+ &ctx);
+ request->send();
+ ASSERT_EQ(-ESTALE, ctx.wait());
+}
+
+TEST_F(TestMockImageSyncSnapshotCreateRequest, SnapCreate) {
+ librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
+
+ InSequence seq;
+ expect_snap_create(mock_local_image_ctx, "snap1", 10, 0);
+ expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
+
+ C_SaferCond ctx;
+ MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
+ "snap1",
+ m_local_image_ctx->size,
+ {}, 0, &ctx);
+ request->send();
+ ASSERT_EQ(0, ctx.wait());
+}
+
TEST_F(TestMockImageSyncSnapshotCreateRequest, SnapCreateError) {
librbd::MockImageCtx mock_local_image_ctx(*m_local_image_ctx);
MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
"snap1",
m_local_image_ctx->size,
- &ctx);
+ {}, 0, &ctx);
request->send();
ASSERT_EQ(-EINVAL, ctx.wait());
}
MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
"snap1",
m_local_image_ctx->size,
- &ctx);
+ {}, 0, &ctx);
request->send();
ASSERT_EQ(0, ctx.wait());
}
MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx,
"snap1",
m_local_image_ctx->size,
- &ctx);
+ {}, 0, &ctx);
request->send();
ASSERT_EQ(-EINVAL, ctx.wait());
}
return new ImageSync<>(m_local_image_ctx, m_remote_image_ctx,
m_threads->timer, &m_threads->timer_lock,
"mirror-uuid", m_remote_journaler, &m_client_meta,
- ctx);
+ m_threads->work_queue, ctx);
}
librbd::ImageCtx *m_remote_image_ctx;
SnapshotCopyRequest<librbd::ImageCtx>::SnapMap *snap_map,
journal::MockJournaler *journaler,
librbd::journal::MirrorPeerClientMeta *client_meta,
+ ContextWQ *work_queue,
Context *on_finish) {
assert(s_instance != nullptr);
s_instance->on_finish = on_finish;
return new MockImageSync(&mock_local_image_ctx, &mock_remote_image_ctx,
m_threads->timer, &m_threads->timer_lock,
"mirror-uuid", &mock_journaler, &m_client_meta,
- ctx);
+ m_threads->work_queue, ctx);
}
librbd::ImageCtx *m_remote_image_ctx;
ImageSync<I>::ImageSync(I *local_image_ctx, I *remote_image_ctx,
SafeTimer *timer, Mutex *timer_lock,
const std::string &mirror_uuid, Journaler *journaler,
- MirrorPeerClientMeta *client_meta, Context *on_finish,
+ MirrorPeerClientMeta *client_meta,
+ ContextWQ *work_queue, Context *on_finish,
ProgressContext *progress_ctx)
: m_local_image_ctx(local_image_ctx), m_remote_image_ctx(remote_image_ctx),
m_timer(timer), m_timer_lock(timer_lock), m_mirror_uuid(mirror_uuid),
- m_journaler(journaler), m_client_meta(client_meta), m_on_finish(on_finish),
+ m_journaler(journaler), m_client_meta(client_meta),
+ m_work_queue(work_queue), m_on_finish(on_finish),
m_progress_ctx(progress_ctx),
m_lock(unique_lock_name("ImageSync::m_lock", this)) {
}
ImageSync<I>, &ImageSync<I>::handle_copy_snapshots>(this);
SnapshotCopyRequest<I> *request = SnapshotCopyRequest<I>::create(
m_local_image_ctx, m_remote_image_ctx, &m_snap_map, m_journaler,
- m_client_meta, ctx);
+ m_client_meta, m_work_queue, ctx);
request->send();
}
#include <vector>
class Context;
+class ContextWQ;
class Mutex;
class SafeTimer;
namespace journal { class Journaler; }
Mutex *timer_lock, const std::string &mirror_uuid,
Journaler *journaler,
MirrorPeerClientMeta *client_meta,
- Context *on_finish,
+ ContextWQ *work_queue, Context *on_finish,
ProgressContext *progress_ctx = nullptr) {
return new ImageSync(local_image_ctx, remote_image_ctx, timer, timer_lock,
- mirror_uuid, journaler, client_meta, on_finish,
- progress_ctx);
+ mirror_uuid, journaler, client_meta, work_queue,
+ on_finish, progress_ctx);
}
ImageSync(ImageCtxT *local_image_ctx, ImageCtxT *remote_image_ctx,
SafeTimer *timer, Mutex *timer_lock, const std::string &mirror_uuid,
Journaler *journaler, MirrorPeerClientMeta *client_meta,
- Context *on_finish, ProgressContext *progress_ctx = nullptr);
+ ContextWQ *work_queue, Context *on_finish,
+ ProgressContext *progress_ctx = nullptr);
void start();
void cancel();
std::string m_mirror_uuid;
Journaler *m_journaler;
MirrorPeerClientMeta *m_client_meta;
+ ContextWQ *m_work_queue;
Context *m_on_finish;
ProgressContext *m_progress_ctx;
m_remote_image_ctx, m_timer,
m_timer_lock,
m_local_mirror_uuid, m_journaler,
- m_client_meta, ctx,
+ m_client_meta, m_work_queue, ctx,
m_progress_ctx);
request->start();
}
#include "SnapshotCopyRequest.h"
#include "SnapshotCreateRequest.h"
#include "common/errno.h"
+#include "common/WorkQueue.h"
#include "journal/Journaler.h"
#include "librbd/Operations.h"
#include "librbd/Utils.h"
SnapMap *snap_map,
Journaler *journaler,
librbd::journal::MirrorPeerClientMeta *meta,
+ ContextWQ *work_queue,
Context *on_finish)
: m_local_image_ctx(local_image_ctx), m_remote_image_ctx(remote_image_ctx),
m_snap_map(snap_map), m_journaler(journaler), m_client_meta(meta),
- m_on_finish(on_finish), m_snap_seqs(meta->snap_seqs) {
+ m_work_queue(work_queue), m_on_finish(on_finish),
+ m_snap_seqs(meta->snap_seqs) {
m_snap_map->clear();
// snap ids ordered from oldest to newest
template <typename I>
void SnapshotCopyRequest<I>::send() {
+ librbd::parent_spec remote_parent_spec;
+ int r = validate_parent(m_remote_image_ctx, &remote_parent_spec);
+ if (r < 0) {
+ derr << ": remote image parent spec mismatch" << dendl;
+ error(r);
+ return;
+ }
+
+ r = validate_parent(m_local_image_ctx, &m_local_parent_spec);
+ if (r < 0) {
+ derr << ": local image parent spec mismatch" << dendl;
+ error(r);
+ return;
+ }
+
send_snap_unprotect();
}
void SnapshotCopyRequest<I>::send_snap_unprotect() {
CephContext *cct = m_local_image_ctx->cct;
- // TODO: issue #14937 needs to add support for cloned images
- m_remote_image_ctx->snap_lock.get_read();
- if (m_remote_image_ctx->parent_md.spec.pool_id != -1 ||
- std::find_if(m_remote_image_ctx->snap_info.begin(),
- m_remote_image_ctx->snap_info.end(),
- [](const std::pair<librados::snap_t, librbd::SnapInfo>& pair) {
- return pair.second.parent.spec.pool_id != -1;
- }) != m_remote_image_ctx->snap_info.end()) {
- lderr(cct) << ": cloned images are not currently supported" << dendl;
- m_remote_image_ctx->snap_lock.put_read();
- finish(-EINVAL);
- return;
- }
- m_remote_image_ctx->snap_lock.put_read();
-
SnapIdSet::iterator snap_id_it = m_local_snap_ids.begin();
if (m_prev_snap_id != CEPH_NOSNAP) {
snap_id_it = m_local_snap_ids.upper_bound(m_prev_snap_id);
finish(-ENOENT);
return;
}
+
uint64_t size = snap_info_it->second.size;
+ librbd::parent_spec parent_spec;
+ uint64_t parent_overlap = 0;
+ if (snap_info_it->second.parent.spec.pool_id != -1) {
+ parent_spec = m_local_parent_spec;
+ parent_overlap = snap_info_it->second.parent.overlap;
+ }
m_remote_image_ctx->snap_lock.put_read();
+
ldout(cct, 20) << ": "
<< "snap_name=" << m_snap_name << ", "
<< "snap_id=" << m_prev_snap_id << ", "
- << "size=" << size << dendl;
+ << "size=" << size << ", "
+ << "parent_info=["
+ << "pool_id=" << parent_spec.pool_id << ", "
+ << "image_id=" << parent_spec.image_id << ", "
+ << "snap_id=" << parent_spec.snap_id << ", "
+ << "overlap=" << parent_overlap << "]" << dendl;
Context *ctx = create_context_callback<
SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::handle_snap_create>(
this);
SnapshotCreateRequest<I> *req = SnapshotCreateRequest<I>::create(
- m_local_image_ctx, m_snap_name, size, ctx);
+ m_local_image_ctx, m_snap_name, size, parent_spec, parent_overlap, ctx);
req->send();
}
finish(0);
}
+template <typename I>
+void SnapshotCopyRequest<I>::error(int r) {
+ dout(20) << ": r=" << r << dendl;
+
+ m_work_queue->queue(create_context_callback<
+ SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::finish>(this), r);
+}
+
template <typename I>
void SnapshotCopyRequest<I>::finish(int r) {
CephContext *cct = m_local_image_ctx->cct;
}
}
+template <typename I>
+int SnapshotCopyRequest<I>::validate_parent(I *image_ctx,
+ librbd::parent_spec *spec) {
+ RWLock::RLocker owner_locker(image_ctx->owner_lock);
+ RWLock::RLocker snap_locker(image_ctx->snap_lock);
+
+ // ensure remote image's parent specs are still consistent
+ *spec = image_ctx->parent_md.spec;
+ for (auto &snap_info_pair : image_ctx->snap_info) {
+ auto &parent_spec = snap_info_pair.second.parent.spec;
+ if (parent_spec.pool_id == -1) {
+ continue;
+ } else if (spec->pool_id == -1) {
+ *spec = parent_spec;
+ continue;
+ }
+
+ if (*spec != parent_spec) {
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
} // namespace image_sync
} // namespace mirror
} // namespace rbd
#include "include/rados/librados.hpp"
#include "common/snap_types.h"
#include "librbd/ImageCtx.h"
+#include "librbd/parent_types.h"
#include "librbd/journal/TypeTraits.h"
#include <map>
#include <set>
#include <tuple>
class Context;
+class ContextWQ;
namespace journal { class Journaler; }
namespace librbd { namespace journal { struct MirrorPeerClientMeta; } }
ImageCtxT *remote_image_ctx,
SnapMap *snap_map, Journaler *journaler,
librbd::journal::MirrorPeerClientMeta *client_meta,
+ ContextWQ *work_queue,
Context *on_finish) {
return new SnapshotCopyRequest(local_image_ctx, remote_image_ctx,
- snap_map, journaler, client_meta, on_finish);
+ snap_map, journaler, client_meta, work_queue,
+ on_finish);
}
SnapshotCopyRequest(ImageCtxT *local_image_ctx, ImageCtxT *remote_image_ctx,
SnapMap *snap_map, Journaler *journaler,
librbd::journal::MirrorPeerClientMeta *client_meta,
- Context *on_finish);
+ ContextWQ *work_queue, Context *on_finish);
void send();
SnapMap *m_snap_map;
Journaler *m_journaler;
librbd::journal::MirrorPeerClientMeta *m_client_meta;
+ ContextWQ *m_work_queue;
Context *m_on_finish;
SnapIdSet m_local_snap_ids;
std::string m_snap_name;
+ librbd::parent_spec m_local_parent_spec;
+
void send_snap_unprotect();
void handle_snap_unprotect(int r);
void send_update_client();
void handle_update_client(int r);
+ void error(int r);
void finish(int r);
void compute_snap_map();
+ int validate_parent(ImageCtxT *image_ctx, librbd::parent_spec *spec);
+
};
} // namespace image_sync
SnapshotCreateRequest<I>::SnapshotCreateRequest(I *local_image_ctx,
const std::string &snap_name,
uint64_t size,
+ const librbd::parent_spec &spec,
+ uint64_t parent_overlap,
Context *on_finish)
: m_local_image_ctx(local_image_ctx), m_snap_name(snap_name), m_size(size),
+ m_parent_spec(spec), m_parent_overlap(parent_overlap),
m_on_finish(on_finish) {
}
template <typename I>
void SnapshotCreateRequest<I>::send_remove_parent() {
- // TODO: issue #14937 needs to add support for cloned images
- if (true) {
- send_snap_create();
+ m_local_image_ctx->parent_lock.get_read();
+ if (m_local_image_ctx->parent_md.spec.pool_id == -1 ||
+ m_local_image_ctx->parent_md.spec == m_parent_spec) {
+ m_local_image_ctx->parent_lock.put_read();
+ send_set_parent();
return;
}
+ m_local_image_ctx->parent_lock.put_read();
CephContext *cct = m_local_image_ctx->cct;
ldout(cct, 20) << dendl;
+ librados::ObjectWriteOperation op;
+ librbd::cls_client::remove_parent(&op);
+
+ librados::AioCompletion *comp = create_rados_safe_callback<
+ SnapshotCreateRequest<I>,
+ &SnapshotCreateRequest<I>::handle_remove_parent>(this);
+ int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid,
+ comp, &op);
+ assert(r == 0);
+ comp->release();
}
template <typename I>
CephContext *cct = m_local_image_ctx->cct;
ldout(cct, 20) << ": r=" << r << dendl;
- // TODO: issue #14937 needs to add support for cloned images
+ if (r < 0) {
+ lderr(cct) << ": failed to remove parent '" << m_snap_name << "': "
+ << cpp_strerror(r) << dendl;
+ finish(r);
+ return;
+ }
+
+ {
+ // adjust in-memory parent now that it's updated on disk
+ RWLock::WLocker parent_locker(m_local_image_ctx->parent_lock);
+ m_local_image_ctx->parent_md.spec = {};
+ m_local_image_ctx->parent_md.overlap = 0;
+ }
+
+ send_set_parent();
}
template <typename I>
void SnapshotCreateRequest<I>::send_set_parent() {
+ m_local_image_ctx->parent_lock.get_read();
+ if (m_local_image_ctx->parent_md.spec == m_parent_spec &&
+ m_local_image_ctx->parent_md.overlap == m_parent_overlap) {
+ m_local_image_ctx->parent_lock.put_read();
+ send_snap_create();
+ return;
+ }
+ m_local_image_ctx->parent_lock.put_read();
+
CephContext *cct = m_local_image_ctx->cct;
ldout(cct, 20) << dendl;
- // TODO: issue #14937 needs to add support for cloned images
+ librados::ObjectWriteOperation op;
+ librbd::cls_client::set_parent(&op, m_parent_spec, m_parent_overlap);
+
+ librados::AioCompletion *comp = create_rados_safe_callback<
+ SnapshotCreateRequest<I>,
+ &SnapshotCreateRequest<I>::handle_set_parent>(this);
+ int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid,
+ comp, &op);
+ assert(r == 0);
+ comp->release();
}
template <typename I>
CephContext *cct = m_local_image_ctx->cct;
ldout(cct, 20) << ": r=" << r << dendl;
- // TODO: issue #14937 needs to add support for cloned images
+ if (r < 0) {
+ lderr(cct) << ": failed to set parent '" << m_snap_name << "': "
+ << cpp_strerror(r) << dendl;
+ finish(r);
+ return;
+ }
+
+ {
+ // adjust in-memory parent now that it's updated on disk
+ RWLock::WLocker parent_locker(m_local_image_ctx->parent_lock);
+ m_local_image_ctx->parent_md.spec = m_parent_spec;
+ m_local_image_ctx->parent_md.overlap = m_parent_overlap;
+ }
+
+ send_snap_create();
}
template <typename I>
#include "include/rados/librados.hpp"
#include "common/snap_types.h"
#include "librbd/ImageCtx.h"
+#include "librbd/parent_types.h"
#include "librbd/journal/TypeTraits.h"
#include <map>
#include <set>
public:
static SnapshotCreateRequest* create(ImageCtxT *local_image_ctx,
const std::string &snap_name,
- uint64_t size, Context *on_finish) {
+ uint64_t size,
+ const librbd::parent_spec &parent_spec,
+ uint64_t parent_overlap,
+ Context *on_finish) {
return new SnapshotCreateRequest(local_image_ctx, snap_name, size,
- on_finish);
+ parent_spec, parent_overlap, on_finish);
}
SnapshotCreateRequest(ImageCtxT *local_image_ctx,
const std::string &snap_name, uint64_t size,
- Context *on_finish);
+ const librbd::parent_spec &parent_spec,
+ uint64_t parent_overlap, Context *on_finish);
void send();
ImageCtxT *m_local_image_ctx;
std::string m_snap_name;
uint64_t m_size;
+ librbd::parent_spec m_parent_spec;
+ uint64_t m_parent_overlap;
Context *m_on_finish;
void send_set_size();