From 1a34fcefeeb1a338d4a00b89c693ff2d05186f37 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Wed, 18 Jan 2017 10:44:52 -0500 Subject: [PATCH] test: separate testing of exclusive lock from managed lock Signed-off-by: Jason Dillaman --- src/librbd/ExclusiveLock.cc | 68 +- src/librbd/ManagedLock.cc | 17 +- src/librbd/ManagedLock.h | 99 ++- src/test/librbd/test_mock_ExclusiveLock.cc | 870 ++++++--------------- 4 files changed, 376 insertions(+), 678 deletions(-) diff --git a/src/librbd/ExclusiveLock.cc b/src/librbd/ExclusiveLock.cc index 7d8e19ba296..b500a980e14 100644 --- a/src/librbd/ExclusiveLock.cc +++ b/src/librbd/ExclusiveLock.cc @@ -14,7 +14,8 @@ #define dout_subsys ceph_subsys_rbd #undef dout_prefix -#define dout_prefix *_dout << "librbd::ExclusiveLock: " << this << " " << __func__ +#define dout_prefix *_dout << "librbd::ExclusiveLock: " << this << " " \ + << __func__ namespace librbd { @@ -30,16 +31,17 @@ ExclusiveLock::ExclusiveLock(I &image_ctx) image_ctx.blacklist_on_break_lock, image_ctx.blacklist_expire_seconds), m_image_ctx(image_ctx), m_pre_post_callback(nullptr), - m_shutting_down(false) { - ML::m_state = ML::STATE_UNINITIALIZED; + m_shutting_down(false) { + Mutex::Locker locker(ML::m_lock); + ML::set_state_uninitialized(); } template bool ExclusiveLock::accept_requests(int *ret_val) const { Mutex::Locker locker(ML::m_lock); - bool accept_requests = (!ML::is_shutdown_locked() && - ML::m_state == ML::STATE_LOCKED && + bool accept_requests = (!ML::is_state_shutdown() && + ML::is_state_locked() && m_request_blocked_count == 0); *ret_val = m_request_blocked_ret_val; @@ -79,8 +81,7 @@ void ExclusiveLock::init(uint64_t features, Context *on_init) { { Mutex::Locker locker(ML::m_lock); - assert(ML::m_state == ML::STATE_UNINITIALIZED); - ML::m_state = ML::STATE_INITIALIZING; + ML::set_state_initializing(); } m_image_ctx.aio_work_queue->block_writes(new C_InitComplete(this, on_init)); @@ -102,12 +103,12 @@ void ExclusiveLock::shut_down(Context *on_shut_down) { template void ExclusiveLock::handle_peer_notification(int r) { Mutex::Locker locker(ML::m_lock); - if (ML::m_state != ML::STATE_WAITING_FOR_LOCK) { + if (!ML::is_state_waiting_for_lock()) { return; } ldout(m_image_ctx.cct, 10) << dendl; - assert(ML::get_active_action() == ML::ACTION_ACQUIRE_LOCK); + assert(ML::is_action_acquire_lock()); m_acquire_lock_peer_ret_val = r; ML::execute_next_action(); @@ -118,7 +119,7 @@ void ExclusiveLock::handle_init_complete() { ldout(m_image_ctx.cct, 10) << dendl; Mutex::Locker locker(ML::m_lock); - ML::m_state = ML::STATE_UNLOCKED; + ML::set_state_unlocked(); } template @@ -137,6 +138,8 @@ void ExclusiveLock::shutdown_handler(int r, Context *on_finish) { template void ExclusiveLock::pre_acquire_lock_handler(Context *on_finish) { + ldout(m_image_ctx.cct, 10) << dendl; + int acquire_lock_peer_ret_val = 0; { Mutex::Locker locker(ML::m_lock); @@ -166,24 +169,28 @@ void ExclusiveLock::post_acquire_lock_handler(int r, Context *on_finish) { return; } else if (r < 0) { ML::m_lock.Lock(); - assert(ML::m_state == ML::STATE_ACQUIRING); + assert(ML::is_state_acquiring()); // PostAcquire state machine will not run, so we need complete prepare m_image_ctx.state->handle_prepare_lock_complete(); - typename ML::Action action = ML::get_active_action(); - if (action == ML::ACTION_ACQUIRE_LOCK && r < 0 && r != -EBLACKLISTED) { - ML::m_state = ML::STATE_WAITING_FOR_LOCK; + // if lock is in-use by another client, request the lock + if (ML::is_action_acquire_lock() && (r == -EBUSY || r == -EAGAIN)) { + ML::set_state_waiting_for_lock(); ML::m_lock.Unlock(); // request the lock from a peer m_image_ctx.image_watcher->notify_request_lock(); - return; - } - ML::m_lock.Unlock(); - if (r == -EAGAIN) { - r = 0; + // inform manage lock that we have interrupted the state machine + r = -ECANCELED; + } else { + ML::m_lock.Unlock(); + + // clear error if peer owns lock + if (r == -EAGAIN) { + r = 0; + } } on_finish->complete(r); @@ -209,10 +216,9 @@ void ExclusiveLock::handle_post_acquiring_lock(int r) { Mutex::Locker locker(ML::m_lock); assert(r == 0); - assert(ML::m_state == ML::STATE_ACQUIRING); // lock is owned at this point - ML::m_state = ML::STATE_POST_ACQUIRING; + ML::set_state_post_acquiring(); } template @@ -222,8 +228,7 @@ void ExclusiveLock::handle_post_acquired_lock(int r) { Context *on_finish = nullptr; { Mutex::Locker locker(ML::m_lock); - assert(ML::m_state == ML::STATE_ACQUIRING || - ML::m_state == ML::STATE_POST_ACQUIRING); + assert(ML::is_state_acquiring() || ML::is_state_post_acquiring()); assert (m_pre_post_callback != nullptr); std::swap(m_pre_post_callback, on_finish); @@ -263,29 +268,24 @@ void ExclusiveLock::handle_pre_releasing_lock(int r) { Mutex::Locker locker(ML::m_lock); assert(r == 0); - if (!m_shutting_down) { - assert(ML::m_state == ML::STATE_PRE_RELEASING); - // all IO and ops should be blocked/canceled by this point - ML::m_state = ML::STATE_RELEASING; + // all IO and ops should be blocked/canceled by this point + if (!m_shutting_down) { + ML::set_state_releasing(); } else { - assert(ML::m_state == ML::STATE_PRE_SHUTTING_DOWN); - - // all IO and ops should be blocked/canceled by this point - ML::m_state = ML::STATE_SHUTTING_DOWN; + ML::set_state_shutting_down(); } } template void ExclusiveLock::post_release_lock_handler(bool shutting_down, int r, - Context *on_finish) { + Context *on_finish) { ldout(m_image_ctx.cct, 10) << ": r=" << r << " shutting_down=" << shutting_down << dendl; if (!shutting_down) { { Mutex::Locker locker(ML::m_lock); - assert(ML::m_state == ML::STATE_PRE_RELEASING || - ML::m_state == ML::STATE_RELEASING); + assert(ML::is_state_pre_releasing() || ML::is_state_releasing()); } if (r >= 0) { diff --git a/src/librbd/ManagedLock.cc b/src/librbd/ManagedLock.cc index 67504a9b3ec..5673694b016 100644 --- a/src/librbd/ManagedLock.cc +++ b/src/librbd/ManagedLock.cc @@ -104,7 +104,7 @@ void ManagedLock::shut_down(Context *on_shut_down) { ldout(m_cct, 10) << dendl; Mutex::Locker locker(m_lock); - assert(!is_shutdown_locked()); + assert(!is_state_shutdown()); execute_action(ACTION_SHUT_DOWN, on_shut_down); } @@ -113,7 +113,7 @@ void ManagedLock::acquire_lock(Context *on_acquired) { int r = 0; { Mutex::Locker locker(m_lock); - if (is_shutdown_locked()) { + if (is_state_shutdown()) { r = -ESHUTDOWN; } else if (m_state != STATE_LOCKED || !m_actions_contexts.empty()) { ldout(m_cct, 10) << dendl; @@ -132,7 +132,7 @@ void ManagedLock::try_acquire_lock(Context *on_acquired) { int r = 0; { Mutex::Locker locker(m_lock); - if (is_shutdown_locked()) { + if (is_state_shutdown()) { r = -ESHUTDOWN; } else if (m_state != STATE_LOCKED || !m_actions_contexts.empty()) { ldout(m_cct, 10) << dendl; @@ -151,7 +151,7 @@ void ManagedLock::release_lock(Context *on_released) { int r = 0; { Mutex::Locker locker(m_lock); - if (is_shutdown_locked()) { + if (is_state_shutdown()) { r = -ESHUTDOWN; } else if (m_state != STATE_UNLOCKED || !m_actions_contexts.empty()) { ldout(m_cct, 10) << dendl; @@ -177,7 +177,7 @@ void ManagedLock::reacquire_lock(Context *on_reacquired) { assert(active_action == ACTION_TRY_LOCK || active_action == ACTION_ACQUIRE_LOCK); execute_next_action(); - } else if (!is_shutdown_locked() && + } else if (!is_state_shutdown() && (m_state == STATE_LOCKED || m_state == STATE_ACQUIRING || m_state == STATE_POST_ACQUIRING || @@ -358,7 +358,7 @@ void ManagedLock::complete_active_action(State next_state, int r) { } template -bool ManagedLock::is_shutdown_locked() const { +bool ManagedLock::is_state_shutdown() const { assert(m_lock.is_locked()); return ((m_state == STATE_SHUTDOWN) || @@ -439,7 +439,8 @@ void ManagedLock::handle_post_acquire_lock(int r) { if (r < 0 && m_post_next_state == STATE_LOCKED) { // release_lock without calling pre and post handlers revert_to_unlock_state(r); - } else { + } else if (r != -ECANCELED) { + // fail the lock request complete_active_action(m_post_next_state, r); } } @@ -511,7 +512,7 @@ void ManagedLock::handle_reacquire_lock(int r) { << dendl; } - if (!is_shutdown_locked()) { + if (!is_state_shutdown()) { // queue a release and re-acquire of the lock since cookie cannot // be updated on older OSDs execute_action(ACTION_RELEASE_LOCK, nullptr); diff --git a/src/librbd/ManagedLock.h b/src/librbd/ManagedLock.h index baa28fdd4dc..7cbc295a936 100644 --- a/src/librbd/ManagedLock.h +++ b/src/librbd/ManagedLock.h @@ -58,15 +58,90 @@ public: bool is_shutdown() const { Mutex::Locker l(m_lock); - return is_shutdown_locked(); + return is_state_shutdown(); } - bool is_locked_state() const { +protected: + mutable Mutex m_lock; + + inline void set_state_uninitialized() { + assert(m_lock.is_locked()); + assert(m_state == STATE_UNLOCKED); + m_state = STATE_UNINITIALIZED; + } + inline void set_state_initializing() { + assert(m_lock.is_locked()); + assert(m_state == STATE_UNINITIALIZED); + m_state = STATE_INITIALIZING; + } + inline void set_state_unlocked() { + assert(m_lock.is_locked()); + assert(m_state == STATE_INITIALIZING || m_state == STATE_RELEASING); + m_state = STATE_UNLOCKED; + } + inline void set_state_waiting_for_lock() { + assert(m_lock.is_locked()); + assert(m_state == STATE_ACQUIRING); + m_state = STATE_WAITING_FOR_LOCK; + } + inline void set_state_post_acquiring() { + assert(m_lock.is_locked()); + assert(m_state == STATE_ACQUIRING); + m_state = STATE_POST_ACQUIRING; + } + inline void set_state_releasing() { + assert(m_lock.is_locked()); + assert(m_state == STATE_PRE_RELEASING); + m_state = STATE_RELEASING; + } + inline void set_state_shutting_down() { + assert(m_lock.is_locked()); + assert(m_state == STATE_PRE_SHUTTING_DOWN); + m_state = STATE_SHUTTING_DOWN; + } + + bool is_state_shutdown() const; + inline bool is_state_acquiring() const { + assert(m_lock.is_locked()); + return m_state == STATE_ACQUIRING; + } + inline bool is_state_post_acquiring() const { + assert(m_lock.is_locked()); + return m_state == STATE_POST_ACQUIRING; + } + inline bool is_state_releasing() const { + assert(m_lock.is_locked()); + return m_state == STATE_RELEASING; + } + inline bool is_state_pre_releasing() const { + assert(m_lock.is_locked()); + return m_state == STATE_PRE_RELEASING; + } + inline bool is_state_locked() const { + assert(m_lock.is_locked()); return m_state == STATE_LOCKED; } + inline bool is_state_waiting_for_lock() { + assert(m_lock.is_locked()); + return m_state == STATE_WAITING_FOR_LOCK; + } -protected: + inline bool is_action_acquire_lock() { + assert(m_lock.is_locked()); + return get_active_action() == ACTION_ACQUIRE_LOCK; + } + + virtual void shutdown_handler(int r, Context *on_finish); + virtual void pre_acquire_lock_handler(Context *on_finish); + virtual void post_acquire_lock_handler(int r, Context *on_finish); + virtual void pre_release_lock_handler(bool shutting_down, + Context *on_finish); + virtual void post_release_lock_handler(bool shutting_down, int r, + Context *on_finish); + void execute_next_action(); + +private: /** * @verbatim * @@ -124,22 +199,6 @@ protected: ACTION_SHUT_DOWN }; - mutable Mutex m_lock; - State m_state; - - virtual void shutdown_handler(int r, Context *on_finish); - virtual void pre_acquire_lock_handler(Context *on_finish); - virtual void post_acquire_lock_handler(int r, Context *on_finish); - virtual void pre_release_lock_handler(bool shutting_down, - Context *on_finish); - virtual void post_release_lock_handler(bool shutting_down, int r, - Context *on_finish); - - Action get_active_action() const; - bool is_shutdown_locked() const; - void execute_next_action(); - -private: typedef std::list Contexts; typedef std::pair ActionContexts; typedef std::list ActionsContexts; @@ -166,6 +225,7 @@ private: std::string m_cookie; std::string m_new_cookie; + State m_state; State m_post_next_state; ActionsContexts m_actions_contexts; @@ -176,6 +236,7 @@ private: void append_context(Action action, Context *ctx); void execute_action(Action action, Context *ctx); + Action get_active_action() const; void complete_active_action(State next_state, int r); diff --git a/src/test/librbd/test_mock_ExclusiveLock.cc b/src/test/librbd/test_mock_ExclusiveLock.cc index 85b5570f95f..cf046f54429 100644 --- a/src/test/librbd/test_mock_ExclusiveLock.cc +++ b/src/test/librbd/test_mock_ExclusiveLock.cc @@ -9,9 +9,6 @@ #include "librbd/exclusive_lock/PreAcquireRequest.h" #include "librbd/exclusive_lock/PostAcquireRequest.h" #include "librbd/exclusive_lock/PreReleaseRequest.h" -#include "librbd/managed_lock/AcquireRequest.h" -#include "librbd/managed_lock/ReacquireRequest.h" -#include "librbd/managed_lock/ReleaseRequest.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include @@ -37,6 +34,51 @@ struct Traits { }; } +template <> +struct ManagedLock { + ManagedLock(librados::IoCtx& ioctx, ContextWQ *work_queue, + const std::string& oid, librbd::MockImageWatcher *watcher, + managed_lock::Mode mode, bool blacklist_on_break_lock, + uint32_t blacklist_expire_seconds) + : m_lock("ManagedLock::m_lock") { + } + + mutable Mutex m_lock; + + virtual void shutdown_handler(int r, Context *) = 0; + virtual void pre_acquire_lock_handler(Context *) = 0; + virtual void post_acquire_lock_handler(int, Context *) = 0; + virtual void pre_release_lock_handler(bool, Context *) = 0; + virtual void post_release_lock_handler(bool, int, Context *) = 0; + + MOCK_CONST_METHOD0(is_lock_owner, bool()); + + MOCK_METHOD1(shut_down, void(Context*)); + MOCK_METHOD1(acquire_lock, void(Context*)); + + void set_state_uninitialized() { + } + + MOCK_METHOD0(set_state_initializing, void()); + MOCK_METHOD0(set_state_unlocked, void()); + MOCK_METHOD0(set_state_waiting_for_lock, void()); + MOCK_METHOD0(set_state_post_acquiring, void()); + MOCK_METHOD0(set_state_releasing, void()); + MOCK_METHOD0(set_state_shutting_down, void()); + + MOCK_CONST_METHOD0(is_state_shutdown, bool()); + MOCK_CONST_METHOD0(is_state_acquiring, bool()); + MOCK_CONST_METHOD0(is_state_post_acquiring, bool()); + MOCK_CONST_METHOD0(is_state_releasing, bool()); + MOCK_CONST_METHOD0(is_state_pre_releasing, bool()); + MOCK_CONST_METHOD0(is_state_locked, bool()); + MOCK_CONST_METHOD0(is_state_waiting_for_lock, bool()); + + MOCK_CONST_METHOD0(is_action_acquire_lock, bool()); + MOCK_METHOD0(execute_next_action, void()); + +}; + namespace exclusive_lock { using librbd::ImageWatcher; @@ -86,82 +128,12 @@ struct PreReleaseRequest : public BaseRequest -struct BaseRequest { - static std::list s_requests; - Context *on_finish = nullptr; - - static T* create(librados::IoCtx& ioctx, MockImageWatcher *watcher, - ContextWQ *work_queue, const std::string& oid, - const std::string& cookie, Context *on_finish) { - assert(!s_requests.empty()); - T* req = s_requests.front(); - req->on_finish = on_finish; - s_requests.pop_front(); - return req; - } - - BaseRequest() { - s_requests.push_back(reinterpret_cast(this)); - } -}; - -template -std::list BaseRequest::s_requests; - -template <> -struct AcquireRequest : public BaseRequest > { - static AcquireRequest* create(librados::IoCtx& ioctx, - MockImageWatcher *watcher, - ContextWQ *work_queue, const std::string& oid, - const std::string& cookie, bool exclusive, - bool blacklist_on_break_lock, - uint32_t blacklist_expire_seconds, - Context *on_finish) { - return BaseRequest::create(ioctx, watcher, work_queue, oid, cookie, - on_finish); - } - MOCK_METHOD0(send, void()); -}; - -template <> -struct ReacquireRequest : public BaseRequest > { - static ReacquireRequest* create(librados::IoCtx &ioctx, const std::string& oid, - const string& old_cookie, const std::string& new_cookie, - bool exclusive, Context *on_finish) { - return BaseRequest::create(ioctx, nullptr, nullptr, oid, new_cookie, - on_finish); - } - - MOCK_METHOD0(send, void()); -}; - -template <> -struct ReleaseRequest : public BaseRequest > { - static ReleaseRequest* create(librados::IoCtx& ioctx, MockImageWatcher *watcher, - ContextWQ *work_queue, const std::string& oid, - const std::string& cookie, Context *on_finish) { - return BaseRequest::create(ioctx, watcher, work_queue, oid, cookie, - on_finish); - } - - MOCK_METHOD0(send, void()); -}; - - -} // namespace managed_lock } // namespace librbd // template definitions #include "librbd/ExclusiveLock.cc" template class librbd::ExclusiveLock; -#include "librbd/ManagedLock.cc" -template class librbd::ManagedLock; - ACTION_P(FinishLockUnlock, request) { if (request->on_lock_unlock != nullptr) { request->on_lock_unlock->complete(0); @@ -182,18 +154,60 @@ using ::testing::Return; class TestMockExclusiveLock : public TestMockFixture { public: + typedef ManagedLock MockManagedLock; typedef ExclusiveLock MockExclusiveLock; typedef exclusive_lock::PreAcquireRequest MockPreAcquireRequest; typedef exclusive_lock::PostAcquireRequest MockPostAcquireRequest; typedef exclusive_lock::PreReleaseRequest MockPreReleaseRequest; - typedef managed_lock::AcquireRequest MockManagedAcquireRequest; - typedef managed_lock::ReacquireRequest MockManagedReacquireRequest; - typedef managed_lock::ReleaseRequest MockManagedReleaseRequest; - void expect_get_watch_handle(MockExclusiveLockImageCtx &mock_image_ctx, - uint64_t watch_handle = 1234567890) { - EXPECT_CALL(*mock_image_ctx.image_watcher, get_watch_handle()) - .WillOnce(Return(watch_handle)); + void expect_set_state_initializing(MockManagedLock &managed_lock) { + EXPECT_CALL(managed_lock, set_state_initializing()); + } + + void expect_set_state_unlocked(MockManagedLock &managed_lock) { + EXPECT_CALL(managed_lock, set_state_unlocked()); + } + + void expect_set_state_waiting_for_lock(MockManagedLock &managed_lock) { + EXPECT_CALL(managed_lock, set_state_waiting_for_lock()); + } + + void expect_is_state_acquiring(MockManagedLock &managed_lock, bool ret_val) { + EXPECT_CALL(managed_lock, is_state_acquiring()) + .WillOnce(Return(ret_val)); + } + + void expect_is_state_waiting_for_lock(MockManagedLock &managed_lock, + bool ret_val) { + EXPECT_CALL(managed_lock, is_state_waiting_for_lock()) + .WillOnce(Return(ret_val)); + } + + void expect_is_state_pre_releasing(MockManagedLock &managed_lock, + bool ret_val) { + EXPECT_CALL(managed_lock, is_state_pre_releasing()) + .WillOnce(Return(ret_val)); + } + + void expect_is_state_releasing(MockManagedLock &managed_lock, bool ret_val) { + EXPECT_CALL(managed_lock, is_state_releasing()) + .WillOnce(Return(ret_val)); + } + + void expect_is_state_locked(MockManagedLock &managed_lock, bool ret_val) { + EXPECT_CALL(managed_lock, is_state_locked()) + .WillOnce(Return(ret_val)); + } + + void expect_is_state_shutdown(MockManagedLock &managed_lock, bool ret_val) { + EXPECT_CALL(managed_lock, is_state_shutdown()) + .WillOnce(Return(ret_val)); + } + + void expect_is_action_acquire_lock(MockManagedLock &managed_lock, + bool ret_val) { + EXPECT_CALL(managed_lock, is_action_acquire_lock()) + .WillOnce(Return(ret_val)); } void expect_set_require_lock_on_read(MockExclusiveLockImageCtx &mock_image_ctx) { @@ -217,65 +231,31 @@ public: EXPECT_CALL(*mock_image_ctx.aio_work_queue, unblock_writes()); } - void expect_acquire_lock(MockExclusiveLockImageCtx &mock_image_ctx, - MockPreAcquireRequest &pre_acquire_request, - MockManagedAcquireRequest &managed_acquire_request, - MockPostAcquireRequest *post_acquire_request, - int pre_r, int managed_r, int post_r) { - - expect_get_watch_handle(mock_image_ctx); + void expect_prepare_lock_complete(MockExclusiveLockImageCtx &mock_image_ctx) { + EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete()); + } + void expect_pre_acquire_request(MockPreAcquireRequest &pre_acquire_request, + int r) { EXPECT_CALL(pre_acquire_request, send()) - .WillOnce(CompleteRequest(&pre_acquire_request, pre_r)); - EXPECT_CALL(managed_acquire_request, send()) - .WillOnce(CompleteRequest(&managed_acquire_request, managed_r)); - if (managed_r == 0) { - assert(post_acquire_request != nullptr); - EXPECT_CALL(*post_acquire_request, send()) - .WillOnce(DoAll(FinishLockUnlock(post_acquire_request), - CompleteRequest(post_acquire_request, post_r))); - } - - if (pre_r == 0 && managed_r == 0 && post_r == 0) { - expect_notify_acquired_lock(mock_image_ctx); - expect_unblock_writes(mock_image_ctx); - } + .WillOnce(CompleteRequest(&pre_acquire_request, r)); } - void expect_release_lock(MockExclusiveLockImageCtx &mock_image_ctx, - MockPreReleaseRequest &pre_release_request, - MockManagedReleaseRequest &managed_release_request, - int pre_r, int managed_r, bool shutting_down = false) { - EXPECT_CALL(pre_release_request, send()) - .WillOnce(DoAll(FinishLockUnlock(&pre_release_request), - CompleteRequest(&pre_release_request, pre_r))); - EXPECT_CALL(managed_release_request, send()) - .WillOnce(CompleteRequest(&managed_release_request, managed_r)); - - if (pre_r == 0 && managed_r == 0) { - if (shutting_down) { - expect_unblock_writes(mock_image_ctx); - } - expect_notify_released_lock(mock_image_ctx); - expect_is_lock_request_needed(mock_image_ctx, false); - } + void expect_post_acquire_request(MockPostAcquireRequest &post_acquire_request, + int r) { + EXPECT_CALL(post_acquire_request, send()) + .WillOnce(CompleteRequest(&post_acquire_request, r)); } - void expect_reacquire_lock(MockExclusiveLockImageCtx &mock_image_ctx, - MockManagedReacquireRequest &mock_reacquire_request, - int r) { - EXPECT_CALL(*mock_image_ctx.image_watcher, get_watch_handle()) - .WillOnce(Return(98765)); - EXPECT_CALL(mock_reacquire_request, send()) - .WillOnce(CompleteRequest(&mock_reacquire_request, r)); + void expect_pre_release_request(MockPreReleaseRequest &pre_release_request, + int r) { + EXPECT_CALL(pre_release_request, send()) + .WillOnce(CompleteRequest(&pre_release_request, r)); } void expect_notify_request_lock(MockExclusiveLockImageCtx &mock_image_ctx, MockExclusiveLock &mock_exclusive_lock) { - EXPECT_CALL(*mock_image_ctx.image_watcher, notify_request_lock()) - .WillRepeatedly(Invoke([&mock_exclusive_lock]() { - mock_exclusive_lock.handle_peer_notification(0); - })); + EXPECT_CALL(*mock_image_ctx.image_watcher, notify_request_lock()); } void expect_notify_acquired_lock(MockExclusiveLockImageCtx &mock_image_ctx) { @@ -298,6 +278,11 @@ public: .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)); } + void expect_shut_down(MockManagedLock &managed_lock) { + EXPECT_CALL(managed_lock, shut_down(_)) + .WillOnce(CompleteContext(0, static_cast(nullptr))); + } + int when_init(MockExclusiveLockImageCtx &mock_image_ctx, MockExclusiveLock &exclusive_lock) { C_SaferCond ctx; @@ -308,33 +293,32 @@ public: return ctx.wait(); } - int when_try_lock(MockExclusiveLockImageCtx &mock_image_ctx, - MockExclusiveLock &exclusive_lock) { + int when_pre_acquire_lock_handler(MockManagedLock &managed_lock) { C_SaferCond ctx; - { - RWLock::WLocker owner_locker(mock_image_ctx.owner_lock); - exclusive_lock.try_acquire_lock(&ctx); - } + managed_lock.pre_acquire_lock_handler(&ctx); return ctx.wait(); } - int when_request_lock(MockExclusiveLockImageCtx &mock_image_ctx, - MockExclusiveLock &exclusive_lock) { + + int when_post_acquire_lock_handler(MockManagedLock &managed_lock, int r) { C_SaferCond ctx; - { - RWLock::RLocker owner_locker(mock_image_ctx.owner_lock); - exclusive_lock.acquire_lock(&ctx); - } + managed_lock.post_acquire_lock_handler(r, &ctx); return ctx.wait(); } - int when_release_lock(MockExclusiveLockImageCtx &mock_image_ctx, - MockExclusiveLock &exclusive_lock) { + + int when_pre_release_lock_handler(MockManagedLock &managed_lock, + bool shutting_down) { C_SaferCond ctx; - { - RWLock::WLocker owner_locker(mock_image_ctx.owner_lock); - exclusive_lock.release_lock(&ctx); - } + managed_lock.pre_release_lock_handler(shutting_down, &ctx); + return ctx.wait(); + } + + int when_post_release_lock_handler(MockManagedLock &managed_lock, + bool shutting_down, int r) { + C_SaferCond ctx; + managed_lock.post_release_lock_handler(shutting_down, r, &ctx); return ctx.wait(); } + int when_shut_down(MockExclusiveLockImageCtx &mock_image_ctx, MockExclusiveLock &exclusive_lock) { C_SaferCond ctx; @@ -363,97 +347,61 @@ TEST_F(TestMockExclusiveLock, StateTransitions) { expect_op_work_queue(mock_image_ctx); InSequence seq; + expect_set_state_initializing(exclusive_lock); expect_block_writes(mock_image_ctx); + expect_set_state_unlocked(exclusive_lock); ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); + // (try) acquire lock MockPreAcquireRequest try_lock_pre_acquire; - MockManagedAcquireRequest try_lock_managed_acquire; + expect_pre_acquire_request(try_lock_pre_acquire, 0); + ASSERT_EQ(0, when_pre_acquire_lock_handler(exclusive_lock)); + MockPostAcquireRequest try_lock_post_acquire; - expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire, - try_lock_managed_acquire, &try_lock_post_acquire, 0, 0, 0); - ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock)); - ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock)); + expect_post_acquire_request(try_lock_post_acquire, 0); + expect_is_state_acquiring(exclusive_lock, true); + expect_notify_acquired_lock(mock_image_ctx); + expect_unblock_writes(mock_image_ctx); + ASSERT_EQ(0, when_post_acquire_lock_handler(exclusive_lock, 0)); + // release lock MockPreReleaseRequest pre_request_release; - MockManagedReleaseRequest managed_request_release; - expect_release_lock(mock_image_ctx, pre_request_release, - managed_request_release, 0, 0); - ASSERT_EQ(0, when_release_lock(mock_image_ctx, exclusive_lock)); - ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock)); + expect_pre_release_request(pre_request_release, 0); + ASSERT_EQ(0, when_pre_release_lock_handler(exclusive_lock, false)); + expect_is_state_pre_releasing(exclusive_lock, false); + expect_is_state_releasing(exclusive_lock, true); + expect_notify_released_lock(mock_image_ctx); + expect_is_lock_request_needed(mock_image_ctx, false); + ASSERT_EQ(0, when_post_release_lock_handler(exclusive_lock, false, 0)); + + // (try) acquire lock MockPreAcquireRequest request_lock_pre_acquire; - MockManagedAcquireRequest request_lock_managed_acquire; + expect_pre_acquire_request(request_lock_pre_acquire, 0); + ASSERT_EQ(0, when_pre_acquire_lock_handler(exclusive_lock)); + MockPostAcquireRequest request_lock_post_acquire; - expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire, - request_lock_managed_acquire, &request_lock_post_acquire, - 0, 0, 0); - ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock)); - ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock)); + expect_post_acquire_request(request_lock_post_acquire, 0); + expect_is_state_acquiring(exclusive_lock, true); + expect_notify_acquired_lock(mock_image_ctx); + expect_unblock_writes(mock_image_ctx); + ASSERT_EQ(0, when_post_acquire_lock_handler(exclusive_lock, 0)); - MockPreReleaseRequest shutdown_pre_release; - MockManagedReleaseRequest shutdown_managed_release; - expect_release_lock(mock_image_ctx, shutdown_pre_release, - shutdown_managed_release, 0, 0, true); + // shut down (and release) + expect_shut_down(exclusive_lock); + expect_is_state_waiting_for_lock(exclusive_lock, false); ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); - ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock)); -} - -TEST_F(TestMockExclusiveLock, TryLockLockedState) { - REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); - - librbd::ImageCtx *ictx; - ASSERT_EQ(0, open_image(m_image_name, &ictx)); - - MockExclusiveLockImageCtx mock_image_ctx(*ictx); - MockExclusiveLock exclusive_lock(mock_image_ctx); - expect_op_work_queue(mock_image_ctx); - - InSequence seq; - expect_block_writes(mock_image_ctx); - ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); - - MockPreAcquireRequest try_lock_pre_acquire; - MockManagedAcquireRequest try_lock_managed_acquire; - MockPostAcquireRequest try_lock_post_acquire; - expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire, - try_lock_managed_acquire, &try_lock_post_acquire, 0, 0, 0); - ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock)); - ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock)); MockPreReleaseRequest shutdown_pre_release; - MockManagedReleaseRequest shutdown_managed_release; - expect_release_lock(mock_image_ctx, shutdown_pre_release, - shutdown_managed_release, 0, 0, true); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); -} - -TEST_F(TestMockExclusiveLock, TryLockAlreadyLocked) { - REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); - - librbd::ImageCtx *ictx; - ASSERT_EQ(0, open_image(m_image_name, &ictx)); - - MockExclusiveLockImageCtx mock_image_ctx(*ictx); - MockExclusiveLock exclusive_lock(mock_image_ctx); - expect_op_work_queue(mock_image_ctx); - - InSequence seq; - expect_block_writes(mock_image_ctx); - ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); - - MockPreAcquireRequest try_lock_pre_acquire; - MockManagedAcquireRequest try_lock_managed_acquire; - expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire, - try_lock_managed_acquire, nullptr, 0, -EAGAIN, 0); - ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock)); - ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock)); + expect_pre_release_request(shutdown_pre_release, 0); + ASSERT_EQ(0, when_pre_release_lock_handler(exclusive_lock, true)); expect_unblock_writes(mock_image_ctx); - expect_flush_notifies(mock_image_ctx); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); + expect_notify_released_lock(mock_image_ctx); + ASSERT_EQ(0, when_post_release_lock_handler(exclusive_lock, true, 0)); } -TEST_F(TestMockExclusiveLock, TryLockBusy) { +TEST_F(TestMockExclusiveLock, TryLockAlreadyLocked) { REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); librbd::ImageCtx *ictx; @@ -464,19 +412,20 @@ TEST_F(TestMockExclusiveLock, TryLockBusy) { expect_op_work_queue(mock_image_ctx); InSequence seq; + expect_set_state_initializing(exclusive_lock); expect_block_writes(mock_image_ctx); + expect_set_state_unlocked(exclusive_lock); ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); + // try acquire lock MockPreAcquireRequest try_lock_pre_acquire; - MockManagedAcquireRequest try_lock_managed_acquire; - expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire, - try_lock_managed_acquire, nullptr, 0, -EBUSY, 0); - ASSERT_EQ(-EBUSY, when_try_lock(mock_image_ctx, exclusive_lock)); - ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock)); + expect_pre_acquire_request(try_lock_pre_acquire, 0); + ASSERT_EQ(0, when_pre_acquire_lock_handler(exclusive_lock)); - expect_unblock_writes(mock_image_ctx); - expect_flush_notifies(mock_image_ctx); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); + expect_is_state_acquiring(exclusive_lock, true); + expect_prepare_lock_complete(mock_image_ctx); + expect_is_action_acquire_lock(exclusive_lock, false); + ASSERT_EQ(0, when_post_acquire_lock_handler(exclusive_lock, -EAGAIN)); } TEST_F(TestMockExclusiveLock, TryLockError) { @@ -490,22 +439,23 @@ TEST_F(TestMockExclusiveLock, TryLockError) { expect_op_work_queue(mock_image_ctx); InSequence seq; + expect_set_state_initializing(exclusive_lock); expect_block_writes(mock_image_ctx); + expect_set_state_unlocked(exclusive_lock); ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); + // try acquire lock MockPreAcquireRequest try_lock_pre_acquire; - MockManagedAcquireRequest try_lock_managed_acquire; - expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire, - try_lock_managed_acquire, nullptr, 0, -EINVAL, 0); - ASSERT_EQ(-EINVAL, when_try_lock(mock_image_ctx, exclusive_lock)); - ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock)); + expect_pre_acquire_request(try_lock_pre_acquire, 0); + ASSERT_EQ(0, when_pre_acquire_lock_handler(exclusive_lock)); - expect_unblock_writes(mock_image_ctx); - expect_flush_notifies(mock_image_ctx); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); + expect_is_state_acquiring(exclusive_lock, true); + expect_prepare_lock_complete(mock_image_ctx); + expect_is_action_acquire_lock(exclusive_lock, false); + ASSERT_EQ(-EBUSY, when_post_acquire_lock_handler(exclusive_lock, -EBUSY)); } -TEST_F(TestMockExclusiveLock, RequestLockLockedState) { +TEST_F(TestMockExclusiveLock, AcquireLockAlreadyLocked) { REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); librbd::ImageCtx *ictx; @@ -516,26 +466,26 @@ TEST_F(TestMockExclusiveLock, RequestLockLockedState) { expect_op_work_queue(mock_image_ctx); InSequence seq; + expect_set_state_initializing(exclusive_lock); expect_block_writes(mock_image_ctx); + expect_set_state_unlocked(exclusive_lock); ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); + // acquire lock MockPreAcquireRequest try_lock_pre_acquire; - MockManagedAcquireRequest try_lock_managed_acquire; - MockPostAcquireRequest try_lock_post_acquire; - expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire, - try_lock_managed_acquire, &try_lock_post_acquire, 0, 0, 0); - ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock)); - ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock)); - ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock)); + expect_pre_acquire_request(try_lock_pre_acquire, 0); + ASSERT_EQ(0, when_pre_acquire_lock_handler(exclusive_lock)); - MockPreReleaseRequest shutdown_pre_release; - MockManagedReleaseRequest shutdown_managed_release; - expect_release_lock(mock_image_ctx, shutdown_pre_release, - shutdown_managed_release, 0, 0, true); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); + expect_is_state_acquiring(exclusive_lock, true); + expect_prepare_lock_complete(mock_image_ctx); + expect_is_action_acquire_lock(exclusive_lock, true); + expect_set_state_waiting_for_lock(exclusive_lock); + expect_notify_request_lock(mock_image_ctx, exclusive_lock); + ASSERT_EQ(-ECANCELED, when_post_acquire_lock_handler(exclusive_lock, + -EAGAIN)); } -TEST_F(TestMockExclusiveLock, RequestLockBlacklist) { +TEST_F(TestMockExclusiveLock, AcquireLockBusy) { REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); librbd::ImageCtx *ictx; @@ -546,60 +496,26 @@ TEST_F(TestMockExclusiveLock, RequestLockBlacklist) { expect_op_work_queue(mock_image_ctx); InSequence seq; + expect_set_state_initializing(exclusive_lock); expect_block_writes(mock_image_ctx); + expect_set_state_unlocked(exclusive_lock); ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); - // will abort after seeing blacklist error (avoid infinite request loop) - MockPreAcquireRequest request_pre_acquire; - MockManagedAcquireRequest request_managed_acquire; - expect_acquire_lock(mock_image_ctx, request_pre_acquire, - request_managed_acquire, nullptr, 0, -EBLACKLISTED, 0); - ASSERT_EQ(-EBLACKLISTED, when_request_lock(mock_image_ctx, exclusive_lock)); - ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock)); - - expect_unblock_writes(mock_image_ctx); - expect_flush_notifies(mock_image_ctx); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); -} - -TEST_F(TestMockExclusiveLock, RequestLockBusy) { - REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); - - librbd::ImageCtx *ictx; - ASSERT_EQ(0, open_image(m_image_name, &ictx)); - - MockExclusiveLockImageCtx mock_image_ctx(*ictx); - MockExclusiveLock exclusive_lock(mock_image_ctx); - expect_op_work_queue(mock_image_ctx); - - InSequence seq; - expect_block_writes(mock_image_ctx); - ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); + // acquire lock + MockPreAcquireRequest try_lock_pre_acquire; + expect_pre_acquire_request(try_lock_pre_acquire, 0); + ASSERT_EQ(0, when_pre_acquire_lock_handler(exclusive_lock)); - // will repeat until successfully acquires the lock - MockPreAcquireRequest request_lock_pre_acquire1; - MockManagedAcquireRequest request_lock_managed_acquire1; - expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire1, - request_lock_managed_acquire1, nullptr, 0, -EBUSY, 0); + expect_is_state_acquiring(exclusive_lock, true); + expect_prepare_lock_complete(mock_image_ctx); + expect_is_action_acquire_lock(exclusive_lock, true); + expect_set_state_waiting_for_lock(exclusive_lock); expect_notify_request_lock(mock_image_ctx, exclusive_lock); - - MockPreAcquireRequest request_lock_pre_acquire2; - MockManagedAcquireRequest request_lock_managed_acquire2; - MockPostAcquireRequest request_lock_post_acquire2; - expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire2, - request_lock_managed_acquire2, - &request_lock_post_acquire2, 0, 0, 0); - ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock)); - ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock)); - - MockPreReleaseRequest shutdown_pre_release; - MockManagedReleaseRequest shutdown_managed_release; - expect_release_lock(mock_image_ctx, shutdown_pre_release, - shutdown_managed_release, 0, 0, true); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); + ASSERT_EQ(-ECANCELED, when_post_acquire_lock_handler(exclusive_lock, + -EBUSY)); } -TEST_F(TestMockExclusiveLock, RequestLockError) { +TEST_F(TestMockExclusiveLock, AcquireLockError) { REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); librbd::ImageCtx *ictx; @@ -610,33 +526,24 @@ TEST_F(TestMockExclusiveLock, RequestLockError) { expect_op_work_queue(mock_image_ctx); InSequence seq; + expect_set_state_initializing(exclusive_lock); expect_block_writes(mock_image_ctx); + expect_set_state_unlocked(exclusive_lock); ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); - // will repeat until successfully acquires the lock - MockPreAcquireRequest request_lock_pre_acquire1; - MockManagedAcquireRequest request_lock_managed_acquire1; - expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire1, - request_lock_managed_acquire1, nullptr, 0, -EINVAL, 0); - expect_notify_request_lock(mock_image_ctx, exclusive_lock); - - MockPreAcquireRequest request_lock_pre_acquire2; - MockManagedAcquireRequest request_lock_managed_acquire2; - MockPostAcquireRequest request_lock_post_acquire2; - expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire2, - request_lock_managed_acquire2, - &request_lock_post_acquire2, 0, 0, 0); - ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock)); - ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock)); - - MockPreReleaseRequest shutdown_pre_release; - MockManagedReleaseRequest shutdown_managed_release; - expect_release_lock(mock_image_ctx, shutdown_pre_release, - shutdown_managed_release, 0, 0, true); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); + // acquire lock + MockPreAcquireRequest try_lock_pre_acquire; + expect_pre_acquire_request(try_lock_pre_acquire, 0); + ASSERT_EQ(0, when_pre_acquire_lock_handler(exclusive_lock)); + + expect_is_state_acquiring(exclusive_lock, true); + expect_prepare_lock_complete(mock_image_ctx); + expect_is_action_acquire_lock(exclusive_lock, true); + ASSERT_EQ(-EBLACKLISTED, when_post_acquire_lock_handler(exclusive_lock, + -EBLACKLISTED)); } -TEST_F(TestMockExclusiveLock, RequestLockJournalEPERM) { +TEST_F(TestMockExclusiveLock, PostAcquireLockError) { REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); librbd::ImageCtx *ictx; @@ -647,85 +554,23 @@ TEST_F(TestMockExclusiveLock, RequestLockJournalEPERM) { expect_op_work_queue(mock_image_ctx); InSequence seq; + expect_set_state_initializing(exclusive_lock); expect_block_writes(mock_image_ctx); + expect_set_state_unlocked(exclusive_lock); ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); - // will abort after seeing perm error (avoid infinite request loop) + // (try) acquire lock MockPreAcquireRequest request_lock_pre_acquire; - MockManagedAcquireRequest request_lock_managed_acquire; - MockPostAcquireRequest request_lock_post_acquire; - expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire, - request_lock_managed_acquire, - &request_lock_post_acquire, 0, 0, -EPERM); - MockManagedReleaseRequest release_on_error; - EXPECT_CALL(release_on_error, send()) - .WillOnce(CompleteRequest(&release_on_error, 0)); - ASSERT_EQ(-EPERM, when_request_lock(mock_image_ctx, exclusive_lock)); - ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock)); - - expect_unblock_writes(mock_image_ctx); - expect_flush_notifies(mock_image_ctx); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); -} - -TEST_F(TestMockExclusiveLock, ReleaseLockUnlockedState) { - REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); - - librbd::ImageCtx *ictx; - ASSERT_EQ(0, open_image(m_image_name, &ictx)); - - MockExclusiveLockImageCtx mock_image_ctx(*ictx); - MockExclusiveLock exclusive_lock(mock_image_ctx); - expect_op_work_queue(mock_image_ctx); - - InSequence seq; - expect_block_writes(mock_image_ctx); - ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); + expect_pre_acquire_request(request_lock_pre_acquire, 0); + ASSERT_EQ(0, when_pre_acquire_lock_handler(exclusive_lock)); - ASSERT_EQ(0, when_release_lock(mock_image_ctx, exclusive_lock)); - - expect_unblock_writes(mock_image_ctx); - expect_flush_notifies(mock_image_ctx); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); -} - -TEST_F(TestMockExclusiveLock, ReleaseLockError) { - REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); - - librbd::ImageCtx *ictx; - ASSERT_EQ(0, open_image(m_image_name, &ictx)); - - MockExclusiveLockImageCtx mock_image_ctx(*ictx); - MockExclusiveLock exclusive_lock(mock_image_ctx); - expect_op_work_queue(mock_image_ctx); - - InSequence seq; - expect_block_writes(mock_image_ctx); - ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); - - MockPreAcquireRequest try_lock_pre_acquire; - MockManagedAcquireRequest try_lock_managed_acquire; - MockPostAcquireRequest try_lock_post_acquire; - expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire, - try_lock_managed_acquire, &try_lock_post_acquire, 0, 0, 0); - ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock)); - - MockPreReleaseRequest request_pre_release; - MockManagedReleaseRequest request_managed_release; - expect_release_lock(mock_image_ctx, request_pre_release, - request_managed_release, 0, -EINVAL, false); - ASSERT_EQ(-EINVAL, when_release_lock(mock_image_ctx, exclusive_lock)); - ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock)); - - MockPreReleaseRequest shutdown_pre_release; - MockManagedReleaseRequest shutdown_managed_release; - expect_release_lock(mock_image_ctx, shutdown_pre_release, - shutdown_managed_release, 0, 0, true); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); - ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock)); + MockPostAcquireRequest request_lock_post_acquire; + expect_post_acquire_request(request_lock_post_acquire, -EPERM); + expect_is_state_acquiring(exclusive_lock, true); + ASSERT_EQ(-EPERM, when_post_acquire_lock_handler(exclusive_lock, 0)); } -TEST_F(TestMockExclusiveLock, ConcurrentRequests) { +TEST_F(TestMockExclusiveLock, PreReleaseLockError) { REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); librbd::ImageCtx *ictx; @@ -736,86 +581,19 @@ TEST_F(TestMockExclusiveLock, ConcurrentRequests) { expect_op_work_queue(mock_image_ctx); InSequence seq; + expect_set_state_initializing(exclusive_lock); expect_block_writes(mock_image_ctx); + expect_set_state_unlocked(exclusive_lock); ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); - MockPreAcquireRequest try_lock_pre_acquire; - MockManagedAcquireRequest try_lock_managed_acquire; - MockPostAcquireRequest try_lock_post_acquire; - C_SaferCond wait_for_send_ctx1; - expect_get_watch_handle(mock_image_ctx); - EXPECT_CALL(try_lock_pre_acquire, send()) - .WillOnce(CompleteRequest(&try_lock_pre_acquire, 0)); - EXPECT_CALL(try_lock_managed_acquire, send()) - .WillOnce(CompleteRequest(&try_lock_managed_acquire, 0)); - EXPECT_CALL(try_lock_post_acquire, send()) - .WillOnce(Notify(&wait_for_send_ctx1)); - - MockManagedReleaseRequest managed_release_on_error; - EXPECT_CALL(managed_release_on_error, send()) - .WillOnce(CompleteRequest(&managed_release_on_error, 0)); - - MockPreAcquireRequest request_pre_acquire; - MockManagedAcquireRequest request_managed_acquire; - MockPostAcquireRequest request_post_acquire; - expect_acquire_lock(mock_image_ctx, request_pre_acquire, - request_managed_acquire, &request_post_acquire, 0, 0, 0); - - MockPreReleaseRequest pre_release; - MockManagedReleaseRequest managed_release; - C_SaferCond wait_for_send_ctx2; - EXPECT_CALL(pre_release, send()).WillOnce(Notify(&wait_for_send_ctx2)); - EXPECT_CALL(managed_release, send()) - .WillOnce(CompleteRequest(&managed_release, 0)); - expect_notify_released_lock(mock_image_ctx); - expect_is_lock_request_needed(mock_image_ctx, false); - - C_SaferCond try_request_ctx1; - { - RWLock::WLocker owner_locker(mock_image_ctx.owner_lock); - exclusive_lock.try_acquire_lock(&try_request_ctx1); - } - - C_SaferCond request_lock_ctx1; - C_SaferCond request_lock_ctx2; - { - RWLock::RLocker owner_locker(mock_image_ctx.owner_lock); - exclusive_lock.acquire_lock(&request_lock_ctx1); - exclusive_lock.acquire_lock(&request_lock_ctx2); - } - - C_SaferCond release_lock_ctx1; - { - RWLock::WLocker owner_locker(mock_image_ctx.owner_lock); - exclusive_lock.release_lock(&release_lock_ctx1); - } - - C_SaferCond request_lock_ctx3; - { - RWLock::RLocker owner_locker(mock_image_ctx.owner_lock); - exclusive_lock.acquire_lock(&request_lock_ctx3); - } - - // fail the try_lock - ASSERT_EQ(0, wait_for_send_ctx1.wait()); - try_lock_post_acquire.on_lock_unlock->complete(0); - try_lock_post_acquire.on_finish->complete(-EINVAL); - ASSERT_EQ(-EINVAL, try_request_ctx1.wait()); - - // all three pending request locks should complete - ASSERT_EQ(0, request_lock_ctx1.wait()); - ASSERT_EQ(0, request_lock_ctx2.wait()); - ASSERT_EQ(0, request_lock_ctx3.wait()); - - // proceed with the release - ASSERT_EQ(0, wait_for_send_ctx2.wait()); - pre_release.on_lock_unlock->complete(0); - pre_release.on_finish->complete(0); - ASSERT_EQ(0, release_lock_ctx1.wait()); + // release lock + MockPreReleaseRequest pre_request_release; + expect_pre_release_request(pre_request_release, -EINVAL); + ASSERT_EQ(-EINVAL, when_pre_release_lock_handler(exclusive_lock, false)); - expect_unblock_writes(mock_image_ctx); - expect_flush_notifies(mock_image_ctx); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); + expect_is_state_pre_releasing(exclusive_lock, true); + ASSERT_EQ(-EINVAL, when_post_release_lock_handler(exclusive_lock, false, + -EINVAL)); } TEST_F(TestMockExclusiveLock, BlockRequests) { @@ -830,170 +608,28 @@ TEST_F(TestMockExclusiveLock, BlockRequests) { expect_op_work_queue(mock_image_ctx); InSequence seq; + expect_set_state_initializing(exclusive_lock); expect_block_writes(mock_image_ctx); + expect_set_state_unlocked(exclusive_lock); ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); - MockPreAcquireRequest try_lock_pre_acquire; - MockManagedAcquireRequest try_lock_managed_acquire; - MockPostAcquireRequest try_lock_post_acquire; - expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire, - try_lock_managed_acquire, &try_lock_post_acquire, 0, 0, 0); - ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock)); - ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock)); - int ret_val; + expect_is_state_shutdown(exclusive_lock, false); + expect_is_state_locked(exclusive_lock, true); ASSERT_TRUE(exclusive_lock.accept_requests(&ret_val)); ASSERT_EQ(0, ret_val); exclusive_lock.block_requests(-EROFS); + expect_is_state_shutdown(exclusive_lock, false); + expect_is_state_locked(exclusive_lock, true); ASSERT_FALSE(exclusive_lock.accept_requests(&ret_val)); ASSERT_EQ(-EROFS, ret_val); exclusive_lock.unblock_requests(); + expect_is_state_shutdown(exclusive_lock, false); + expect_is_state_locked(exclusive_lock, true); ASSERT_TRUE(exclusive_lock.accept_requests(&ret_val)); ASSERT_EQ(0, ret_val); - - MockPreReleaseRequest shutdown_pre_release; - MockManagedReleaseRequest shutdown_managed_release; - expect_release_lock(mock_image_ctx, shutdown_pre_release, - shutdown_managed_release, 0, 0, true); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); - ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock)); -} - -TEST_F(TestMockExclusiveLock, RequestLockWatchNotRegistered) { - REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); - - librbd::ImageCtx *ictx; - ASSERT_EQ(0, open_image(m_image_name, &ictx)); - - MockExclusiveLockImageCtx mock_image_ctx(*ictx); - MockExclusiveLock exclusive_lock(mock_image_ctx); - expect_op_work_queue(mock_image_ctx); - - InSequence seq; - expect_block_writes(mock_image_ctx); - ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); - - EXPECT_CALL(*mock_image_ctx.image_watcher, get_watch_handle()) - .WillOnce(DoAll(Invoke([&mock_image_ctx, &exclusive_lock]() { - mock_image_ctx.image_ctx->op_work_queue->queue( - new FunctionContext([&mock_image_ctx, &exclusive_lock](int r) { - RWLock::RLocker owner_locker(mock_image_ctx.owner_lock); - exclusive_lock.reacquire_lock(); - })); - }), - Return(0))); - - MockPreAcquireRequest request_lock_pre_acquire; - MockManagedAcquireRequest request_lock_managed_acquire; - MockPostAcquireRequest request_lock_post_acquire; - expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire, - request_lock_managed_acquire, - &request_lock_post_acquire, 0, 0, 0); - ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock)); - ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock)); - - MockPreReleaseRequest shutdown_pre_release; - MockManagedReleaseRequest shutdown_managed_release; - expect_release_lock(mock_image_ctx, shutdown_pre_release, - shutdown_managed_release, 0, 0, true); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); - ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock)); -} - -TEST_F(TestMockExclusiveLock, ReacquireLock) { - REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); - - librbd::ImageCtx *ictx; - ASSERT_EQ(0, open_image(m_image_name, &ictx)); - - MockExclusiveLockImageCtx mock_image_ctx(*ictx); - MockExclusiveLock exclusive_lock(mock_image_ctx); - expect_op_work_queue(mock_image_ctx); - - InSequence seq; - expect_block_writes(mock_image_ctx); - ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); - - MockPreAcquireRequest request_lock_pre_acquire; - MockManagedAcquireRequest request_lock_managed_acquire; - MockPostAcquireRequest request_lock_post_acquire; - expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire, - request_lock_managed_acquire, - &request_lock_post_acquire, 0, 0, 0); - ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock)); - ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock)); - - EXPECT_CALL(*mock_image_ctx.image_watcher, get_watch_handle()) - .WillOnce(Return(1234567890)); - - C_SaferCond reacquire_ctx; - { - RWLock::RLocker owner_locker(mock_image_ctx.owner_lock); - exclusive_lock.reacquire_lock(&reacquire_ctx); - } - ASSERT_EQ(0, reacquire_ctx.wait()); - - MockPreReleaseRequest shutdown_pre_release; - MockManagedReleaseRequest shutdown_managed_release; - expect_release_lock(mock_image_ctx, shutdown_pre_release, - shutdown_managed_release, 0, 0, true); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); - ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock)); -} - -TEST_F(TestMockExclusiveLock, ReacquireLockError) { - REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); - - librbd::ImageCtx *ictx; - ASSERT_EQ(0, open_image(m_image_name, &ictx)); - - MockExclusiveLockImageCtx mock_image_ctx(*ictx); - MockExclusiveLock exclusive_lock(mock_image_ctx); - expect_op_work_queue(mock_image_ctx); - - InSequence seq; - expect_block_writes(mock_image_ctx); - ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock)); - - MockPreAcquireRequest request_lock_pre_acquire; - MockManagedAcquireRequest request_lock_managed_acquire; - MockPostAcquireRequest request_lock_post_acquire; - expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire, - request_lock_managed_acquire, - &request_lock_post_acquire, 0, 0, 0); - ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock)); - ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock)); - - MockManagedReacquireRequest mock_reacquire_request; - C_SaferCond reacquire_ctx; - expect_reacquire_lock(mock_image_ctx, mock_reacquire_request, -EOPNOTSUPP); - - MockPreReleaseRequest reacquire_lock_pre_release; - MockManagedReleaseRequest reacquire_lock_managed_release; - expect_release_lock(mock_image_ctx, reacquire_lock_pre_release, - reacquire_lock_managed_release, 0, 0, false); - - MockPreAcquireRequest reacquire_lock_pre_acquire; - MockManagedAcquireRequest reacquire_lock_managed_acquire; - MockPostAcquireRequest reacquire_lock_post_acquire; - expect_acquire_lock(mock_image_ctx, reacquire_lock_pre_acquire, - reacquire_lock_managed_acquire, - &reacquire_lock_post_acquire, 0, 0, 0); - - { - RWLock::RLocker owner_locker(mock_image_ctx.owner_lock); - exclusive_lock.reacquire_lock(&reacquire_ctx); - } - ASSERT_EQ(-EOPNOTSUPP, reacquire_ctx.wait()); - - MockPreReleaseRequest shutdown_pre_release; - MockManagedReleaseRequest shutdown_managed_release; - expect_release_lock(mock_image_ctx, shutdown_pre_release, - shutdown_managed_release, 0, 0, true); - ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock)); - ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock)); } } // namespace librbd -- 2.39.5