From: Jason Dillaman Date: Thu, 11 Feb 2021 20:45:01 +0000 (-0500) Subject: rbd-mirror: ensure that the last non-primary snapshot cannot be pruned X-Git-Tag: v16.2.0~185^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=b4db13c433fea13a713d779b1a72f94f4d40291d;p=ceph.git 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) --- diff --git a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc index 5be76aa0683c..bde515084750 100644 --- a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc +++ b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc @@ -404,6 +404,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(); @@ -425,26 +426,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) {