From a3acdbd069b5c5bd62e528cbf2fbc33fe6f23d92 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Wed, 8 Apr 2020 23:06:05 -0400 Subject: [PATCH] librbd: fixed race condition on demotion of snapshot-based mirrored image A pending refresh could occur after setting the non-primary feature flag but before the creation of the demotion snapshot. This would prevent the snapshot from being created and would leave the image in a half-primary state. Signed-off-by: Jason Dillaman --- src/librbd/api/Mirror.cc | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/librbd/api/Mirror.cc b/src/librbd/api/Mirror.cc index 99aca1414f9..4fafea2a7ab 100644 --- a/src/librbd/api/Mirror.cc +++ b/src/librbd/api/Mirror.cc @@ -669,21 +669,33 @@ void Mirror::image_demote(I *ictx, Context *on_finish) { CephContext *cct = ictx->cct; ldout(cct, 20) << "ictx=" << ictx << dendl; - auto on_refresh = new LambdaContext([ictx, on_finish](int r) { + auto on_cleanup = new LambdaContext([ictx, on_finish](int r) { + ictx->image_lock.lock(); + ictx->read_only_mask |= IMAGE_READ_ONLY_FLAG_NON_PRIMARY; + ictx->image_lock.unlock(); + + ictx->state->handle_update_notification(); + + on_finish->complete(r); + }); + auto on_refresh = new LambdaContext([ictx, on_cleanup](int r) { if (r < 0) { lderr(ictx->cct) << "refresh failed: " << cpp_strerror(r) << dendl; - on_finish->complete(r); + on_cleanup->complete(r); return; } - auto req = mirror::DemoteRequest<>::create(*ictx, on_finish); + auto req = mirror::DemoteRequest<>::create(*ictx, on_cleanup); req->send(); }); - if (ictx->state->is_refresh_required()) { - ictx->state->refresh(on_refresh); - } else { - on_refresh->complete(0); - } + + // ensure we can create a snapshot after setting the non-primary + // feature bit + ictx->image_lock.lock(); + ictx->read_only_mask &= ~IMAGE_READ_ONLY_FLAG_NON_PRIMARY; + ictx->image_lock.unlock(); + + ictx->state->refresh(on_refresh); } template -- 2.39.5