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>
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: