]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: prevent racing clone and snap unprotect
authorJosh Durgin <josh.durgin@inktank.com>
Wed, 29 Aug 2012 00:24:47 +0000 (17:24 -0700)
committerJosh Durgin <josh.durgin@inktank.com>
Tue, 18 Sep 2012 22:18:59 +0000 (15:18 -0700)
If the following sequence of events occured,
a clone could be created of an unprotected snapshot:

1. A: begin clone - check that snap foo is protected
2. B: rbd unprotect snap foo
3. B: check that all pools have no clones of foo
4. B: unprotect snap foo
5. A: finish creating clone of foo, add it as a child

To stop this from happening, check at the beginning and end of
cloning that the parent snapshot is protected. If it is not,
or checking protection status fails (possibly because the parent
snapshot was removed), remove the clone and return an error.

Signed-off-by: Josh Durgin <josh.durgin@inktank.com>
src/librbd/internal.cc

index 4d8b0a4ba463af2151c328c980b60172599149d9..b394ddbcda839d7eeebb1dde3bcc0effccfe7686 100644 (file)
@@ -859,11 +859,29 @@ reprotect_and_return_err:
       lderr(cct) << "couldn't add child: " << r << dendl;
       goto err_close_child;
     }
+
+    p_imctx->snap_lock.Lock();
+    r = p_imctx->is_snap_protected(p_imctx->snap_name, &snap_protected);
+    p_imctx->snap_lock.Unlock();
+
+    if (r < 0 || !snap_protected) {
+      // we lost the race with unprotect
+      r = -EINVAL;
+      goto err_remove_child;
+    }
+
     ldout(cct, 2) << "done." << dendl;
     close_image(c_imctx);
     close_image(p_imctx);
     return 0;
 
+  err_remove_child:
+    remove_r = cls_client::remove_child(&c_ioctx, RBD_CHILDREN, pspec,
+                                       c_imctx->id);
+    if (remove_r < 0) {
+     lderr(cct) << "Error removing failed clone from list of children: "
+                << cpp_strerror(remove_r) << dendl;
+    }
   err_close_child:
     close_image(c_imctx);
   err_remove: