From aac5473889f062c1871ba9a0e55b60ffd0b40e66 Mon Sep 17 00:00:00 2001 From: Mykola Golub Date: Tue, 8 May 2018 15:29:38 +0300 Subject: [PATCH] librbd: fix deep copy clone to destination with larger object size When assembling a destination object from source objects we need to read from parent if some (but not all) of assembles do not exist. Signed-off-by: Mykola Golub (cherry picked from commit 947993a8d36f60bde05bc7b9a49c333dd51da4c5) Conflicts: src/test/librbd/deep_copy/test_mock_ImageCopyRequest.cc: trivial resolution --- src/librbd/deep_copy/ImageCopyRequest.cc | 127 ++++++++++- src/librbd/deep_copy/ImageCopyRequest.h | 24 ++- src/librbd/deep_copy/ObjectCopyRequest.cc | 199 ++++++++++++++++-- src/librbd/deep_copy/ObjectCopyRequest.h | 25 ++- .../deep_copy/test_mock_ImageCopyRequest.cc | 94 ++++++++- .../deep_copy/test_mock_ObjectCopyRequest.cc | 34 ++- src/test/librbd/mock/MockImageCtx.h | 1 + 7 files changed, 471 insertions(+), 33 deletions(-) diff --git a/src/librbd/deep_copy/ImageCopyRequest.cc b/src/librbd/deep_copy/ImageCopyRequest.cc index 4a315f9231bcd..d101aa8d17d62 100644 --- a/src/librbd/deep_copy/ImageCopyRequest.cc +++ b/src/librbd/deep_copy/ImageCopyRequest.cc @@ -6,6 +6,9 @@ #include "common/errno.h" #include "librbd/Utils.h" #include "librbd/deep_copy/Utils.h" +#include "librbd/image/CloseRequest.h" +#include "librbd/image/OpenRequest.h" +#include "librbd/image/SetSnapRequest.h" #include "osdc/Striper.h" #define dout_subsys ceph_subsys_rbd @@ -16,6 +19,7 @@ namespace librbd { namespace deep_copy { +using librbd::util::create_context_callback; using librbd::util::unique_lock_name; template @@ -44,7 +48,7 @@ void ImageCopyRequest::send() { return; } - send_object_copies(); + send_open_parent(); } template @@ -55,6 +59,90 @@ void ImageCopyRequest::cancel() { m_canceled = true; } +template +void ImageCopyRequest::send_open_parent() { + { + RWLock::RLocker snap_locker(m_src_image_ctx->snap_lock); + RWLock::RLocker parent_locker(m_src_image_ctx->parent_lock); + + auto snap_id = m_snap_map.begin()->first; + auto parent_info = m_src_image_ctx->get_parent_info(snap_id); + if (parent_info == nullptr) { + ldout(m_cct, 20) << "could not find parent info for snap id " << snap_id + << dendl; + } else { + m_parent_spec = parent_info->spec; + } + } + + if (m_parent_spec.pool_id == -1) { + send_object_copies(); + return; + } + + ldout(m_cct, 20) << "pool_id=" << m_parent_spec.pool_id << ", image_id=" + << m_parent_spec.image_id << ", snap_id=" + << m_parent_spec.snap_id << dendl; + + librados::Rados rados(m_src_image_ctx->md_ctx); + librados::IoCtx parent_io_ctx; + int r = rados.ioctx_create2(m_parent_spec.pool_id, parent_io_ctx); + if (r < 0) { + lderr(m_cct) << "failed to access parent pool (id=" << m_parent_spec.pool_id + << "): " << cpp_strerror(r) << dendl; + finish(r); + return; + } + + m_src_parent_image_ctx = I::create("", m_parent_spec.image_id, nullptr, parent_io_ctx, true); + + auto ctx = create_context_callback< + ImageCopyRequest, &ImageCopyRequest::handle_open_parent>(this); + + auto req = image::OpenRequest::create(m_src_parent_image_ctx, false, ctx); + req->send(); +} + +template +void ImageCopyRequest::handle_open_parent(int r) { + ldout(m_cct, 20) << "r=" << r << dendl; + + if (r < 0) { + lderr(m_cct) << "failed to open parent: " << cpp_strerror(r) << dendl; + m_src_parent_image_ctx->destroy(); + m_src_parent_image_ctx = nullptr; + finish(r); + return; + } + + send_set_parent_snap(); +} + +template +void ImageCopyRequest::send_set_parent_snap() { + ldout(m_cct, 20) << dendl; + + auto ctx = create_context_callback< + ImageCopyRequest, &ImageCopyRequest::handle_set_parent_snap>(this); + auto req = image::SetSnapRequest::create(*m_src_parent_image_ctx, + m_parent_spec.snap_id, ctx); + req->send(); +} + +template +void ImageCopyRequest::handle_set_parent_snap(int r) { + ldout(m_cct, 20) << "r=" << r << dendl; + + if (r < 0) { + lderr(m_cct) << "failed to set parent snap: " << cpp_strerror(r) << dendl; + m_ret_val = r; + send_close_parent(); + return; + } + + send_object_copies(); +} + template void ImageCopyRequest::send_object_copies() { m_object_no = 0; @@ -90,7 +178,7 @@ void ImageCopyRequest::send_object_copies() { } if (complete) { - finish(m_ret_val); + send_close_parent(); } } @@ -118,7 +206,8 @@ void ImageCopyRequest::send_next_object_copy() { handle_object_copy(ono, r); }); ObjectCopyRequest *req = ObjectCopyRequest::create( - m_src_image_ctx, m_dst_image_ctx, m_snap_map, ono, ctx); + m_src_image_ctx, m_src_parent_image_ctx, m_dst_image_ctx, m_snap_map, ono, + ctx); req->send(); } @@ -158,8 +247,40 @@ void ImageCopyRequest::handle_object_copy(uint64_t object_no, int r) { } if (complete) { + send_close_parent(); + } +} + +template +void ImageCopyRequest::send_close_parent() { + if (m_src_parent_image_ctx == nullptr) { finish(m_ret_val); + return; } + + ldout(m_cct, 20) << dendl; + + auto ctx = create_context_callback< + ImageCopyRequest, &ImageCopyRequest::handle_close_parent>(this); + auto req = image::CloseRequest::create(m_src_parent_image_ctx, ctx); + req->send(); +} + +template +void ImageCopyRequest::handle_close_parent(int r) { + ldout(m_cct, 20) << "r=" << r << dendl; + + if (r < 0) { + lderr(m_cct) << "failed to close parent: " << cpp_strerror(r) << dendl; + if (m_ret_val == 0) { + m_ret_val = r; + } + } + + m_src_parent_image_ctx->destroy(); + m_src_parent_image_ctx = nullptr; + + finish(m_ret_val); } template diff --git a/src/librbd/deep_copy/ImageCopyRequest.h b/src/librbd/deep_copy/ImageCopyRequest.h index bdba8fc59409e..8c395a34c9fd2 100644 --- a/src/librbd/deep_copy/ImageCopyRequest.h +++ b/src/librbd/deep_copy/ImageCopyRequest.h @@ -53,12 +53,23 @@ private: /** * @verbatim * - * . . . . . + * + * | + * v + * OPEN_PARENT (skip if not needed) + * | + * v + * SET_PARENT_SNAP (skip if not needed) + * | + * | . . . . . * | . . (parallel execution of * v v . multiple objects at once) * COPY_OBJECT . . . . * | * v + * CLOSE_PARENT (skip if not needed) + * | + * v * * * @endverbatim @@ -85,11 +96,22 @@ private: bool m_updating_progress = false; SnapMap m_snap_map; int m_ret_val = 0; + ParentSpec m_parent_spec; + ImageCtxT *m_src_parent_image_ctx = nullptr; + + void send_open_parent(); + void handle_open_parent(int r); + + void send_set_parent_snap(); + void handle_set_parent_snap(int r); void send_object_copies(); void send_next_object_copy(); void handle_object_copy(uint64_t object_no, int r); + void send_close_parent(); + void handle_close_parent(int r); + void finish(int r); }; diff --git a/src/librbd/deep_copy/ObjectCopyRequest.cc b/src/librbd/deep_copy/ObjectCopyRequest.cc index bd83ebfae8ce9..212d90d0bb790 100644 --- a/src/librbd/deep_copy/ObjectCopyRequest.cc +++ b/src/librbd/deep_copy/ObjectCopyRequest.cc @@ -7,6 +7,9 @@ #include "librbd/ExclusiveLock.h" #include "librbd/ObjectMap.h" #include "librbd/Utils.h" +#include "librbd/io/AioCompletion.h" +#include "librbd/io/ImageRequest.h" +#include "librbd/io/ReadResult.h" #include "osdc/Striper.h" #define dout_subsys ceph_subsys_rbd @@ -37,13 +40,17 @@ using librbd::util::create_context_callback; using librbd::util::create_rados_callback; template -ObjectCopyRequest::ObjectCopyRequest(I *src_image_ctx, I *dst_image_ctx, +ObjectCopyRequest::ObjectCopyRequest(I *src_image_ctx, + I *src_parent_image_ctx, + I *dst_image_ctx, const SnapMap &snap_map, uint64_t dst_object_number, Context *on_finish) - : m_src_image_ctx(src_image_ctx), m_dst_image_ctx(dst_image_ctx), - m_cct(dst_image_ctx->cct), m_snap_map(snap_map), - m_dst_object_number(dst_object_number), m_on_finish(on_finish) { + : m_src_image_ctx(src_image_ctx), + m_src_parent_image_ctx(src_parent_image_ctx), + m_dst_image_ctx(dst_image_ctx), m_cct(dst_image_ctx->cct), + m_snap_map(snap_map), m_dst_object_number(dst_object_number), + m_on_finish(on_finish) { assert(!m_snap_map.empty()); m_src_io_ctx.dup(m_src_image_ctx->data_ctx); @@ -92,11 +99,7 @@ void ObjectCopyRequest::handle_list_snaps(int r) { ldout(m_cct, 20) << "r=" << r << dendl; - if (r == -ENOENT) { - r = 0; - } - - if (r < 0) { + if (r < 0 && r != -ENOENT) { lderr(m_cct) << "failed to list snaps: " << cpp_strerror(r) << dendl; finish(r); return; @@ -115,7 +118,19 @@ void ObjectCopyRequest::handle_list_snaps(int r) { m_retry_snap_set = {}; } - compute_read_ops(); + if (r == -ENOENT) { + for (auto &it : m_src_object_extents) { + auto &e = it.second; + if (e.object_no == m_src_ono) { + e.noent = true; + } + } + m_read_ops = {}; + m_read_snaps = {}; + m_zero_interval = {}; + } else { + compute_read_ops(); + } send_read_object(); } @@ -135,16 +150,7 @@ void ObjectCopyRequest::send_read_object() { } // all objects have been read - - compute_zero_ops(); - - if (m_write_ops.empty()) { - // nothing to copy - finish(0); - return; - } - - send_write_object(); + send_read_from_parent(); return; } @@ -220,6 +226,71 @@ void ObjectCopyRequest::handle_read_object(int r) { send_read_object(); } +template +void ObjectCopyRequest::send_read_from_parent() { + io::Extents image_extents; + compute_read_from_parent_ops(&image_extents); + if (image_extents.empty()) { + handle_read_from_parent(0); + return; + } + + ldout(m_cct, 20) << dendl; + + assert(m_src_parent_image_ctx != nullptr); + + auto ctx = create_context_callback< + ObjectCopyRequest, &ObjectCopyRequest::handle_read_from_parent>(this); + auto comp = io::AioCompletion::create_and_start( + ctx, util::get_image_ctx(m_src_image_ctx), io::AIO_TYPE_READ); + ldout(m_cct, 20) << "completion " << comp << ", extents " << image_extents + << dendl; + io::ImageRequest::aio_read(m_src_parent_image_ctx, comp, + std::move(image_extents), + io::ReadResult{&m_read_from_parent_data}, 0, + ZTracer::Trace()); +} + +template +void ObjectCopyRequest::handle_read_from_parent(int r) { + ldout(m_cct, 20) << "r=" << r << dendl; + + if (r < 0) { + lderr(m_cct) << "failed to read from parent: " << cpp_strerror(r) << dendl; + finish(r); + return; + } + + if (!m_read_ops.empty()) { + assert(m_read_ops.size() == 1); + auto src_snap_seq = m_read_ops.begin()->first.first; + auto ©_ops = m_read_ops.begin()->second; + uint64_t offset = 0; + for (auto it = copy_ops.begin(); it != copy_ops.end(); ) { + it->out_bl.substr_of(m_read_from_parent_data, offset, it->length); + offset += it->length; + if (it->out_bl.is_zero()) { + m_zero_interval[src_snap_seq].insert(it->dst_offset, it->length); + it = copy_ops.erase(it); + } else { + it++; + } + } + merge_write_ops(); + } + + compute_zero_ops(); + + if (m_write_ops.empty()) { + // nothing to copy + finish(0); + return; + } + + send_write_object(); + return; +} + template void ObjectCopyRequest::send_write_object() { assert(!m_write_ops.empty()); @@ -592,6 +663,94 @@ void ObjectCopyRequest::compute_read_ops() { } } +template +void ObjectCopyRequest::compute_read_from_parent_ops( + io::Extents *parent_image_extents) { + m_read_ops = {}; + m_zero_interval = {}; + parent_image_extents->clear(); + + if (m_src_parent_image_ctx == nullptr) { + ldout(m_cct, 20) << "no parent" << dendl; + return; + } + + size_t noent_count = 0; + for (auto &it : m_src_object_extents) { + if (it.second.noent) { + noent_count++; + } + } + + if (noent_count == 0) { + ldout(m_cct, 20) << "no extents need read from parent" << dendl; + return; + } + + if (noent_count == m_src_object_extents.size()) { + ldout(m_cct, 20) << "reading all extents skipped when no flatten" + << dendl; + return; + } + + ldout(m_cct, 20) << dendl; + + auto src_snap_seq = m_snap_map.begin()->first; + + RWLock::RLocker snap_locker(m_src_image_ctx->snap_lock); + RWLock::RLocker parent_locker(m_src_image_ctx->parent_lock); + + uint64_t parent_overlap; + int r = m_src_image_ctx->get_parent_overlap(src_snap_seq, &parent_overlap); + if (r < 0) { + ldout(m_cct, 5) << "failed getting parent overlap for snap_id: " + << src_snap_seq << ": " << cpp_strerror(r) << dendl; + return; + } + if (parent_overlap == 0) { + ldout(m_cct, 20) << "no parent overlap" << dendl; + return; + } + + for (auto &it : m_src_object_extents) { + auto dst_object_offset = it.first; + auto &e = it.second; + + if (!e.noent) { + continue; + } + + std::vector> image_extents; + Striper::extent_to_file(m_cct, &m_src_image_ctx->layout, e.object_no, + e.offset, e.length, image_extents); + + uint64_t overlap = m_src_image_ctx->prune_parent_extents(image_extents, + parent_overlap); + if (overlap == 0) { + ldout(m_cct, 20) << "no parent overlap for object_no " << e.object_no + << " extent " << e.offset << "~" << e.length << dendl; + continue; + } + + ldout(m_cct, 20) << "object_no " << e.object_no << " extent " << e.offset + << "~" << e.length << " overlap " << parent_overlap + << " parent extents " << image_extents << dendl; + + assert(image_extents.size() == 1); + + auto src_image_offset = image_extents.begin()->first; + auto length = image_extents.begin()->second; + m_read_ops[{src_snap_seq, 0}].emplace_back(COPY_OP_TYPE_WRITE, e.offset, + dst_object_offset, length); + m_read_ops[{src_snap_seq, 0}].rbegin()->src_extent_map[e.offset] = length; + parent_image_extents->emplace_back(src_image_offset, length); + } + + if (!parent_image_extents->empty()) { + m_dst_object_state[src_snap_seq] = OBJECT_EXISTS; + } +} + template void ObjectCopyRequest::merge_write_ops() { ldout(m_cct, 20) << dendl; diff --git a/src/librbd/deep_copy/ObjectCopyRequest.h b/src/librbd/deep_copy/ObjectCopyRequest.h index d6f3ec3285031..d2a0cad623d07 100644 --- a/src/librbd/deep_copy/ObjectCopyRequest.h +++ b/src/librbd/deep_copy/ObjectCopyRequest.h @@ -10,6 +10,7 @@ #include "common/snap_types.h" #include "librbd/ImageCtx.h" #include "librbd/deep_copy/Types.h" +#include "librbd/io/Types.h" #include #include #include @@ -24,16 +25,19 @@ template class ObjectCopyRequest { public: static ObjectCopyRequest* create(ImageCtxT *src_image_ctx, + ImageCtxT *src_parent_image_ctx, ImageCtxT *dst_image_ctx, const SnapMap &snap_map, - uint64_t object_number, Context *on_finish) { - return new ObjectCopyRequest(src_image_ctx, dst_image_ctx, snap_map, - object_number, on_finish); + uint64_t object_number, + Context *on_finish) { + return new ObjectCopyRequest(src_image_ctx, src_parent_image_ctx, + dst_image_ctx, snap_map, object_number, + on_finish); } - ObjectCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *dst_image_ctx, - const SnapMap &snap_map, uint64_t object_number, - Context *on_finish); + ObjectCopyRequest(ImageCtxT *src_image_ctx, ImageCtxT *src_parent_image_ctx, + ImageCtxT *dst_image_ctx, const SnapMap &snap_map, + uint64_t object_number, Context *on_finish); void send(); @@ -62,6 +66,8 @@ private: * READ_OBJECT ---------/ | * | | | * | \----------------------/ + * v + * READ_FROM_PARENT (skip if not needed) * | * | /-----------\ * | | | (repeat for each snapshot) @@ -83,6 +89,7 @@ private: uint64_t object_no = 0; uint64_t offset = 0; uint64_t length = 0; + bool noent = false; SrcObjectExtent() { } @@ -125,6 +132,7 @@ private: typedef std::map> SnapObjectSizes; ImageCtxT *m_src_image_ctx; + ImageCtxT *m_src_parent_image_ctx; ImageCtxT *m_dst_image_ctx; CephContext *m_cct; const SnapMap &m_snap_map; @@ -151,6 +159,7 @@ private: std::map> m_zero_interval; std::map> m_dst_zero_interval; std::map m_dst_object_state; + bufferlist m_read_from_parent_data; void send_list_snaps(); void handle_list_snaps(int r); @@ -158,6 +167,9 @@ private: void send_read_object(); void handle_read_object(int r); + void send_read_from_parent(); + void handle_read_from_parent(int r); + void send_write_object(); void handle_write_object(int r); @@ -170,6 +182,7 @@ private: void compute_src_object_extents(); void compute_read_ops(); + void compute_read_from_parent_ops(io::Extents *image_extents); void merge_write_ops(); void compute_zero_ops(); diff --git a/src/test/librbd/deep_copy/test_mock_ImageCopyRequest.cc b/src/test/librbd/deep_copy/test_mock_ImageCopyRequest.cc index bd8932e788bb1..bd4f897249c99 100644 --- a/src/test/librbd/deep_copy/test_mock_ImageCopyRequest.cc +++ b/src/test/librbd/deep_copy/test_mock_ImageCopyRequest.cc @@ -8,6 +8,9 @@ #include "librbd/Operations.h" #include "librbd/deep_copy/ImageCopyRequest.h" #include "librbd/deep_copy/ObjectCopyRequest.h" +#include "librbd/image/CloseRequest.h" +#include "librbd/image/OpenRequest.h" +#include "librbd/image/SetSnapRequest.h" #include "librbd/internal.h" #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" #include "test/librbd/mock/MockImageCtx.h" @@ -19,11 +22,25 @@ namespace librbd { namespace { struct MockTestImageCtx : public librbd::MockImageCtx { - MockTestImageCtx(librbd::ImageCtx &image_ctx) + static MockTestImageCtx* s_instance; + static MockTestImageCtx* create(const std::string &image_name, + const std::string &image_id, + const char *snap, librados::IoCtx& p, + bool read_only) { + assert(s_instance != nullptr); + return s_instance; + } + + explicit MockTestImageCtx(librbd::ImageCtx &image_ctx) : librbd::MockImageCtx(image_ctx) { + s_instance = this; } + + MOCK_METHOD0(destroy, void()); }; +MockTestImageCtx* MockTestImageCtx::s_instance = nullptr; + } // anonymous namespace namespace deep_copy { @@ -33,6 +50,7 @@ struct ObjectCopyRequest { static ObjectCopyRequest* s_instance; static ObjectCopyRequest* create( librbd::MockTestImageCtx *src_image_ctx, + librbd::MockTestImageCtx *src_parent_image_ctx, librbd::MockTestImageCtx *dst_image_ctx, const SnapMap &snap_map, uint64_t object_number, Context *on_finish) { assert(s_instance != nullptr); @@ -59,6 +77,70 @@ struct ObjectCopyRequest { ObjectCopyRequest* ObjectCopyRequest::s_instance = nullptr; } // namespace deep_copy + +namespace image { + +template <> +struct CloseRequest { + Context* on_finish = nullptr; + static CloseRequest* s_instance; + static CloseRequest* create(MockTestImageCtx *image_ctx, Context *on_finish) { + assert(s_instance != nullptr); + s_instance->on_finish = on_finish; + return s_instance; + } + + MOCK_METHOD0(send, void()); + + CloseRequest() { + s_instance = this; + } +}; + +CloseRequest* CloseRequest::s_instance = nullptr; + +template <> +struct OpenRequest { + Context* on_finish = nullptr; + static OpenRequest* s_instance; + static OpenRequest* create(MockTestImageCtx *image_ctx, + bool skip_open_parent, Context *on_finish) { + assert(s_instance != nullptr); + s_instance->on_finish = on_finish; + return s_instance; + } + + MOCK_METHOD0(send, void()); + + OpenRequest() { + s_instance = this; + } +}; + +OpenRequest* OpenRequest::s_instance = nullptr; + +template <> +struct SetSnapRequest { + Context* on_finish = nullptr; + static SetSnapRequest* s_instance; + static SetSnapRequest* create(MockTestImageCtx &image_ctx, uint64_t snap_id, + Context *on_finish) { + assert(s_instance != nullptr); + s_instance->on_finish = on_finish; + return s_instance; + } + + MOCK_METHOD0(send, void()); + + SetSnapRequest() { + s_instance = this; + } +}; + +SetSnapRequest* SetSnapRequest::s_instance = nullptr; + +} // namespace image + } // namespace librbd // template definitions @@ -104,6 +186,10 @@ public: .WillOnce(Return(size)).RetiresOnSaturation(); } + void expect_get_parent_info(librbd::MockTestImageCtx &mock_image_ctx) { + EXPECT_CALL(mock_image_ctx, get_parent_info(_)).WillOnce(Return(nullptr)); + } + void expect_object_copy_send(MockObjectCopyRequest &mock_object_copy_request) { EXPECT_CALL(mock_object_copy_request, send()); } @@ -203,6 +289,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, SimpleImage) { MockObjectCopyRequest mock_object_copy_request; InSequence seq; + expect_get_parent_info(mock_src_image_ctx); expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order); expect_get_image_size(mock_src_image_ctx, 0); expect_object_copy_send(mock_object_copy_request); @@ -238,6 +325,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, OutOfOrder) { librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); MockObjectCopyRequest mock_object_copy_request; + expect_get_parent_info(mock_src_image_ctx); expect_get_image_size(mock_src_image_ctx, object_count * (1 << m_src_image_ctx->order)); expect_get_image_size(mock_src_image_ctx, 0); @@ -305,6 +393,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, SnapshotSubset) { MockObjectCopyRequest mock_object_copy_request; InSequence seq; + expect_get_parent_info(mock_src_image_ctx); expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order); expect_get_image_size(mock_src_image_ctx, 0); expect_get_image_size(mock_src_image_ctx, 0); @@ -337,6 +426,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, RestartPartialSync) { MockObjectCopyRequest mock_object_copy_request; InSequence seq; + expect_get_parent_info(mock_src_image_ctx); expect_get_image_size(mock_src_image_ctx, 2 * (1 << m_src_image_ctx->order)); expect_get_image_size(mock_src_image_ctx, 0); expect_object_copy_send(mock_object_copy_request); @@ -371,6 +461,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, Cancel) { MockObjectCopyRequest mock_object_copy_request; InSequence seq; + expect_get_parent_info(mock_src_image_ctx); expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order); expect_get_image_size(mock_src_image_ctx, 0); expect_object_copy_send(mock_object_copy_request); @@ -407,6 +498,7 @@ TEST_F(TestMockDeepCopyImageCopyRequest, Cancel_Inflight_Sync) { MockObjectCopyRequest mock_object_copy_request; InSequence seq; + expect_get_parent_info(mock_src_image_ctx); expect_get_image_size(mock_src_image_ctx, 6 * (1 << m_src_image_ctx->order)); expect_get_image_size(mock_src_image_ctx, m_image_size); diff --git a/src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc b/src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc index 448e5dda89c4a..cc86b800aaa80 100644 --- a/src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc +++ b/src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc @@ -11,6 +11,7 @@ #include "librbd/Operations.h" #include "librbd/api/Image.h" #include "librbd/deep_copy/ObjectCopyRequest.h" +#include "librbd/io/ImageRequest.h" #include "librbd/io/ImageRequestWQ.h" #include "librbd/io/ReadResult.h" #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" @@ -27,6 +28,34 @@ struct MockTestImageCtx : public librbd::MockImageCtx { }; } // anonymous namespace + +namespace util { + +inline ImageCtx* get_image_ctx(MockTestImageCtx* image_ctx) { + return image_ctx->image_ctx; +} + +} // namespace util + +namespace io { + +template <> +struct ImageRequest { + static ImageRequest *s_instance; + + static void aio_read(MockTestImageCtx *ictx, AioCompletion *c, + Extents &&image_extents, ReadResult &&read_result, + int op_flags, const ZTracer::Trace &parent_trace) { + assert(s_instance != nullptr); + s_instance->aio_read(c, image_extents); + } + MOCK_METHOD2(aio_read, void(AioCompletion *, const Extents&)); +}; + +ImageRequest *ImageRequest::s_instance = nullptr; + +} // namespace io + } // namespace librbd // template definitions @@ -169,8 +198,9 @@ public: librbd::MockTestImageCtx &mock_src_image_ctx, librbd::MockTestImageCtx &mock_dst_image_ctx, Context *on_finish) { expect_get_object_name(mock_dst_image_ctx); - return new MockObjectCopyRequest(&mock_src_image_ctx, &mock_dst_image_ctx, - m_snap_map, 0, on_finish); + return new MockObjectCopyRequest(&mock_src_image_ctx, nullptr, + &mock_dst_image_ctx, m_snap_map, 0, + on_finish); } void expect_set_snap_read(librados::MockTestMemIoCtxImpl &mock_io_ctx, diff --git a/src/test/librbd/mock/MockImageCtx.h b/src/test/librbd/mock/MockImageCtx.h index 40215bc3e0b77..8c77ca16ffb84 100644 --- a/src/test/librbd/mock/MockImageCtx.h +++ b/src/test/librbd/mock/MockImageCtx.h @@ -165,6 +165,7 @@ struct MockImageCtx { cls::rbd::SnapshotNamespace *out_snap_namespace)); MOCK_CONST_METHOD2(get_parent_spec, int(librados::snap_t in_snap_id, ParentSpec *pspec)); + MOCK_CONST_METHOD1(get_parent_info, const ParentInfo*(librados::snap_t)); MOCK_CONST_METHOD2(get_parent_overlap, int(librados::snap_t in_snap_id, uint64_t *overlap)); MOCK_CONST_METHOD2(prune_parent_extents, uint64_t(vector >& , -- 2.39.5