From 0096d079e1e953c84eb3bf085ee3fbf74b83c0b6 Mon Sep 17 00:00:00 2001 From: Mykola Golub Date: Mon, 7 Oct 2019 17:07:34 +0100 Subject: [PATCH] librbd: state machine for unlinking peer from mirror snapshot Signed-off-by: Mykola Golub --- src/librbd/CMakeLists.txt | 1 + .../mirror/snapshot/UnlinkPeerRequest.cc | 215 +++++++++++ .../mirror/snapshot/UnlinkPeerRequest.h | 90 +++++ src/test/librbd/CMakeLists.txt | 1 + .../snapshot/test_mock_UnlinkPeerRequest.cc | 344 ++++++++++++++++++ src/test/librbd/test_mirroring.cc | 2 +- 6 files changed, 652 insertions(+), 1 deletion(-) create mode 100644 src/librbd/mirror/snapshot/UnlinkPeerRequest.cc create mode 100644 src/librbd/mirror/snapshot/UnlinkPeerRequest.h create mode 100644 src/test/librbd/mirror/snapshot/test_mock_UnlinkPeerRequest.cc diff --git a/src/librbd/CMakeLists.txt b/src/librbd/CMakeLists.txt index 8b95fe1e30d..ee869e66014 100644 --- a/src/librbd/CMakeLists.txt +++ b/src/librbd/CMakeLists.txt @@ -104,6 +104,7 @@ set(librbd_internal_srcs mirror/GetInfoRequest.cc mirror/GetStatusRequest.cc mirror/PromoteRequest.cc + mirror/snapshot/UnlinkPeerRequest.cc object_map/CreateRequest.cc object_map/InvalidateRequest.cc object_map/LockRequest.cc diff --git a/src/librbd/mirror/snapshot/UnlinkPeerRequest.cc b/src/librbd/mirror/snapshot/UnlinkPeerRequest.cc new file mode 100644 index 00000000000..ec23f35c538 --- /dev/null +++ b/src/librbd/mirror/snapshot/UnlinkPeerRequest.cc @@ -0,0 +1,215 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "librbd/mirror/snapshot/UnlinkPeerRequest.h" +#include "common/dout.h" +#include "common/errno.h" +#include "cls/rbd/cls_rbd_client.h" +#include "librbd/ImageCtx.h" +#include "librbd/ImageState.h" +#include "librbd/Operations.h" +#include "librbd/Utils.h" + +#define dout_subsys ceph_subsys_rbd +#undef dout_prefix +#define dout_prefix *_dout << "librbd::mirror::snapshot::UnlinkPeerRequest: " \ + << this << " " << __func__ << ": " + +namespace librbd { +namespace mirror { +namespace snapshot { + +using librbd::util::create_context_callback; +using librbd::util::create_rados_callback; + +template +void UnlinkPeerRequest::send() { + if (!m_image_ctx->state->is_refresh_required()) { + unlink_peer(); + return; + } + + refresh_image(); +} + +template +void UnlinkPeerRequest::refresh_image() { + CephContext *cct = m_image_ctx->cct; + ldout(cct, 20) << dendl; + + auto ctx = create_context_callback< + UnlinkPeerRequest, &UnlinkPeerRequest::handle_refresh_image>(this); + m_image_ctx->state->refresh(ctx); +} + +template +void UnlinkPeerRequest::handle_refresh_image(int r) { + CephContext *cct = m_image_ctx->cct; + ldout(cct, 20) << "r=" << r << dendl; + + if (r < 0) { + lderr(cct) << "failed to refresh image: " << cpp_strerror(r) << dendl; + finish(r); + return; + } + + unlink_peer(); +} + +template +void UnlinkPeerRequest::unlink_peer() { + CephContext *cct = m_image_ctx->cct; + + m_image_ctx->image_lock.lock_shared(); + + auto snap_info = m_image_ctx->get_snap_info(m_snap_id); + if (!snap_info) { + m_image_ctx->image_lock.unlock_shared(); + finish(-ENOENT); + return; + } + + auto info = boost::get( + &snap_info->snap_namespace); + if (info == nullptr) { + lderr(cct) << "not mirror primary snapshot (snap_id=" << m_snap_id << ")" + << dendl; + m_image_ctx->image_lock.unlock_shared(); + finish(-EINVAL); + return; + } + + if (info->mirror_peer_uuids.count(m_mirror_peer_uuid) == 0 || + info->mirror_peer_uuids.size() == 1U) { + m_image_ctx->image_lock.unlock_shared(); + remove_snapshot(); + return; + } + + m_image_ctx->image_lock.unlock_shared(); + + ldout(cct, 20) << dendl; + + librados::ObjectWriteOperation op; + librbd::cls_client::mirror_image_snapshot_unlink_peer(&op, m_snap_id, + m_mirror_peer_uuid); + auto aio_comp = create_rados_callback< + UnlinkPeerRequest, &UnlinkPeerRequest::handle_unlink_peer>(this); + int r = m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, aio_comp, + &op); + ceph_assert(r == 0); + aio_comp->release(); +} + +template +void UnlinkPeerRequest::handle_unlink_peer(int r) { + CephContext *cct = m_image_ctx->cct; + ldout(cct, 20) << "r=" << r << dendl; + + if (r == -ERESTART || r == -ENOENT) { + refresh_image(); + return; + } + + if (r < 0) { + lderr(cct) << "failed to unlink peer: " << cpp_strerror(r) << dendl; + finish(r); + return; + } + + notify_update(); +} + +template +void UnlinkPeerRequest::notify_update() { + CephContext *cct = m_image_ctx->cct; + ldout(cct, 20) << dendl; + + auto ctx = create_context_callback< + UnlinkPeerRequest, &UnlinkPeerRequest::handle_notify_update>(this); + m_image_ctx->notify_update(ctx); +} + +template +void UnlinkPeerRequest::handle_notify_update(int r) { + CephContext *cct = m_image_ctx->cct; + ldout(cct, 20) << "r=" << r << dendl; + + if (r < 0 && r != -ENOENT) { + lderr(cct) << "failed to notify update: " << cpp_strerror(r) << dendl; + finish(r); + return; + } + + refresh_image(); +} + +template +void UnlinkPeerRequest::remove_snapshot() { + CephContext *cct = m_image_ctx->cct; + ldout(cct, 20) << dendl; + + cls::rbd::SnapshotNamespace snap_namespace; + std::string snap_name; + int r = 0; + { + std::shared_lock image_locker{m_image_ctx->image_lock}; + + auto snap_info = m_image_ctx->get_snap_info(m_snap_id); + if (!snap_info) { + r = -ENOENT; + } else { + snap_namespace = snap_info->snap_namespace; + snap_name = snap_info->name; + } + } + + if (r == ENOENT) { + finish(0); + return; + } + + auto info = boost::get( + &snap_namespace); + ceph_assert(info); + + if (info->mirror_peer_uuids.size() > 1 || + info->mirror_peer_uuids.count(m_mirror_peer_uuid) == 0) { + finish(0); + return; + } + + auto ctx = create_context_callback< + UnlinkPeerRequest, &UnlinkPeerRequest::handle_remove_snapshot>(this); + m_image_ctx->operations->snap_remove(snap_namespace, snap_name, ctx); +} + +template +void UnlinkPeerRequest::handle_remove_snapshot(int r) { + CephContext *cct = m_image_ctx->cct; + ldout(cct, 20) << "r=" << r << dendl; + + if (r < 0 && r != -ENOENT) { + lderr(cct) << "failed to remove snapshot: " << cpp_strerror(r) << dendl; + finish(r); + return; + } + + finish(0); +} + +template +void UnlinkPeerRequest::finish(int r) { + CephContext *cct = m_image_ctx->cct; + ldout(cct, 20) << "r=" << r << dendl; + + auto on_finish = m_on_finish; + delete this; + on_finish->complete(r); +} + +} // namespace snapshot +} // namespace mirror +} // namespace librbd + +template class librbd::mirror::snapshot::UnlinkPeerRequest; diff --git a/src/librbd/mirror/snapshot/UnlinkPeerRequest.h b/src/librbd/mirror/snapshot/UnlinkPeerRequest.h new file mode 100644 index 00000000000..c42f89200d0 --- /dev/null +++ b/src/librbd/mirror/snapshot/UnlinkPeerRequest.h @@ -0,0 +1,90 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_LIBRBD_MIRROR_SNAPSHOT_UNLINK_PEER_REQUEST_H +#define CEPH_LIBRBD_MIRROR_SNAPSHOT_UNLINK_PEER_REQUEST_H + +#include "include/buffer.h" + +#include +#include + +struct Context; + +namespace librbd { + +struct ImageCtx; + +namespace mirror { +namespace snapshot { + +template +class UnlinkPeerRequest { +public: + static UnlinkPeerRequest *create(ImageCtxT *image_ctx, uint64_t snap_id, + const std::string &mirror_peer_uuid, + Context *on_finish) { + return new UnlinkPeerRequest(image_ctx, snap_id, mirror_peer_uuid, + on_finish); + } + + UnlinkPeerRequest(ImageCtxT *image_ctx, uint64_t snap_id, + const std::string &mirror_peer_uuid, Context *on_finish) + : m_image_ctx(image_ctx), m_snap_id(snap_id), + m_mirror_peer_uuid(mirror_peer_uuid), m_on_finish(on_finish) { + } + + void send(); + +private: + /* + * @verbatim + * + * + * | + * v + * REFRESH_IMAGE <--------------------------\ + * | ^ (not found | + * | * or last) | + * | * | + * |\---------------> UNLINK_PEER --> NOTIFY_UPDATE + * | (peer not last) + * | + * | + * |\---------------> REMOVE_SNAPSHOT + * | (peer last) | + * | | + * |(peer not found) | + * v | + * <---------------/ + * + * @endverbatim + */ + + ImageCtxT *m_image_ctx; + uint64_t m_snap_id; + std::string m_mirror_peer_uuid; + Context *m_on_finish; + + void refresh_image(); + void handle_refresh_image(int r); + + void unlink_peer(); + void handle_unlink_peer(int r); + + void notify_update(); + void handle_notify_update(int r); + + void remove_snapshot(); + void handle_remove_snapshot(int r); + + void finish(int r); +}; + +} // namespace snapshot +} // namespace mirror +} // namespace librbd + +extern template class librbd::mirror::snapshot::UnlinkPeerRequest; + +#endif // CEPH_LIBRBD_MIRROR_SNAPSHOT_UNLINK_PEER_REQUEST_H diff --git a/src/test/librbd/CMakeLists.txt b/src/test/librbd/CMakeLists.txt index 64e67f9485f..7f08342f97d 100644 --- a/src/test/librbd/CMakeLists.txt +++ b/src/test/librbd/CMakeLists.txt @@ -85,6 +85,7 @@ set(unittest_librbd_srcs managed_lock/test_mock_GetLockerRequest.cc managed_lock/test_mock_ReacquireRequest.cc managed_lock/test_mock_ReleaseRequest.cc + mirror/snapshot/test_mock_UnlinkPeerRequest.cc mirror/test_mock_DisableRequest.cc object_map/test_mock_InvalidateRequest.cc object_map/test_mock_LockRequest.cc diff --git a/src/test/librbd/mirror/snapshot/test_mock_UnlinkPeerRequest.cc b/src/test/librbd/mirror/snapshot/test_mock_UnlinkPeerRequest.cc new file mode 100644 index 00000000000..3c81aef865b --- /dev/null +++ b/src/test/librbd/mirror/snapshot/test_mock_UnlinkPeerRequest.cc @@ -0,0 +1,344 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "test/librbd/test_mock_fixture.h" +#include "test/librbd/test_support.h" +#include "test/librbd/mock/MockImageCtx.h" +#include "test/librbd/mock/MockOperations.h" +#include "test/librados_test_stub/MockTestMemIoCtxImpl.h" +#include "test/librados_test_stub/MockTestMemRadosClient.h" +#include "librbd/mirror/snapshot/UnlinkPeerRequest.h" + +namespace librbd { + +namespace { + +struct MockTestImageCtx : public MockImageCtx { + explicit MockTestImageCtx(librbd::ImageCtx& image_ctx) : MockImageCtx(image_ctx) { + } +}; + +} // anonymous namespace +} // namespace librbd + +// template definitions +#include "librbd/mirror/snapshot/UnlinkPeerRequest.cc" +template class librbd::mirror::snapshot::UnlinkPeerRequest; + +namespace librbd { +namespace mirror { +namespace snapshot { + +using ::testing::_; +using ::testing::DoAll; +using ::testing::InSequence; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::StrEq; + +class TestMockMirrorSnapshotUnlinkPeerRequest : public TestMockFixture { +public: + typedef UnlinkPeerRequest MockUnlinkPeerRequest; + + uint64_t m_snap_seq = 0; + + uint64_t snap_create(MockTestImageCtx &mock_image_ctx, + const cls::rbd::SnapshotNamespace &ns, + const std::string& snap_name) { + EXPECT_TRUE(mock_image_ctx.snap_info.insert( + {++m_snap_seq, + SnapInfo{snap_name, ns, 0, {}, 0, 0, {}}}).second); + return m_snap_seq; + } + + void expect_get_snap_info(MockTestImageCtx &mock_image_ctx, + librados::snap_t snap_id) { + EXPECT_CALL(mock_image_ctx, get_snap_info(snap_id)) + .WillRepeatedly(Invoke([&mock_image_ctx]( + librados::snap_t snap_id) -> librbd::SnapInfo * { + auto it = mock_image_ctx.snap_info.find(snap_id); + if (it == mock_image_ctx.snap_info.end()) { + return nullptr; + } + return &it->second; + })); + } + + void expect_is_refresh_required(MockTestImageCtx &mock_image_ctx, + bool refresh_required) { + EXPECT_CALL(*mock_image_ctx.state, is_refresh_required()) + .WillOnce(Return(refresh_required)); + } + + void expect_refresh_image(MockTestImageCtx &mock_image_ctx, int r) { + EXPECT_CALL(*mock_image_ctx.state, refresh(_)) + .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); + } + + void expect_unlink_peer(MockTestImageCtx &mock_image_ctx, uint64_t snap_id, + const std::string &peer_uuid, int r) { + using ceph::encode; + bufferlist bl; + encode(snapid_t{snap_id}, bl); + encode(peer_uuid, bl); + + EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), + exec(mock_image_ctx.header_oid, _, StrEq("rbd"), + StrEq("mirror_image_snapshot_unlink_peer"), + ContentsEqual(bl), _, _)) + .WillOnce(Invoke([&mock_image_ctx, snap_id, peer_uuid, r](auto&&... args) -> int { + if (r == 0) { + auto it = mock_image_ctx.snap_info.find(snap_id); + EXPECT_NE(it, mock_image_ctx.snap_info.end()); + auto info = + boost::get( + &it->second.snap_namespace); + EXPECT_NE(nullptr, info); + EXPECT_NE(0, info->mirror_peer_uuids.erase( + peer_uuid)); + } + return r; + })); + } + + void expect_notify_update(MockTestImageCtx &mock_image_ctx, int r) { + EXPECT_CALL(mock_image_ctx, notify_update(_)) + .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); + } + + void expect_remove_snapshot(MockTestImageCtx &mock_image_ctx, + uint64_t snap_id, int r) { + EXPECT_CALL(*mock_image_ctx.operations, snap_remove(_, _, _)) + .WillOnce(Invoke([&mock_image_ctx, snap_id, r]( + const cls::rbd::SnapshotNamespace &snap_namespace, + const std::string &snap_name, Context *on_finish) { + if (r == 0) { + auto it = mock_image_ctx.snap_info.find(snap_id); + EXPECT_NE(it, mock_image_ctx.snap_info.end()); + EXPECT_EQ(it->second.snap_namespace, snap_namespace); + EXPECT_EQ(it->second.name, snap_name); + mock_image_ctx.snap_info.erase(it); + } + mock_image_ctx.image_ctx->op_work_queue->queue( + on_finish, r); + })); + } +}; + +TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, Success) { + REQUIRE_FORMAT_V2(); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + cls::rbd::MirrorPrimarySnapshotNamespace ns{false, {"peer1_uuid", "peer2_uuid"}}; + auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap"); + + expect_get_snap_info(mock_image_ctx, snap_id); + + InSequence seq; + + expect_is_refresh_required(mock_image_ctx, true); + expect_refresh_image(mock_image_ctx, 0); + expect_unlink_peer(mock_image_ctx, snap_id, "peer1_uuid", 0); + expect_notify_update(mock_image_ctx, 0); + expect_refresh_image(mock_image_ctx, 0); + + C_SaferCond ctx; + auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer1_uuid", + &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); +} + +TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, RemoveSnapshot) { + REQUIRE_FORMAT_V2(); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + cls::rbd::MirrorPrimarySnapshotNamespace ns{false, {"peer_uuid"}}; + auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap"); + + expect_get_snap_info(mock_image_ctx, snap_id); + + InSequence seq; + + expect_is_refresh_required(mock_image_ctx, true); + expect_refresh_image(mock_image_ctx, 0); + expect_remove_snapshot(mock_image_ctx, snap_id, 0); + + C_SaferCond ctx; + auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer_uuid", + &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); +} + +TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, SnapshotDNE) { + REQUIRE_FORMAT_V2(); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + + expect_get_snap_info(mock_image_ctx, 123); + + InSequence seq; + + expect_is_refresh_required(mock_image_ctx, true); + expect_refresh_image(mock_image_ctx, 0); + + C_SaferCond ctx; + auto req = new MockUnlinkPeerRequest(&mock_image_ctx, 123, "peer_uuid", &ctx); + req->send(); + ASSERT_EQ(-ENOENT, ctx.wait()); +} + +TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, PeerDNE) { + REQUIRE_FORMAT_V2(); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + cls::rbd::MirrorPrimarySnapshotNamespace ns{false, {"peer_uuid"}}; + auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap"); + + expect_get_snap_info(mock_image_ctx, snap_id); + + InSequence seq; + + expect_is_refresh_required(mock_image_ctx, true); + expect_refresh_image(mock_image_ctx, 0); + + C_SaferCond ctx; + auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "unknown_peer", + &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); +} + +TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, InvalidSnapshot) { + REQUIRE_FORMAT_V2(); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + cls::rbd::UserSnapshotNamespace ns; + auto snap_id = snap_create(mock_image_ctx, ns, "user_snap"); + + expect_get_snap_info(mock_image_ctx, snap_id); + + InSequence seq; + + expect_is_refresh_required(mock_image_ctx, false); + + C_SaferCond ctx; + auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer_uuid", + &ctx); + req->send(); + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, RefreshError) { + REQUIRE_FORMAT_V2(); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + + InSequence seq; + + expect_is_refresh_required(mock_image_ctx, true); + expect_refresh_image(mock_image_ctx, -EINVAL); + + C_SaferCond ctx; + auto req = new MockUnlinkPeerRequest(&mock_image_ctx, 123, "peer_uuid", &ctx); + req->send(); + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, UnlinkError) { + REQUIRE_FORMAT_V2(); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + cls::rbd::MirrorPrimarySnapshotNamespace ns{false, + {"peer1_uuid", "peer2_uuid"}}; + auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap"); + + expect_get_snap_info(mock_image_ctx, snap_id); + + InSequence seq; + + expect_is_refresh_required(mock_image_ctx, false); + expect_unlink_peer(mock_image_ctx, snap_id, "peer1_uuid", -EINVAL); + + C_SaferCond ctx; + auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer1_uuid", + &ctx); + req->send(); + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, NotifyError) { + REQUIRE_FORMAT_V2(); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + cls::rbd::MirrorPrimarySnapshotNamespace ns{false, + {"peer1_uuid", "peer2_uuid"}}; + auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap"); + + expect_get_snap_info(mock_image_ctx, snap_id); + + InSequence seq; + + expect_is_refresh_required(mock_image_ctx, false); + expect_unlink_peer(mock_image_ctx, snap_id, "peer1_uuid", 0); + expect_notify_update(mock_image_ctx, -EINVAL); + + C_SaferCond ctx; + auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer1_uuid", + &ctx); + req->send(); + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, RemoveSnapshotError) { + REQUIRE_FORMAT_V2(); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + cls::rbd::MirrorPrimarySnapshotNamespace ns{false, {"peer_uuid"}}; + auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap"); + + expect_get_snap_info(mock_image_ctx, snap_id); + + InSequence seq; + + expect_is_refresh_required(mock_image_ctx, false); + expect_remove_snapshot(mock_image_ctx, snap_id, -EINVAL); + + C_SaferCond ctx; + auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer_uuid", + &ctx); + req->send(); + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +} // namespace snapshot +} // namespace mirror +} // namespace librbd diff --git a/src/test/librbd/test_mirroring.cc b/src/test/librbd/test_mirroring.cc index e7948c62846..4970f675821 100644 --- a/src/test/librbd/test_mirroring.cc +++ b/src/test/librbd/test_mirroring.cc @@ -19,11 +19,11 @@ #include "librbd/internal.h" #include "librbd/ObjectMap.h" #include "librbd/Operations.h" +#include "librbd/api/Image.h" #include "librbd/io/AioCompletion.h" #include "librbd/io/ImageRequest.h" #include "librbd/io/ImageRequestWQ.h" #include "librbd/journal/Types.h" -#include "librbd/api/Image.h" #include "journal/Journaler.h" #include "journal/Settings.h" #include "common/Cond.h" -- 2.39.5