From 63f6c9bac9a437d1315e7bf8295926a33de1a954 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Mon, 23 Feb 2015 12:16:39 -0500 Subject: [PATCH] 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 --- src/librbd/ImageWatcher.cc | 4 ++++ src/librbd/internal.cc | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) 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; -- 2.47.3