From: Jason Dillaman Date: Mon, 23 Feb 2015 17:16:39 +0000 (-0500) Subject: librbd: fixed snap create race conditions X-Git-Tag: v0.93~15^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=refs%2Fpull%2F3777%2Fhead;p=ceph.git librbd: fixed snap create race conditions 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 --- diff --git a/src/librbd/ImageWatcher.cc b/src/librbd/ImageWatcher.cc index 41608eb44741..a1afa1eb8ef0 100644 --- a/src/librbd/ImageWatcher.cc +++ b/src/librbd/ImageWatcher.cc @@ -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)); diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index 542ad434dc35..e4584acc64e0 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -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;