From: Jason Dillaman Date: Thu, 26 May 2016 12:22:16 +0000 (-0400) Subject: rbd-mirror: copy snapshot parent image settings X-Git-Tag: v10.2.2~40^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=af6be1bc15dfc2757cf74772078dd8516ed889be;p=ceph.git rbd-mirror: copy snapshot parent image settings Signed-off-by: Jason Dillaman (cherry picked from commit f5fd09373714ebe8886bcf51bb97732038fffe55) --- diff --git a/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc b/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc index 5712e60e3d6c..79b7eff13496 100644 --- a/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc +++ b/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc @@ -47,7 +47,7 @@ struct ImageSync { 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; diff --git a/src/test/rbd_mirror/image_sync/test_mock_SnapshotCopyRequest.cc b/src/test/rbd_mirror/image_sync/test_mock_SnapshotCopyRequest.cc index b3e4a120ab12..35252f9177e0 100644 --- a/src/test/rbd_mirror/image_sync/test_mock_SnapshotCopyRequest.cc +++ b/src/test/rbd_mirror/image_sync/test_mock_SnapshotCopyRequest.cc @@ -34,7 +34,10 @@ struct SnapshotCreateRequest { 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; @@ -157,7 +160,7 @@ public: 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, diff --git a/src/test/rbd_mirror/image_sync/test_mock_SnapshotCreateRequest.cc b/src/test/rbd_mirror/image_sync/test_mock_SnapshotCreateRequest.cc index dd8305de0249..8cf6217bf75b 100644 --- a/src/test/rbd_mirror/image_sync/test_mock_SnapshotCreateRequest.cc +++ b/src/test/rbd_mirror/image_sync/test_mock_SnapshotCreateRequest.cc @@ -54,6 +54,18 @@ public: .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)) @@ -81,9 +93,12 @@ public: 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; @@ -99,7 +114,7 @@ TEST_F(TestMockImageSyncSnapshotCreateRequest, Resize) { C_SaferCond ctx; MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", 123, + "snap1", 123, {}, 0, &ctx); request->send(); ASSERT_EQ(0, ctx.wait()); @@ -113,16 +128,71 @@ TEST_F(TestMockImageSyncSnapshotCreateRequest, ResizeError) { 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); @@ -130,11 +200,63 @@ TEST_F(TestMockImageSyncSnapshotCreateRequest, SnapCreate) { 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); @@ -145,7 +267,7 @@ TEST_F(TestMockImageSyncSnapshotCreateRequest, SnapCreateError) { MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, "snap1", m_local_image_ctx->size, - &ctx); + {}, 0, &ctx); request->send(); ASSERT_EQ(-EINVAL, ctx.wait()); } @@ -162,7 +284,7 @@ TEST_F(TestMockImageSyncSnapshotCreateRequest, ResizeObjectMap) { MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, "snap1", m_local_image_ctx->size, - &ctx); + {}, 0, &ctx); request->send(); ASSERT_EQ(0, ctx.wait()); } @@ -179,7 +301,7 @@ TEST_F(TestMockImageSyncSnapshotCreateRequest, ResizeObjectMapError) { MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, "snap1", m_local_image_ctx->size, - &ctx); + {}, 0, &ctx); request->send(); ASSERT_EQ(-EINVAL, ctx.wait()); } diff --git a/src/test/rbd_mirror/test_ImageSync.cc b/src/test/rbd_mirror/test_ImageSync.cc index 5b80f970d888..db6e26f544d8 100644 --- a/src/test/rbd_mirror/test_ImageSync.cc +++ b/src/test/rbd_mirror/test_ImageSync.cc @@ -88,7 +88,7 @@ public: 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; diff --git a/src/test/rbd_mirror/test_mock_ImageSync.cc b/src/test/rbd_mirror/test_mock_ImageSync.cc index f3c94bac2260..38d2cb00e10d 100644 --- a/src/test/rbd_mirror/test_mock_ImageSync.cc +++ b/src/test/rbd_mirror/test_mock_ImageSync.cc @@ -73,6 +73,7 @@ public: SnapshotCopyRequest::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; @@ -238,7 +239,7 @@ public: 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; diff --git a/src/tools/rbd_mirror/ImageSync.cc b/src/tools/rbd_mirror/ImageSync.cc index 24202f496f1d..ff2c7bb1561a 100644 --- a/src/tools/rbd_mirror/ImageSync.cc +++ b/src/tools/rbd_mirror/ImageSync.cc @@ -30,11 +30,13 @@ template ImageSync::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)) { } @@ -138,7 +140,7 @@ void ImageSync::send_copy_snapshots() { ImageSync, &ImageSync::handle_copy_snapshots>(this); SnapshotCopyRequest *request = SnapshotCopyRequest::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(); } diff --git a/src/tools/rbd_mirror/ImageSync.h b/src/tools/rbd_mirror/ImageSync.h index 95809ab0fb95..abe0f4648ddf 100644 --- a/src/tools/rbd_mirror/ImageSync.h +++ b/src/tools/rbd_mirror/ImageSync.h @@ -12,6 +12,7 @@ #include class Context; +class ContextWQ; class Mutex; class SafeTimer; namespace journal { class Journaler; } @@ -36,17 +37,18 @@ public: 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(); @@ -94,6 +96,7 @@ private: std::string m_mirror_uuid; Journaler *m_journaler; MirrorPeerClientMeta *m_client_meta; + ContextWQ *m_work_queue; Context *m_on_finish; ProgressContext *m_progress_ctx; diff --git a/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc b/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc index e241aee19e94..b90b60856f35 100644 --- a/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc +++ b/src/tools/rbd_mirror/image_replayer/BootstrapRequest.cc @@ -515,7 +515,7 @@ void BootstrapRequest::image_sync() { 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(); } diff --git a/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc b/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc index 016e4b4e4bbb..bee21c019e66 100644 --- a/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc +++ b/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc @@ -4,6 +4,7 @@ #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" @@ -42,10 +43,12 @@ SnapshotCopyRequest::SnapshotCopyRequest(I *local_image_ctx, 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 @@ -57,6 +60,21 @@ SnapshotCopyRequest::SnapshotCopyRequest(I *local_image_ctx, template void SnapshotCopyRequest::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(); } @@ -64,21 +82,6 @@ template void SnapshotCopyRequest::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& 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); @@ -271,19 +274,32 @@ void SnapshotCopyRequest::send_snap_create() { 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, &SnapshotCopyRequest::handle_snap_create>( this); SnapshotCreateRequest *req = SnapshotCreateRequest::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(); } @@ -437,6 +453,14 @@ void SnapshotCopyRequest::handle_update_client(int r) { finish(0); } +template +void SnapshotCopyRequest::error(int r) { + dout(20) << ": r=" << r << dendl; + + m_work_queue->queue(create_context_callback< + SnapshotCopyRequest, &SnapshotCopyRequest::finish>(this), r); +} + template void SnapshotCopyRequest::finish(int r) { CephContext *cct = m_local_image_ctx->cct; @@ -460,6 +484,30 @@ void SnapshotCopyRequest::compute_snap_map() { } } +template +int SnapshotCopyRequest::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 diff --git a/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.h b/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.h index 87f766f1f2cc..02b5ce74a39d 100644 --- a/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.h +++ b/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.h @@ -8,6 +8,7 @@ #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 #include @@ -15,6 +16,7 @@ #include class Context; +class ContextWQ; namespace journal { class Journaler; } namespace librbd { namespace journal { struct MirrorPeerClientMeta; } } @@ -35,15 +37,17 @@ public: 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(); @@ -90,6 +94,7 @@ private: 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; @@ -99,6 +104,8 @@ private: std::string m_snap_name; + librbd::parent_spec m_local_parent_spec; + void send_snap_unprotect(); void handle_snap_unprotect(int r); @@ -114,10 +121,13 @@ private: 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 diff --git a/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc b/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc index 60d03ffa1eb9..e15ca958e482 100644 --- a/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc +++ b/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc @@ -25,8 +25,11 @@ template SnapshotCreateRequest::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) { } @@ -87,15 +90,28 @@ void SnapshotCreateRequest::handle_set_size(int r) { template void SnapshotCreateRequest::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, + &SnapshotCreateRequest::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 @@ -103,15 +119,47 @@ void SnapshotCreateRequest::handle_remove_parent(int r) { 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 void SnapshotCreateRequest::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, + &SnapshotCreateRequest::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 @@ -119,7 +167,21 @@ void SnapshotCreateRequest::handle_set_parent(int r) { 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 diff --git a/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.h b/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.h index 897c7b9d8ac5..c8c772f4acaf 100644 --- a/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.h +++ b/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.h @@ -8,6 +8,7 @@ #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 #include @@ -25,14 +26,18 @@ class SnapshotCreateRequest { 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(); @@ -66,6 +71,8 @@ private: 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();