From: Jason Dillaman Date: Thu, 9 Apr 2020 03:06:05 +0000 (-0400) Subject: librbd: fixed race condition on demotion of snapshot-based mirrored image X-Git-Tag: v15.2.2~44^2~22 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=ea71fc8008c01e1d4c43a1310510960737133c38;p=ceph.git 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 (cherry picked from commit a3acdbd069b5c5bd62e528cbf2fbc33fe6f23d92) --- diff --git a/src/librbd/api/Mirror.cc b/src/librbd/api/Mirror.cc index de8e58604d559..e11863f0e4479 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