]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: fixed race condition on demotion of snapshot-based mirrored image
authorJason Dillaman <dillaman@redhat.com>
Thu, 9 Apr 2020 03:06:05 +0000 (23:06 -0400)
committerNathan Cutler <ncutler@suse.com>
Tue, 28 Apr 2020 18:52:10 +0000 (20:52 +0200)
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 <dillaman@redhat.com>
(cherry picked from commit a3acdbd069b5c5bd62e528cbf2fbc33fe6f23d92)

src/librbd/api/Mirror.cc

index de8e58604d559204e8b798ebbc2893acaa7d27ff..e11863f0e4479aca9662b80d4bbedce708f5f011 100644 (file)
@@ -669,21 +669,33 @@ void Mirror<I>::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 <typename I>