]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: fixed snap create race conditions 3777/head
authorJason Dillaman <dillaman@redhat.com>
Mon, 23 Feb 2015 17:16:39 +0000 (12:16 -0500)
committerJason Dillaman <dillaman@redhat.com>
Mon, 23 Feb 2015 17:46:33 +0000 (12:46 -0500)
Since the post-snap create header update runs asynchrously
in a finalizer callback, it's possible that the snapshot
is not immediately visible.  Also, if a proxied snap create
message is replayed, it's possible for the client to receive
a EEXISTS error.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/librbd/ImageWatcher.cc
src/librbd/internal.cc

index 41608eb4474148f4f59c43a70ba3aa2ec1b05cff..a1afa1eb8ef048ae6217cee470305fe03a1ab5fe 100644 (file)
@@ -895,6 +895,10 @@ void ImageWatcher::handle_payload(const SnapCreatePayload &payload,
 
     ::encode(ResponseMessage(r), *out);
     if (r == 0) {
+      // increment now to avoid race due to the delayed notification
+      Mutex::Locker lictx(m_image_ctx.refresh_lock);
+      ++m_image_ctx.refresh_seq;
+
       // cannot notify within a notificiation
       FunctionContext *ctx = new FunctionContext(
        boost::bind(&ImageWatcher::finalize_header_update, this));
index 542ad434dc358d3608c44505ff686ffda71893bf..e4584acc64e038f9f47e839808e642fc5f20cf20 100644 (file)
@@ -479,6 +479,13 @@ namespace librbd {
     if (r < 0)
       return r;
 
+    {
+      RWLock::RLocker l(ictx->snap_lock);
+      if (ictx->get_snap_id(snap_name) != CEPH_NOSNAP) {
+        return -EEXIST;
+      }
+    }
+
     bool lock_owner = false;
     while (ictx->image_watcher->is_lock_supported()) {
       r = prepare_image_update(ictx);
@@ -490,7 +497,9 @@ namespace librbd {
       }
 
       r = ictx->image_watcher->notify_snap_create(snap_name);
-      if (r != -ETIMEDOUT) {
+      if (r == -EEXIST) {
+        return 0;
+      } else if (r != -ETIMEDOUT) {
        return r;
       }
       ldout(ictx->cct, 5) << "snap_create timed out notifying lock owner" << dendl;