From 23d15f270acd192fe8aa76918558316a57594ad9 Mon Sep 17 00:00:00 2001 From: VinayBhaskar-V Date: Wed, 14 May 2025 01:55:44 +0530 Subject: [PATCH] rbd-mirror: prevent image deletion if remote image is not primary A resync on a mirrored image may incorrectly results in the local image being deleted even when the remote image is no longer primary. This issue can occur under the following conditions: * if resync is requested on the secondary before the remote image has been fully demoted * if the demotion of the primary image is not mirrored due to the rbd-mirror daemon being offline. This can be fixed by ensuring that image deletion during a resync is only allowed when the remote image is confirmed to be primary. This commit fixes the issue only for snapshot based mirroring mode Fixes: https://tracker.ceph.com/issues/70948 Signed-off-by: VinayBhaskar-V (cherry picked from commit e14afbc95a5fb8f5a33e7ea23a035992b966d671) --- qa/workunits/rbd/rbd_mirror.sh | 48 +++ .../snapshot/test_mock_Replayer.cc | 317 ++++++++++++------ .../snapshot/PrepareReplayRequest.cc | 5 +- .../image_replayer/snapshot/Replayer.cc | 67 ++-- .../image_replayer/snapshot/Replayer.h | 6 +- 5 files changed, 308 insertions(+), 135 deletions(-) diff --git a/qa/workunits/rbd/rbd_mirror.sh b/qa/workunits/rbd/rbd_mirror.sh index 589ed26d477..61cc0d6c8f3 100755 --- a/qa/workunits/rbd/rbd_mirror.sh +++ b/qa/workunits/rbd/rbd_mirror.sh @@ -526,6 +526,54 @@ for i in ${image2} ${image4}; do remove_image_retry ${CLUSTER2} ${POOL} ${i} done +if [ "${RBD_MIRROR_MODE}" = "snapshot" ]; then + testlog "TEST: request image resync when remote is not primary" + test_resync_image=test_resync_image + create_image_and_enable_mirror ${CLUSTER2} ${POOL} ${test_resync_image} ${RBD_MIRROR_MODE} + write_image ${CLUSTER2} ${POOL} ${test_resync_image} 100 + wait_for_image_replay_stopped ${CLUSTER2} ${POOL} ${test_resync_image} + wait_for_image_replay_started ${CLUSTER1} ${POOL} ${test_resync_image} + wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${test_resync_image} + wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${test_resync_image} + wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${test_resync_image} 'up+stopped' + write_image ${CLUSTER2} ${POOL} ${test_resync_image} 100 + demote_image ${CLUSTER2} ${POOL} ${test_resync_image} + request_resync_image ${CLUSTER1} ${POOL} ${test_resync_image} test_resync_image_id + wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${test_resync_image} 'up+unknown' 'remote image is not primary' + wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${test_resync_image} 'up+unknown' 'remote image is not primary' + promote_image ${CLUSTER1} ${POOL} ${test_resync_image} + wait_for_image_replay_started ${CLUSTER2} ${POOL} ${test_resync_image} + wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${test_resync_image} 'up+stopped' + wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${test_resync_image} 'up+replaying' + compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${test_resync_image} + remove_image_retry ${CLUSTER1} ${POOL} ${test_resync_image} + + if [ -z "${RBD_MIRROR_USE_RBD_MIRROR}" ]; then + testlog "TEST: request image resync when remote is not primary and daemon is offline" + test_resync_image=test_resync_image + create_image_and_enable_mirror ${CLUSTER2} ${POOL} ${test_resync_image} ${RBD_MIRROR_MODE} + write_image ${CLUSTER2} ${POOL} ${test_resync_image} 100 + wait_for_image_replay_stopped ${CLUSTER2} ${POOL} ${test_resync_image} + wait_for_image_replay_started ${CLUSTER1} ${POOL} ${test_resync_image} + wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${test_resync_image} + wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${test_resync_image} + wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${test_resync_image} 'up+stopped' + stop_mirrors ${CLUSTER1} + write_image ${CLUSTER2} ${POOL} ${test_resync_image} 100 + demote_image ${CLUSTER2} ${POOL} ${test_resync_image} + request_resync_image ${CLUSTER1} ${POOL} ${test_resync_image} test_resync_image_id + start_mirrors ${CLUSTER1} + wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${test_resync_image} 'up+unknown' 'remote image is not primary' + wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${test_resync_image} 'up+unknown' 'remote image is not primary' + promote_image ${CLUSTER1} ${POOL} ${test_resync_image} + wait_for_image_replay_started ${CLUSTER2} ${POOL} ${test_resync_image} + wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${test_resync_image} 'up+stopped' + wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${test_resync_image} 'up+replaying' + compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${test_resync_image} + remove_image_retry ${CLUSTER1} ${POOL} ${test_resync_image} + fi +fi + testlog "TEST: disable mirror while daemon is stopped" stop_mirrors ${CLUSTER1} stop_mirrors ${CLUSTER2} diff --git a/src/test/rbd_mirror/image_replayer/snapshot/test_mock_Replayer.cc b/src/test/rbd_mirror/image_replayer/snapshot/test_mock_Replayer.cc index 75141e5a7be..dff9cd4b65c 100644 --- a/src/test/rbd_mirror/image_replayer/snapshot/test_mock_Replayer.cc +++ b/src/test/rbd_mirror/image_replayer/snapshot/test_mock_Replayer.cc @@ -676,8 +676,8 @@ public: expect_register_update_watcher(mock_remote_image_ctx, update_watch_ctx, 234, 0); expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); C_SaferCond init_ctx; mock_replayer.init(&init_ctx); @@ -800,8 +800,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { // sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, 0); @@ -826,14 +826,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { // sync snap4 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, true); - expect_refresh( - mock_local_image_ctx, { - {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", - 1, true, 0, {{1, CEPH_NOSNAP}}}, - 0, {}, 0, 0, {}}}, - }, 0); expect_is_refresh_required(mock_remote_image_ctx, true); expect_refresh( mock_remote_image_ctx, { @@ -856,6 +848,14 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}} }, 0); + expect_is_refresh_required(mock_local_image_ctx, true); + expect_refresh( + mock_local_image_ctx, { + {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", + 1, true, 0, {{1, CEPH_NOSNAP}}}, + 0, {}, 0, 0, {}}}, + }, 0); expect_snapshot_copy(mock_snapshot_copy_request, 1, 4, 11, {{1, 11}, {2, 12}, {4, CEPH_NOSNAP}}, 0); expect_get_image_state(mock_get_image_state_request, 4, 0); @@ -877,20 +877,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { // prune non-primary snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, true); - expect_refresh( - mock_local_image_ctx, { - {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", - 1, true, 0, {}}, - 0, {}, 0, 0, {}}}, - {12U, librbd::SnapInfo{"snap2", cls::rbd::UserSnapshotNamespace{}, - 0, {}, 0, 0, {}}}, - {14U, librbd::SnapInfo{"snap4", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", - 4, true, 0, {}}, - 0, {}, 0, 0, {}}}, - }, 0); expect_is_refresh_required(mock_remote_image_ctx, true); expect_refresh( mock_remote_image_ctx, { @@ -909,18 +895,24 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}} }, 0); - expect_prune_non_primary_snapshot(mock_local_image_ctx, 11, 0); - - // idle - expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { + {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", + 1, true, 0, {}}, + 0, {}, 0, 0, {}}}, + {12U, librbd::SnapInfo{"snap2", cls::rbd::UserSnapshotNamespace{}, + 0, {}, 0, 0, {}}}, {14U, librbd::SnapInfo{"snap4", cls::rbd::MirrorSnapshotNamespace{ cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", 4, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); + expect_prune_non_primary_snapshot(mock_local_image_ctx, 11, 0); + + // idle + expect_load_image_meta(mock_image_meta, false, 0); expect_is_refresh_required(mock_remote_image_ctx, true); expect_refresh( mock_remote_image_ctx, { @@ -929,6 +921,14 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}} }, 0); + expect_is_refresh_required(mock_local_image_ctx, true); + expect_refresh( + mock_local_image_ctx, { + {14U, librbd::SnapInfo{"snap4", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", + 4, true, 0, {}}, + 0, {}, 0, 0, {}}}, + }, 0); // fire init C_SaferCond init_ctx; @@ -990,8 +990,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncInitial) { // re-sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockGetImageStateRequest mock_get_image_state_request; expect_get_image_state(mock_get_image_state_request, 11, 0); expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); @@ -1008,6 +1008,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncInitial) { // idle expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -1016,7 +1017,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncInitial) { 1, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, false); // wake-up replayer update_watch_ctx->handle_notify(); @@ -1084,8 +1084,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDelta) { // re-sync snap2 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockGetImageStateRequest mock_get_image_state_request; expect_get_image_state(mock_get_image_state_request, 12, 0); expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); @@ -1105,6 +1105,14 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDelta) { // prune non-primary snap1 expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, true); + expect_refresh( + mock_remote_image_ctx, { + {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, + "", CEPH_NOSNAP, true, 0, {}}, + 0, {}, 0, 0, {}}}, + }, 0); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -1117,18 +1125,11 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDelta) { 2, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, true); - expect_refresh( - mock_remote_image_ctx, { - {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, - "", CEPH_NOSNAP, true, 0, {}}, - 0, {}, 0, 0, {}}}, - }, 0); expect_prune_non_primary_snapshot(mock_local_image_ctx, 11, 0); // idle expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -1137,7 +1138,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDelta) { 2, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, false); // wake-up replayer update_watch_ctx->handle_notify(); @@ -1206,8 +1206,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDeltaDemote) { // re-sync snap2 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockGetImageStateRequest mock_get_image_state_request; expect_get_image_state(mock_get_image_state_request, 12, 0); expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); @@ -1227,6 +1227,14 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDeltaDemote) { // idle expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, true); + expect_refresh( + mock_remote_image_ctx, { + {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, + "", CEPH_NOSNAP, true, 0, {}}, + 0, {}, 0, 0, {}}}, + }, 0); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -1239,14 +1247,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSyncDeltaDemote) { 2, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, true); - expect_refresh( - mock_remote_image_ctx, { - {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, - "", CEPH_NOSNAP, true, 0, {}}, - 0, {}, 0, 0, {}}}, - }, 0); // wake-up replayer update_watch_ctx->handle_notify(); @@ -1305,8 +1305,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncInitial) { // re-sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockGetImageStateRequest mock_get_image_state_request; expect_get_image_state(mock_get_image_state_request, 11, 0); expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); @@ -1322,6 +1322,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncInitial) { // idle expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -1330,7 +1331,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncInitial) { 1, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, false); // wake-up replayer update_watch_ctx->handle_notify(); @@ -1398,12 +1398,13 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDelta) { // prune non-primary snap2 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); expect_prune_non_primary_snapshot(mock_local_image_ctx, 12, 0); // sync snap2 expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -1412,7 +1413,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDelta) { 1, true, 0, {{1, CEPH_NOSNAP}}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 1, 2, 11, {{2, CEPH_NOSNAP}}, 0); @@ -1438,6 +1438,14 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDelta) { // prune non-primary snap1 expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, true); + expect_refresh( + mock_remote_image_ctx, { + {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, + "", CEPH_NOSNAP, true, 0, {}}, + 0, {}, 0, 0, {}}}, + }, 0); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -1450,18 +1458,11 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDelta) { 2, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, true); - expect_refresh( - mock_remote_image_ctx, { - {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, - "", CEPH_NOSNAP, true, 0, {}}, - 0, {}, 0, 0, {}}}, - }, 0); expect_prune_non_primary_snapshot(mock_local_image_ctx, 11, 0); // idle expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -1470,7 +1471,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDelta) { 2, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, false); // wake-up replayer update_watch_ctx->handle_notify(); @@ -1539,12 +1539,13 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDeltaDemote) // prune non-primary snap2 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); expect_prune_non_primary_snapshot(mock_local_image_ctx, 12, 0); // sync snap2 expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -1553,7 +1554,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDeltaDemote) {"remote mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 1, 2, 11, {{2, CEPH_NOSNAP}}, 0); @@ -1579,6 +1579,14 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDeltaDemote) // idle expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, true); + expect_refresh( + mock_remote_image_ctx, { + {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, + "", CEPH_NOSNAP, true, 0, {}}, + 0, {}, 0, 0, {}}}, + }, 0); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -1591,14 +1599,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedPendingSyncDeltaDemote) 2, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, true); - expect_refresh( - mock_remote_image_ctx, { - {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, - "", CEPH_NOSNAP, true, 0, {}}, - 0, {}, 0, 0, {}}}, - }, 0); // wake-up replayer update_watch_ctx->handle_notify(); @@ -1652,8 +1652,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteImageDemoted) { // sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, 0); @@ -1678,6 +1678,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteImageDemoted) { // idle expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -1686,7 +1687,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteImageDemoted) { 1, true, 0, {}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, false); // wake-up replayer update_watch_ctx->handle_notify(); @@ -1741,8 +1741,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, LocalImagePromoted) { // idle expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); // wake-up replayer update_watch_ctx->handle_notify(); @@ -1787,9 +1787,16 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, ResyncRequested) { mock_replayer_listener, mock_image_meta, &update_watch_ctx)); + // inject a primary snapshot + mock_remote_image_ctx.snap_info = { + {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, + "", CEPH_NOSNAP, true, 0, {}}, + 0, {}, 0, 0, {}}}}; // idle expect_load_image_meta(mock_image_meta, true, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); // wake-up replayer update_watch_ctx->handle_notify(); @@ -1803,6 +1810,94 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, ResyncRequested) { mock_remote_image_ctx)); } +TEST_F(TestMockImageReplayerSnapshotReplayer, ResyncRequestedRemoteNotPrimary) { + librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; + librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; + + MockThreads mock_threads(m_threads); + expect_work_queue_repeatedly(mock_threads); + + MockReplayerListener mock_replayer_listener; + expect_notification(mock_threads, mock_replayer_listener); + + InSequence seq; + + MockInstanceWatcher mock_instance_watcher; + MockImageMeta mock_image_meta; + MockStateBuilder mock_state_builder(mock_local_image_ctx, + mock_remote_image_ctx, + mock_image_meta); + MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, + "local mirror uuid", &m_pool_meta_cache, + &mock_state_builder, &mock_replayer_listener}; + m_pool_meta_cache.set_remote_pool_meta( + m_remote_io_ctx.get_id(), + {"remote mirror uuid", "remote mirror peer uuid"}); + + librbd::UpdateWatchCtx* update_watch_ctx = nullptr; + ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, + mock_local_image_ctx, + mock_remote_image_ctx, + mock_replayer_listener, + mock_image_meta, + &update_watch_ctx)); + + // inject a demotion snapshot + mock_remote_image_ctx.snap_info = { + {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, + {"remote mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, + 0, {}, 0, 0, {}}}}; + + // resync requested + expect_load_image_meta(mock_image_meta, true, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); + + // remote is not primary so no resync should occur + expect_is_refresh_required(mock_local_image_ctx, false); + MockSnapshotCopyRequest mock_snapshot_copy_request; + expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, + {{1, CEPH_NOSNAP}}, 0); + MockGetImageStateRequest mock_get_image_state_request; + expect_get_image_state(mock_get_image_state_request, 1, 0); + MockCreateNonPrimaryRequest mock_create_non_primary_request; + expect_create_non_primary_request(mock_create_non_primary_request, + true, "remote mirror uuid", 1, + {{1, CEPH_NOSNAP}}, 11, 0); + MockImageStateUpdateRequest mock_image_state_update_request; + expect_update_mirror_image_state(mock_image_state_update_request, 0); + expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); + MockImageCopyRequest mock_image_copy_request; + expect_image_copy(mock_image_copy_request, 0, 1, 0, {}, + {{1, CEPH_NOSNAP}}, 0); + MockApplyImageStateRequest mock_apply_state_request; + expect_apply_image_state(mock_apply_state_request, 0); + expect_mirror_image_snapshot_set_copy_progress( + mock_local_image_ctx, 11, true, 0, 0); + expect_notify_update(mock_local_image_ctx); + expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); + expect_load_image_meta(mock_image_meta, true, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, true); + expect_refresh( + mock_local_image_ctx, { + {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED, {"uuid"}, + "remote mirror uuid", 1, true, 0, {{1, CEPH_NOSNAP}}}, + 0, {}, 0, 0, {}}}, + }, 0); + + // wake-up replayer + update_watch_ctx->handle_notify(); + + ASSERT_EQ(0, wait_for_notification(1)); + ASSERT_FALSE(mock_replayer.is_replaying()); + + ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, + mock_local_image_ctx, + mock_remote_image_ctx)); +} + TEST_F(TestMockImageReplayerSnapshotReplayer, RegisterLocalUpdateWatcherError) { librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; @@ -2039,6 +2134,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RefreshLocalImageError) { // sync expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh(mock_local_image_ctx, {}, -EINVAL); @@ -2089,7 +2185,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RefreshRemoteImageError) { // sync expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, true); expect_refresh(mock_remote_image_ctx, {}, -EINVAL); @@ -2147,8 +2242,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CopySnapshotsError) { // sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, -EINVAL); @@ -2207,8 +2302,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, GetImageStateError) { // sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, 0); @@ -2269,8 +2364,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CreateNonPrimarySnapshotError) { // sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, 0); @@ -2335,8 +2430,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UpdateMirrorImageStateError) { // sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, 0); @@ -2403,8 +2498,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RequestSyncError) { // sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, 0); @@ -2473,8 +2568,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, CopyImageError) { // sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, 0); @@ -2546,8 +2641,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UpdateNonPrimarySnapshotError) { // sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, 0); @@ -2632,8 +2727,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnlinkPeerError) { // sync snap2 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 1, 2, 11, {{2, CEPH_NOSNAP}}, 0); @@ -2716,8 +2811,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SplitBrain) { // detect split-brain expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); // wake-up replayer update_watch_ctx->handle_notify(); @@ -2784,8 +2879,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteSnapshotMissingSplitBrain) { // split-brain due to missing snapshot 1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); // wake-up replayer update_watch_ctx->handle_notify(); @@ -2858,8 +2953,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteFailover) { // attach to promoted remote image expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 2, 3, 12, {{2, 12}, {3, CEPH_NOSNAP}}, 0); @@ -2886,6 +2981,20 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteFailover) { // idle expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, true); + expect_refresh( + mock_remote_image_ctx, { + {1U, librbd::SnapInfo{"snap1", cls::rbd::UserSnapshotNamespace{}, + 0, {}, 0, 0, {}}}, + {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED, + {"remote mirror peer uuid"}, "local mirror uuid", 12U, true, 0, {}}, + 0, {}, 0, 0, {}}}, + {3U, librbd::SnapInfo{"snap3", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {}, "", CEPH_NOSNAP, true, 0, + {}}, + 0, {}, 0, 0, {}}} + }, 0); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -2901,20 +3010,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteFailover) { {{1, 11}, {2, 12}, {3, CEPH_NOSNAP}}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, true); - expect_refresh( - mock_remote_image_ctx, { - {1U, librbd::SnapInfo{"snap1", cls::rbd::UserSnapshotNamespace{}, - 0, {}, 0, 0, {}}}, - {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED, - {"remote mirror peer uuid"}, "local mirror uuid", 12U, true, 0, {}}, - 0, {}, 0, 0, {}}}, - {3U, librbd::SnapInfo{"snap3", cls::rbd::MirrorSnapshotNamespace{ - cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {}, "", CEPH_NOSNAP, true, 0, - {}}, - 0, {}, 0, 0, {}}} - }, 0); // wake-up replayer update_watch_ctx->handle_notify(); @@ -2977,15 +3072,14 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnlinkRemoteSnapshot) { // unlink snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockUnlinkPeerRequest mock_unlink_peer_request; expect_unlink_peer(mock_unlink_peer_request, 1, "remote mirror peer uuid", false, 0); // idle expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, true); expect_refresh( mock_remote_image_ctx, { @@ -3000,6 +3094,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, UnlinkRemoteSnapshot) { "", CEPH_NOSNAP, true, 0, {}}, 0, {}, 0, 0, {}}} }, 0); + expect_is_refresh_required(mock_local_image_ctx, false); // fire init C_SaferCond init_ctx; @@ -3055,8 +3150,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SkipImageSync) { // sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, 0); @@ -3076,6 +3171,7 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SkipImageSync) { // idle expect_load_image_meta(mock_image_meta, false, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); expect_is_refresh_required(mock_local_image_ctx, true); expect_refresh( mock_local_image_ctx, { @@ -3084,7 +3180,6 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, SkipImageSync) { 1, true, 0, {{1, CEPH_NOSNAP}}}, 0, {}, 0, 0, {}}}, }, 0); - expect_is_refresh_required(mock_remote_image_ctx, false); // fire init C_SaferCond init_ctx; @@ -3132,11 +3227,19 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, ImageNameUpdated) { mock_image_meta, &update_watch_ctx)); + // inject a primary snapshot + mock_remote_image_ctx.snap_info = { + {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ + cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, + "", CEPH_NOSNAP, true, 0, {}}, + 0, {}, 0, 0, {}}}}; + // change the name of the image mock_local_image_ctx.name = "NEW NAME"; // idle expect_load_image_meta(mock_image_meta, true, 0); + expect_is_refresh_required(mock_remote_image_ctx, false); // wake-up replayer update_watch_ctx->handle_notify(); @@ -3196,8 +3299,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, ApplyImageStatePendingShutdown) { // sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, 0); @@ -3283,8 +3386,8 @@ TEST_F(TestMockImageReplayerSnapshotReplayer, ApplyImageStateErrorPendingShutdow // sync snap1 expect_load_image_meta(mock_image_meta, false, 0); - expect_is_refresh_required(mock_local_image_ctx, false); expect_is_refresh_required(mock_remote_image_ctx, false); + expect_is_refresh_required(mock_local_image_ctx, false); MockSnapshotCopyRequest mock_snapshot_copy_request; expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, 0); diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/PrepareReplayRequest.cc b/src/tools/rbd_mirror/image_replayer/snapshot/PrepareReplayRequest.cc index 575eb8534fa..8c9a6934850 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/PrepareReplayRequest.cc +++ b/src/tools/rbd_mirror/image_replayer/snapshot/PrepareReplayRequest.cc @@ -58,7 +58,10 @@ void PrepareReplayRequest::handle_load_local_image_meta(int r) { return; } - *m_resync_requested = m_state_builder->local_image_meta->resync_requested; + if (r >= 0 && m_state_builder->local_image_meta->resync_requested && + m_state_builder->is_remote_primary()) { + *m_resync_requested = true; + } finish(0); } diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc index 645c0616f8b..20fe59ebdf7 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc +++ b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc @@ -336,6 +336,22 @@ bool Replayer::get_replay_status(std::string* description, return true; } +template +bool Replayer::is_remote_primary() { + auto remote_image_ctx = m_state_builder->remote_image_ctx; + std::shared_lock image_locker{remote_image_ctx->image_lock}; + for (auto snap_info_it = remote_image_ctx->snap_info.rbegin(); + snap_info_it != remote_image_ctx->snap_info.rend(); ++snap_info_it) { + const auto& snap_ns = snap_info_it->second.snap_namespace; + auto mirror_ns = std::get_if< + cls::rbd::MirrorSnapshotNamespace>(&snap_ns); + if (mirror_ns != nullptr) { + return mirror_ns->state == cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY; + } + } + return false; +} + template void Replayer::load_local_image_meta() { dout(10) << dendl; @@ -380,46 +396,47 @@ void Replayer::handle_load_local_image_meta(int r) { return; } - if (r >= 0 && m_state_builder->local_image_meta->resync_requested) { - m_resync_requested = true; - - dout(10) << "local image resync requested" << dendl; - handle_replay_complete(0, "resync requested"); - return; - } - - refresh_local_image(); + refresh_remote_image(); } template -void Replayer::refresh_local_image() { - if (!m_state_builder->local_image_ctx->state->is_refresh_required()) { - refresh_remote_image(); +void Replayer::refresh_remote_image() { + if (!m_state_builder->remote_image_ctx->state->is_refresh_required()) { + refresh_local_image(); return; } dout(10) << dendl; auto ctx = create_context_callback< - Replayer, &Replayer::handle_refresh_local_image>(this); - m_state_builder->local_image_ctx->state->refresh(ctx); + Replayer, &Replayer::handle_refresh_remote_image>(this); + m_state_builder->remote_image_ctx->state->refresh(ctx); } template -void Replayer::handle_refresh_local_image(int r) { +void Replayer::handle_refresh_remote_image(int r) { dout(10) << "r=" << r << dendl; if (r < 0) { - derr << "failed to refresh local image: " << cpp_strerror(r) << dendl; - handle_replay_complete(r, "failed to refresh local image"); + derr << "failed to refresh remote image: " << cpp_strerror(r) << dendl; + handle_replay_complete(r, "failed to refresh remote image"); return; } - refresh_remote_image(); + refresh_local_image(); } template -void Replayer::refresh_remote_image() { - if (!m_state_builder->remote_image_ctx->state->is_refresh_required()) { +void Replayer::refresh_local_image() { + if (m_state_builder->local_image_meta->resync_requested && + is_remote_primary()) { + std::unique_lock locker{m_lock}; + m_resync_requested = true; + + dout(10) << "local image resync requested" << dendl; + handle_replay_complete(&locker, 0, "resync requested"); + return; + } + if (!m_state_builder->local_image_ctx->state->is_refresh_required()) { std::unique_lock locker{m_lock}; scan_local_mirror_snapshots(&locker); return; @@ -427,17 +444,17 @@ void Replayer::refresh_remote_image() { dout(10) << dendl; auto ctx = create_context_callback< - Replayer, &Replayer::handle_refresh_remote_image>(this); - m_state_builder->remote_image_ctx->state->refresh(ctx); + Replayer, &Replayer::handle_refresh_local_image>(this); + m_state_builder->local_image_ctx->state->refresh(ctx); } template -void Replayer::handle_refresh_remote_image(int r) { +void Replayer::handle_refresh_local_image(int r) { dout(10) << "r=" << r << dendl; if (r < 0) { - derr << "failed to refresh remote image: " << cpp_strerror(r) << dendl; - handle_replay_complete(r, "failed to refresh remote image"); + derr << "failed to refresh local image: " << cpp_strerror(r) << dendl; + handle_replay_complete(r, "failed to refresh local image"); return; } diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h index 17d45f6bc80..6a4be2f8973 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h +++ b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.h @@ -115,10 +115,10 @@ private: * LOAD_LOCAL_IMAGE_META <----------------------------\ * | | * v (skip if not needed) | - * REFRESH_LOCAL_IMAGE | + * REFRESH_REMOTE_IMAGE | * | | * v (skip if not needed) | - * REFRESH_REMOTE_IMAGE | + * REFRESH_LOCAL_IMAGE | * | | * | (unused non-primary snapshot) | * |\--------------> PRUNE_NON_PRIMARY_SNAPSHOT---/| @@ -257,6 +257,8 @@ private: PerfCounters *m_perf_counters = nullptr; + bool is_remote_primary(); + void load_local_image_meta(); void handle_load_local_image_meta(int r); -- 2.39.5