From 59df5ce246926a3f08f89f331bf34cad18098bcc Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Thu, 11 Feb 2021 15:45:01 -0500 Subject: [PATCH] rbd-mirror: ensure that the last non-primary snapshot cannot be pruned Tweak the normal pruning behavior to ensure that an incomplete initial non-primary snapshot is not included in the prune set since we know it will be complete since otherwise the image would have been deleted due to not updating the mirror-image-state to enabled. Also ensure we cannot prune a non-primary mirror snapshot if we don't have a predecessor. Signed-off-by: Jason Dillaman (cherry picked from commit ecd3778a6f9a6ca33aebbf47cef79db5f04157a9) --- .../image_replayer/snapshot/Replayer.cc | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc index 075937771d94e..e7b54143508f5 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc +++ b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc @@ -405,6 +405,7 @@ void Replayer::scan_local_mirror_snapshots( std::set prune_snap_ids; + bool completed_non_primary_snapshots_exist = false; auto local_image_ctx = m_state_builder->local_image_ctx; std::shared_lock image_locker{local_image_ctx->image_lock}; for (auto snap_info_it = local_image_ctx->snap_info.begin(); @@ -426,26 +427,39 @@ void Replayer::scan_local_mirror_snapshots( // if remote has new snapshots, we would sync from here m_local_snap_id_start = local_snap_id; m_local_snap_id_end = CEPH_NOSNAP; + completed_non_primary_snapshots_exist = true; if (mirror_ns->mirror_peer_uuids.empty()) { // no other peer will attempt to sync to this snapshot so store as // a candidate for removal prune_snap_ids.insert(local_snap_id); } - } else { - if (mirror_ns->last_copied_object_number == 0) { - // snapshot might be missing image state, object-map, etc, so just - // delete and re-create it if we haven't started copying data - // objects. Also only prune this snapshot since we will need the - // previous mirror snapshot for syncing. - prune_snap_ids.clear(); - prune_snap_ids.insert(local_snap_id); - break; + } else if (mirror_ns->last_copied_object_number == 0 && + m_local_snap_id_start > 0) { + // shouldn't be possible, but ensure that pruning this snapshot + // wouldn't leave this image w/o any non-primary snapshots + if (!completed_non_primary_snapshots_exist) { + derr << "incomplete local non-primary snapshot" << dendl; + handle_replay_complete(locker, -EINVAL, + "incomplete local non-primary snapshot"); + return; } + // snapshot might be missing image state, object-map, etc, so just + // delete and re-create it if we haven't started copying data + // objects. Also only prune this snapshot since we will need the + // previous mirror snapshot for syncing. Special case exception for + // the first non-primary snapshot since we know its snapshot is + // well-formed because otherwise the mirror-image-state would have + // forced an image deletion. + prune_snap_ids.clear(); + prune_snap_ids.insert(local_snap_id); + break; + } else { // start snap will be last complete mirror snapshot or initial // image revision m_local_snap_id_end = local_snap_id; + break; } } else if (mirror_ns->is_primary()) { if (mirror_ns->complete) { -- 2.39.5