From: Jason Dillaman Date: Thu, 16 Mar 2017 16:28:41 +0000 (-0400) Subject: librbd: is_exclusive_lock_owner API should ping OSD X-Git-Tag: v10.2.8~57^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=refs%2Fpull%2F14481%2Fhead;p=ceph.git librbd: is_exclusive_lock_owner API should ping OSD This is required to detect if a peer has been silently blacklisted and is therefore no longer the lock owner. Fixes: http://tracker.ceph.com/issues/19287 Signed-off-by: Jason Dillaman (cherry picked from commit e15db05960a284bdf3701256722299d553cfd5aa) Conflicts: src/librbd/ManagedLock.[h|cc]: logic moved to ExclusiveLock (cherry picked from commit 7e30b630e2806c73ea503871599f958b58df7934) --- diff --git a/src/librbd/ExclusiveLock.cc b/src/librbd/ExclusiveLock.cc index ef37b71b7a29..43ed31b6c295 100644 --- a/src/librbd/ExclusiveLock.cc +++ b/src/librbd/ExclusiveLock.cc @@ -250,6 +250,44 @@ void ExclusiveLock::handle_peer_notification(int r) { handle_acquire_lock(r); } +template +int ExclusiveLock::assert_header_locked() { + CephContext *cct = m_image_ctx.cct; + ldout(cct, 10) << this << " " << __func__ << dendl; + + librados::ObjectReadOperation op; + { + Mutex::Locker locker(m_lock); + rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, + m_cookie, WATCHER_LOCK_TAG); + } + + int r = m_image_ctx.md_ctx.operate(m_image_ctx.header_oid, &op, nullptr); + if (r < 0) { + if (r == -EBLACKLISTED) { + ldout(cct, 5) << this << " " << __func__ << ": " + << "client is not lock owner -- client blacklisted" + << dendl; + } else if (r == -ENOENT) { + ldout(cct, 5) << this << " " << __func__ << ": " + << "client is not lock owner -- no lock detected" + << dendl; + } else if (r == -EBUSY) { + ldout(cct, 5) << this << " " << __func__ << ": " + << "client is not lock owner -- owned by different client" + << dendl; + } else { + lderr(cct) << this << " " << __func__ << ": " + << "failed to verify lock ownership: " << cpp_strerror(r) + << dendl; + } + + return r; + } + + return 0; +} + template std::string ExclusiveLock::encode_lock_cookie() const { assert(m_lock.is_locked()); diff --git a/src/librbd/ExclusiveLock.h b/src/librbd/ExclusiveLock.h index 58eaa9376893..eee61caaab01 100644 --- a/src/librbd/ExclusiveLock.h +++ b/src/librbd/ExclusiveLock.h @@ -43,6 +43,8 @@ public: void reacquire_lock(Context *on_reacquired = nullptr); + int assert_header_locked(); + void handle_peer_notification(int r); static bool decode_lock_cookie(const std::string &cookie, uint64_t *handle); diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index 70734789f634..9fecb1e1688f 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -2099,9 +2099,22 @@ int mirror_image_disable_internal(ImageCtx *ictx, bool force, int is_exclusive_lock_owner(ImageCtx *ictx, bool *is_owner) { - RWLock::RLocker l(ictx->owner_lock); - *is_owner = (ictx->exclusive_lock != nullptr && - ictx->exclusive_lock->is_lock_owner()); + *is_owner = false; + + RWLock::RLocker owner_locker(ictx->owner_lock); + if (ictx->exclusive_lock == nullptr || + !ictx->exclusive_lock->is_lock_owner()) { + return 0; + } + + // might have been blacklisted by peer -- ensure we still own + // the lock by pinging the OSD + int r = ictx->exclusive_lock->assert_header_locked(); + if (r < 0) { + return r; + } + + *is_owner = true; return 0; } diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index 5f1e7e9a1ffa..e3bf108db5c6 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -1186,6 +1186,9 @@ class TestExclusiveLock(object): image.lock_break(RBD_LOCK_MODE_EXCLUSIVE, lock_owners[0]['owner']) + assert_raises(ConnectionShutdown, + blacklist_image.is_exclusive_lock_owner) + blacklist_rados.wait_for_latest_osdmap() data = rand_data(256) assert_raises(ConnectionShutdown,