From: Ricardo Dias Date: Thu, 5 Jan 2017 11:23:56 +0000 (+0000) Subject: librbd: Support for shared locking in ManagedLock X-Git-Tag: v12.0.0~147^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=5769c6b449f14e582cfcf1cf80be4a301b67532f;p=ceph.git librbd: Support for shared locking in ManagedLock Signed-off-by: Ricardo Dias --- diff --git a/src/librbd/ExclusiveLock.cc b/src/librbd/ExclusiveLock.cc index 2b1621ef60d..7d8e19ba296 100644 --- a/src/librbd/ExclusiveLock.cc +++ b/src/librbd/ExclusiveLock.cc @@ -26,7 +26,8 @@ using ML = ManagedLock; template ExclusiveLock::ExclusiveLock(I &image_ctx) : ML(image_ctx.md_ctx, image_ctx.op_work_queue, image_ctx.header_oid, - image_ctx.image_watcher, image_ctx.blacklist_on_break_lock, + image_ctx.image_watcher, managed_lock::EXCLUSIVE, + 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) { diff --git a/src/librbd/ManagedLock.cc b/src/librbd/ManagedLock.cc index 0a5074e28b0..18f33e184ab 100644 --- a/src/librbd/ManagedLock.cc +++ b/src/librbd/ManagedLock.cc @@ -24,6 +24,7 @@ namespace librbd { using std::string; +using namespace managed_lock; namespace { @@ -46,7 +47,7 @@ const std::string ManagedLock::WATCHER_LOCK_TAG("internal"); template ManagedLock::ManagedLock(librados::IoCtx &ioctx, ContextWQ *work_queue, - const string& oid, Watcher *watcher, + const string& oid, Watcher *watcher, Mode mode, bool blacklist_on_break_lock, uint32_t blacklist_expire_seconds) : m_lock(util::unique_lock_name("librbd::ManagedLock::m_lock", this)), @@ -55,6 +56,7 @@ ManagedLock::ManagedLock(librados::IoCtx &ioctx, ContextWQ *work_queue, m_work_queue(work_queue), m_oid(oid), m_watcher(watcher), + m_mode(mode), m_blacklist_on_break_lock(blacklist_on_break_lock), m_blacklist_expire_seconds(blacklist_expire_seconds) { } @@ -199,7 +201,7 @@ void ManagedLock::get_locker(managed_lock::Locker *locker, ldout(m_cct, 10) << dendl; auto req = managed_lock::GetLockerRequest::create( - m_ioctx, m_oid, locker, on_finish); + m_ioctx, m_oid, m_mode == EXCLUSIVE, locker, on_finish); req->send(); } @@ -419,7 +421,7 @@ void ManagedLock::handle_pre_acquire_lock(int r) { using managed_lock::AcquireRequest; AcquireRequest* req = AcquireRequest::create( - m_ioctx, m_watcher, m_work_queue, m_oid, m_cookie, + m_ioctx, m_watcher, m_work_queue, m_oid, m_cookie, m_mode == EXCLUSIVE, m_blacklist_on_break_lock, m_blacklist_expire_seconds, util::create_context_callback< ManagedLock, &ManagedLock::handle_acquire_lock>(this)); @@ -507,7 +509,7 @@ void ManagedLock::send_reacquire_lock() { using managed_lock::ReacquireRequest; ReacquireRequest* req = ReacquireRequest::create(m_ioctx, m_oid, - m_cookie, m_new_cookie, + m_cookie, m_new_cookie, m_mode == EXCLUSIVE, util::create_context_callback< ManagedLock, &ManagedLock::handle_reacquire_lock>(this)); m_work_queue->queue(new C_SendLockRequest>(req)); diff --git a/src/librbd/ManagedLock.h b/src/librbd/ManagedLock.h index 0b4893926df..45f06b4978e 100644 --- a/src/librbd/ManagedLock.h +++ b/src/librbd/ManagedLock.h @@ -9,6 +9,7 @@ #include "include/rados/librados.hpp" #include "cls/lock/cls_lock_types.h" #include "librbd/watcher/Types.h" +#include "librbd/managed_lock/Types.h" #include "common/Mutex.h" #include #include @@ -33,15 +34,16 @@ public: static ManagedLock *create(librados::IoCtx& ioctx, ContextWQ *work_queue, const std::string& oid, Watcher *watcher, + managed_lock::Mode mode, bool blacklist_on_break_lock, uint32_t blacklist_expire_seconds) { - return new ManagedLock(ioctx, work_queue, oid, watcher, + return new ManagedLock(ioctx, work_queue, oid, watcher, mode, blacklist_on_break_lock, blacklist_expire_seconds); } ManagedLock(librados::IoCtx& ioctx, ContextWQ *work_queue, const std::string& oid, Watcher *watcher, - bool blacklist_on_break_lock, + managed_lock::Mode mode, bool blacklist_on_break_lock, uint32_t blacklist_expire_seconds); virtual ~ManagedLock(); @@ -161,6 +163,7 @@ private: ContextWQ *m_work_queue; std::string m_oid; Watcher *m_watcher; + managed_lock::Mode m_mode; bool m_blacklist_on_break_lock; uint32_t m_blacklist_expire_seconds; diff --git a/src/librbd/managed_lock/AcquireRequest.cc b/src/librbd/managed_lock/AcquireRequest.cc index 23b0f044ee0..d40b0c0dbfa 100644 --- a/src/librbd/managed_lock/AcquireRequest.cc +++ b/src/librbd/managed_lock/AcquireRequest.cc @@ -38,24 +38,26 @@ AcquireRequest* AcquireRequest::create(librados::IoCtx& ioctx, ContextWQ *work_queue, const string& oid, const string& cookie, + bool exclusive, bool blacklist_on_break_lock, uint32_t blacklist_expire_seconds, Context *on_finish) { return new AcquireRequest(ioctx, watcher, work_queue, oid, cookie, - blacklist_on_break_lock, blacklist_expire_seconds, - on_finish); + exclusive, blacklist_on_break_lock, + blacklist_expire_seconds, on_finish); } template AcquireRequest::AcquireRequest(librados::IoCtx& ioctx, Watcher *watcher, ContextWQ *work_queue, const string& oid, - const string& cookie, + const string& cookie, bool exclusive, bool blacklist_on_break_lock, uint32_t blacklist_expire_seconds, Context *on_finish) : m_ioctx(ioctx), m_watcher(watcher), m_cct(reinterpret_cast(m_ioctx.cct())), m_work_queue(work_queue), m_oid(oid), m_cookie(cookie), + m_exclusive(exclusive), m_blacklist_on_break_lock(blacklist_on_break_lock), m_blacklist_expire_seconds(blacklist_expire_seconds), m_on_finish(new C_AsyncCallback(work_queue, on_finish)) { @@ -76,7 +78,8 @@ void AcquireRequest::send_get_locker() { Context *ctx = create_context_callback< AcquireRequest, &AcquireRequest::handle_get_locker>(this); - auto req = GetLockerRequest::create(m_ioctx, m_oid, &m_locker, ctx); + auto req = GetLockerRequest::create(m_ioctx, m_oid, m_exclusive, + &m_locker, ctx); req->send(); } @@ -105,7 +108,8 @@ void AcquireRequest::send_lock() { ldout(m_cct, 10) << dendl; librados::ObjectWriteOperation op; - rados::cls::lock::lock(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, m_cookie, + rados::cls::lock::lock(&op, RBD_LOCK_NAME, + m_exclusive ? LOCK_EXCLUSIVE : LOCK_SHARED, m_cookie, ManagedLock::WATCHER_LOCK_TAG, "", utime_t(), 0); using klass = AcquireRequest; diff --git a/src/librbd/managed_lock/AcquireRequest.h b/src/librbd/managed_lock/AcquireRequest.h index fe31595df4a..16a5be36c78 100644 --- a/src/librbd/managed_lock/AcquireRequest.h +++ b/src/librbd/managed_lock/AcquireRequest.h @@ -31,6 +31,7 @@ public: static AcquireRequest* create(librados::IoCtx& ioctx, Watcher *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); @@ -61,7 +62,8 @@ private: AcquireRequest(librados::IoCtx& ioctx, Watcher *watcher, ContextWQ *work_queue, const std::string& oid, - const std::string& cookie, bool blacklist_on_break_lock, + const std::string& cookie, bool exclusive, + bool blacklist_on_break_lock, uint32_t blacklist_expire_seconds, Context *on_finish); librados::IoCtx& m_ioctx; @@ -70,6 +72,7 @@ private: ContextWQ *m_work_queue; std::string m_oid; std::string m_cookie; + bool m_exclusive; bool m_blacklist_on_break_lock; uint32_t m_blacklist_expire_seconds; Context *m_on_finish; diff --git a/src/librbd/managed_lock/GetLockerRequest.cc b/src/librbd/managed_lock/GetLockerRequest.cc index 25b182743d1..9f93d305c04 100644 --- a/src/librbd/managed_lock/GetLockerRequest.cc +++ b/src/librbd/managed_lock/GetLockerRequest.cc @@ -24,10 +24,11 @@ using util::create_rados_ack_callback; template GetLockerRequest::GetLockerRequest(librados::IoCtx& ioctx, - const std::string& oid, Locker *locker, - Context *on_finish) + const std::string& oid, bool exclusive, + Locker *locker, Context *on_finish) : m_ioctx(ioctx), m_cct(reinterpret_cast(m_ioctx.cct())), - m_oid(oid), m_locker(locker), m_on_finish(on_finish) { + m_oid(oid), m_exclusive(exclusive), m_locker(locker), + m_on_finish(on_finish) { } template @@ -61,8 +62,8 @@ void GetLockerRequest::handle_get_lockers(int r) { std::string lock_tag; if (r == 0) { bufferlist::iterator it = m_out_bl.begin(); - r = rados::cls::lock::get_lock_info_finish(&it, &lockers, - &lock_type, &lock_tag); + r = rados::cls::lock::get_lock_info_finish(&it, &lockers, &lock_type, + &lock_tag); } if (r < 0) { @@ -83,8 +84,12 @@ void GetLockerRequest::handle_get_lockers(int r) { return; } - if (lock_type == LOCK_SHARED) { - ldout(m_cct, 5) << "shared lock type detected" << dendl; + if (m_exclusive && lock_type == LOCK_SHARED) { + ldout(m_cct, 5) << "incompatible shared lock type detected" << dendl; + finish(-EBUSY); + return; + } else if (!m_exclusive && lock_type == LOCK_EXCLUSIVE) { + ldout(m_cct, 5) << "incompatible exclusive lock type detected" << dendl; finish(-EBUSY); return; } diff --git a/src/librbd/managed_lock/GetLockerRequest.h b/src/librbd/managed_lock/GetLockerRequest.h index 97373c5f6bb..9a245d88205 100644 --- a/src/librbd/managed_lock/GetLockerRequest.h +++ b/src/librbd/managed_lock/GetLockerRequest.h @@ -23,9 +23,9 @@ template class GetLockerRequest { public: static GetLockerRequest* create(librados::IoCtx& ioctx, - const std::string& oid, + const std::string& oid, bool exclusive, Locker *locker, Context *on_finish) { - return new GetLockerRequest(ioctx, oid, locker, on_finish); + return new GetLockerRequest(ioctx, oid, exclusive, locker, on_finish); } void send(); @@ -34,13 +34,14 @@ private: librados::IoCtx &m_ioctx; CephContext *m_cct; std::string m_oid; + bool m_exclusive; Locker *m_locker; Context *m_on_finish; bufferlist m_out_bl; GetLockerRequest(librados::IoCtx& ioctx, const std::string& oid, - Locker *locker, Context *on_finish); + bool exclusive, Locker *locker, Context *on_finish); void send_get_lockers(); void handle_get_lockers(int r); diff --git a/src/librbd/managed_lock/ReacquireRequest.cc b/src/librbd/managed_lock/ReacquireRequest.cc index 33bd1db7136..02c564d7ff4 100644 --- a/src/librbd/managed_lock/ReacquireRequest.cc +++ b/src/librbd/managed_lock/ReacquireRequest.cc @@ -29,9 +29,10 @@ ReacquireRequest::ReacquireRequest(librados::IoCtx& ioctx, const string& oid, const string& old_cookie, const string &new_cookie, + bool exclusive, Context *on_finish) : m_ioctx(ioctx), m_oid(oid), m_old_cookie(old_cookie), - m_new_cookie(new_cookie), m_on_finish(on_finish) { + m_new_cookie(new_cookie), m_exclusive(exclusive), m_on_finish(on_finish) { } @@ -46,8 +47,10 @@ void ReacquireRequest::set_cookie() { ldout(cct, 10) << dendl; librados::ObjectWriteOperation op; - rados::cls::lock::set_cookie(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, m_old_cookie, - ManagedLock::WATCHER_LOCK_TAG, m_new_cookie); + rados::cls::lock::set_cookie(&op, RBD_LOCK_NAME, + m_exclusive ? LOCK_EXCLUSIVE : LOCK_SHARED, + m_old_cookie, ManagedLock::WATCHER_LOCK_TAG, + m_new_cookie); librados::AioCompletion *rados_completion = create_rados_safe_callback< ReacquireRequest, &ReacquireRequest::handle_set_cookie>(this); diff --git a/src/librbd/managed_lock/ReacquireRequest.h b/src/librbd/managed_lock/ReacquireRequest.h index 60256c836de..3f2b7d7e211 100644 --- a/src/librbd/managed_lock/ReacquireRequest.h +++ b/src/librbd/managed_lock/ReacquireRequest.h @@ -24,13 +24,16 @@ public: const std::string& oid, const std::string& old_cookie, const std::string &new_cookie, + bool exclusive, Context *on_finish) { - return new ReacquireRequest(ioctx, oid, old_cookie, new_cookie, on_finish); + return new ReacquireRequest(ioctx, oid, old_cookie, new_cookie, exclusive, + on_finish); } ReacquireRequest(librados::IoCtx& ioctx, const std::string& oid, const std::string& old_cookie, - const std::string &new_cookie, Context *on_finish); + const std::string &new_cookie, bool exclusive, + Context *on_finish); void send(); @@ -52,6 +55,7 @@ private: std::string m_oid; std::string m_old_cookie; std::string m_new_cookie; + bool m_exclusive; Context *m_on_finish; void set_cookie(); diff --git a/src/librbd/managed_lock/Types.h b/src/librbd/managed_lock/Types.h index beb764ea5b5..01c31b6dfb7 100644 --- a/src/librbd/managed_lock/Types.h +++ b/src/librbd/managed_lock/Types.h @@ -17,6 +17,12 @@ struct Locker { uint64_t handle; }; +enum Mode { + EXCLUSIVE, + SHARED +}; + + } // namespace managed_lock } // namespace librbd diff --git a/src/test/librbd/managed_lock/test_mock_AcquireRequest.cc b/src/test/librbd/managed_lock/test_mock_AcquireRequest.cc index b99f202ffeb..5ea9ada6a04 100644 --- a/src/test/librbd/managed_lock/test_mock_AcquireRequest.cc +++ b/src/test/librbd/managed_lock/test_mock_AcquireRequest.cc @@ -56,7 +56,7 @@ struct GetLockerRequest { static GetLockerRequest *s_instance; static GetLockerRequest* create(librados::IoCtx& ioctx, - const std::string& oid, + const std::string& oid, bool exclusive, Locker *locker, Context *on_finish) { assert(s_instance != nullptr); s_instance->locker = locker; @@ -84,6 +84,19 @@ template class librbd::managed_lock::AcquireRequest; #include "librbd/ManagedLock.cc" template class librbd::ManagedLock; +namespace { + +MATCHER_P(IsLockType, exclusive, "") { + cls_lock_lock_op op; + bufferlist bl; + bl.share(arg); + bufferlist::iterator iter = bl.begin(); + ::decode(op, iter); + return op.type == (exclusive ? LOCK_EXCLUSIVE : LOCK_SHARED); +} + +} // anonymous namespace + namespace librbd { namespace managed_lock { @@ -105,9 +118,11 @@ public: typedef GetLockerRequest MockGetLockerRequest; typedef ManagedLock MockManagedLock; - void expect_lock(MockImageCtx &mock_image_ctx, int r) { + void expect_lock(MockImageCtx &mock_image_ctx, int r, + bool exclusive = true) { EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), - exec(mock_image_ctx.header_oid, _, StrEq("lock"), StrEq("lock"), _, _, _)) + exec(mock_image_ctx.header_oid, _, StrEq("lock"), + StrEq("lock"), IsLockType(exclusive), _, _)) .WillOnce(Return(r)); } @@ -129,7 +144,7 @@ public: } }; -TEST_F(TestMockManagedLockAcquireRequest, Success) { +TEST_F(TestMockManagedLockAcquireRequest, SuccessExclusive) { librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -144,7 +159,27 @@ TEST_F(TestMockManagedLockAcquireRequest, Success) { C_SaferCond ctx; MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx.md_ctx, mock_image_ctx.image_watcher, ictx->op_work_queue, mock_image_ctx.header_oid, - TEST_COOKIE, true, 0, &ctx); + TEST_COOKIE, true, true, 0, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); +} + +TEST_F(TestMockManagedLockAcquireRequest, SuccessShared) { + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockImageCtx mock_image_ctx(*ictx); + MockGetLockerRequest mock_get_locker_request; + + InSequence seq; + expect_get_locker(mock_image_ctx, mock_get_locker_request, {}, 0); + expect_lock(mock_image_ctx, 0, false); + + C_SaferCond ctx; + MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx.md_ctx, + mock_image_ctx.image_watcher, ictx->op_work_queue, mock_image_ctx.header_oid, + TEST_COOKIE, false, true, 0, &ctx); req->send(); ASSERT_EQ(0, ctx.wait()); } @@ -170,7 +205,7 @@ TEST_F(TestMockManagedLockAcquireRequest, LockBusy) { C_SaferCond ctx; MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx.md_ctx, mock_image_ctx.image_watcher, ictx->op_work_queue, mock_image_ctx.header_oid, - TEST_COOKIE, true, 0, &ctx); + TEST_COOKIE, true, true, 0, &ctx); req->send(); ASSERT_EQ(-ENOENT, ctx.wait()); } @@ -188,7 +223,7 @@ TEST_F(TestMockManagedLockAcquireRequest, GetLockInfoError) { C_SaferCond ctx; MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx.md_ctx, mock_image_ctx.image_watcher, ictx->op_work_queue, mock_image_ctx.header_oid, - TEST_COOKIE, true, 0, &ctx); + TEST_COOKIE, true, true, 0, &ctx); req->send(); ASSERT_EQ(-EINVAL, ctx.wait()); } @@ -207,7 +242,7 @@ TEST_F(TestMockManagedLockAcquireRequest, GetLockInfoEmpty) { C_SaferCond ctx; MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx.md_ctx, mock_image_ctx.image_watcher, ictx->op_work_queue, mock_image_ctx.header_oid, - TEST_COOKIE, true, 0, &ctx); + TEST_COOKIE, true, true, 0, &ctx); req->send(); ASSERT_EQ(-EINVAL, ctx.wait()); } @@ -230,7 +265,7 @@ TEST_F(TestMockManagedLockAcquireRequest, BreakLockError) { C_SaferCond ctx; MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx.md_ctx, mock_image_ctx.image_watcher, ictx->op_work_queue, mock_image_ctx.header_oid, - TEST_COOKIE, true, 0, &ctx); + TEST_COOKIE, true, true, 0, &ctx); req->send(); ASSERT_EQ(-EINVAL, ctx.wait()); } diff --git a/src/test/librbd/managed_lock/test_mock_GetLockerRequest.cc b/src/test/librbd/managed_lock/test_mock_GetLockerRequest.cc index af3bb07a369..e8b1ec76d3d 100644 --- a/src/test/librbd/managed_lock/test_mock_GetLockerRequest.cc +++ b/src/test/librbd/managed_lock/test_mock_GetLockerRequest.cc @@ -78,7 +78,7 @@ public: } }; -TEST_F(TestMockManagedLockGetLockerRequest, Success) { +TEST_F(TestMockManagedLockGetLockerRequest, SuccessExclusive) { REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); librbd::ImageCtx *ictx; @@ -95,7 +95,34 @@ TEST_F(TestMockManagedLockGetLockerRequest, Success) { C_SaferCond ctx; Locker locker; MockGetLockerRequest *req = MockGetLockerRequest::create( - mock_image_ctx.md_ctx, mock_image_ctx.header_oid, &locker, &ctx); + mock_image_ctx.md_ctx, mock_image_ctx.header_oid, true, &locker, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + ASSERT_EQ(entity_name_t::CLIENT(1), locker.entity); + ASSERT_EQ("1.2.3.4:0/0", locker.address); + ASSERT_EQ("auto 123", locker.cookie); + ASSERT_EQ(123U, locker.handle); +} + +TEST_F(TestMockManagedLockGetLockerRequest, SuccessShared) { + REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + expect_op_work_queue(mock_image_ctx); + + InSequence seq; + expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4", + "auto 123", ManagedLock<>::WATCHER_LOCK_TAG, + LOCK_SHARED); + + C_SaferCond ctx; + Locker locker; + MockGetLockerRequest *req = MockGetLockerRequest::create( + mock_image_ctx.md_ctx, mock_image_ctx.header_oid, false, &locker, &ctx); req->send(); ASSERT_EQ(0, ctx.wait()); @@ -121,7 +148,7 @@ TEST_F(TestMockManagedLockGetLockerRequest, GetLockInfoError) { C_SaferCond ctx; Locker locker; MockGetLockerRequest *req = MockGetLockerRequest::create( - mock_image_ctx.md_ctx, mock_image_ctx.header_oid, &locker, &ctx); + mock_image_ctx.md_ctx, mock_image_ctx.header_oid, true, &locker, &ctx); req->send(); ASSERT_EQ(-EINVAL, ctx.wait()); } @@ -142,7 +169,7 @@ TEST_F(TestMockManagedLockGetLockerRequest, GetLockInfoEmpty) { C_SaferCond ctx; Locker locker; MockGetLockerRequest *req = MockGetLockerRequest::create( - mock_image_ctx.md_ctx, mock_image_ctx.header_oid, &locker, &ctx); + mock_image_ctx.md_ctx, mock_image_ctx.header_oid, true, &locker, &ctx); req->send(); ASSERT_EQ(-ENOENT, ctx.wait()); } @@ -163,12 +190,12 @@ TEST_F(TestMockManagedLockGetLockerRequest, GetLockInfoExternalTag) { C_SaferCond ctx; Locker locker; MockGetLockerRequest *req = MockGetLockerRequest::create( - mock_image_ctx.md_ctx, mock_image_ctx.header_oid, &locker, &ctx); + mock_image_ctx.md_ctx, mock_image_ctx.header_oid, true, &locker, &ctx); req->send(); ASSERT_EQ(-EBUSY, ctx.wait()); } -TEST_F(TestMockManagedLockGetLockerRequest, GetLockInfoShared) { +TEST_F(TestMockManagedLockGetLockerRequest, GetLockInfoIncompatibleShared) { REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); librbd::ImageCtx *ictx; @@ -185,7 +212,29 @@ TEST_F(TestMockManagedLockGetLockerRequest, GetLockInfoShared) { C_SaferCond ctx; Locker locker; MockGetLockerRequest *req = MockGetLockerRequest::create( - mock_image_ctx.md_ctx, mock_image_ctx.header_oid, &locker, &ctx); + mock_image_ctx.md_ctx, mock_image_ctx.header_oid, true, &locker, &ctx); + req->send(); + ASSERT_EQ(-EBUSY, ctx.wait()); +} + +TEST_F(TestMockManagedLockGetLockerRequest, GetLockInfoIncompatibleExclusive) { + REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + expect_op_work_queue(mock_image_ctx); + + InSequence seq; + expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4", + "auto 123", ManagedLock<>::WATCHER_LOCK_TAG, + LOCK_EXCLUSIVE); + + C_SaferCond ctx; + Locker locker; + MockGetLockerRequest *req = MockGetLockerRequest::create( + mock_image_ctx.md_ctx, mock_image_ctx.header_oid, false, &locker, &ctx); req->send(); ASSERT_EQ(-EBUSY, ctx.wait()); } @@ -207,7 +256,7 @@ TEST_F(TestMockManagedLockGetLockerRequest, GetLockInfoExternalCookie) { C_SaferCond ctx; Locker locker; MockGetLockerRequest *req = MockGetLockerRequest::create( - mock_image_ctx.md_ctx, mock_image_ctx.header_oid, &locker, &ctx); + mock_image_ctx.md_ctx, mock_image_ctx.header_oid, true, &locker, &ctx); req->send(); ASSERT_EQ(-EBUSY, ctx.wait()); } diff --git a/src/test/librbd/managed_lock/test_mock_ReacquireRequest.cc b/src/test/librbd/managed_lock/test_mock_ReacquireRequest.cc index 634b3538536..103078d2526 100644 --- a/src/test/librbd/managed_lock/test_mock_ReacquireRequest.cc +++ b/src/test/librbd/managed_lock/test_mock_ReacquireRequest.cc @@ -19,6 +19,19 @@ template class librbd::managed_lock::ReacquireRequest; #include "librbd/ManagedLock.cc" template class librbd::ManagedLock; +namespace { + +MATCHER_P(IsLockType, exclusive, "") { + cls_lock_set_cookie_op op; + bufferlist bl; + bl.share(arg); + bufferlist::iterator iter = bl.begin(); + ::decode(op, iter); + return op.type == (exclusive ? LOCK_EXCLUSIVE : LOCK_SHARED); +} + +} // anonymous namespace + namespace librbd { namespace managed_lock { @@ -27,20 +40,22 @@ using ::testing::InSequence; using ::testing::Return; using ::testing::StrEq; + class TestMockManagedLockReacquireRequest : public TestMockFixture { public: typedef ReacquireRequest MockReacquireRequest; typedef ManagedLock MockManagedLock; - void expect_set_cookie(MockImageCtx &mock_image_ctx, int r) { + void expect_set_cookie(MockImageCtx &mock_image_ctx, int r, + bool exclusive = true) { EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), exec(mock_image_ctx.header_oid, _, StrEq("lock"), - StrEq("set_cookie"), _, _, _)) + StrEq("set_cookie"), IsLockType(exclusive), _, _)) .WillOnce(Return(r)); } }; -TEST_F(TestMockManagedLockReacquireRequest, Success) { +TEST_F(TestMockManagedLockReacquireRequest, SuccessExclusive) { librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -52,7 +67,24 @@ TEST_F(TestMockManagedLockReacquireRequest, Success) { C_SaferCond ctx; MockReacquireRequest *req = MockReacquireRequest::create( mock_image_ctx.md_ctx, mock_image_ctx.header_oid, "old_cookie", - "new_cookie", &ctx); + "new_cookie", true, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); +} + +TEST_F(TestMockManagedLockReacquireRequest, SuccessShared) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockImageCtx mock_image_ctx(*ictx); + + InSequence seq; + expect_set_cookie(mock_image_ctx, 0, false); + + C_SaferCond ctx; + MockReacquireRequest *req = MockReacquireRequest::create( + mock_image_ctx.md_ctx, mock_image_ctx.header_oid, "old_cookie", + "new_cookie", false, &ctx); req->send(); ASSERT_EQ(0, ctx.wait()); } @@ -69,7 +101,7 @@ TEST_F(TestMockManagedLockReacquireRequest, NotSupported) { C_SaferCond ctx; MockReacquireRequest *req = MockReacquireRequest::create( mock_image_ctx.md_ctx, mock_image_ctx.header_oid, "old_cookie", - "new_cookie", &ctx); + "new_cookie", true, &ctx); req->send(); ASSERT_EQ(-EOPNOTSUPP, ctx.wait()); } @@ -86,7 +118,7 @@ TEST_F(TestMockManagedLockReacquireRequest, Error) { C_SaferCond ctx; MockReacquireRequest *req = MockReacquireRequest::create( mock_image_ctx.md_ctx, mock_image_ctx.header_oid, "old_cookie", - "new_cookie", &ctx); + "new_cookie", true, &ctx); req->send(); ASSERT_EQ(-EBUSY, ctx.wait()); } diff --git a/src/test/librbd/test_mock_ExclusiveLock.cc b/src/test/librbd/test_mock_ExclusiveLock.cc index 525d95b94f0..85b5570f95f 100644 --- a/src/test/librbd/test_mock_ExclusiveLock.cc +++ b/src/test/librbd/test_mock_ExclusiveLock.cc @@ -117,11 +117,12 @@ struct AcquireRequest : public BaseRequest struct ReacquireRequest : public BaseRequest > { static ReacquireRequest* create(librados::IoCtx &ioctx, const std::string& oid, const string& old_cookie, const std::string& new_cookie, - Context *on_finish) { - return BaseRequest::create(ioctx, nullptr, nullptr, oid, new_cookie, on_finish); + bool exclusive, Context *on_finish) { + return BaseRequest::create(ioctx, nullptr, nullptr, oid, new_cookie, + on_finish); } MOCK_METHOD0(send, void()); @@ -139,6 +141,13 @@ struct ReacquireRequest : public BaseRequest 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()); }; diff --git a/src/test/librbd/test_mock_ManagedLock.cc b/src/test/librbd/test_mock_ManagedLock.cc index f546003b9cd..7e79aa24125 100644 --- a/src/test/librbd/test_mock_ManagedLock.cc +++ b/src/test/librbd/test_mock_ManagedLock.cc @@ -57,7 +57,7 @@ struct AcquireRequest : public BaseRequest struct ReacquireRequest : public BaseRequest > { static ReacquireRequest* create(librados::IoCtx &ioctx, const std::string& oid, const string& old_cookie, const std::string& new_cookie, - Context *on_finish) { - return BaseRequest::create(ioctx, nullptr, nullptr, oid, new_cookie, on_finish); + bool exclusive, Context *on_finish) { + return BaseRequest::create(ioctx, nullptr, nullptr, oid, new_cookie, + on_finish); } MOCK_METHOD0(send, void()); @@ -79,13 +80,19 @@ struct ReacquireRequest : public BaseRequest 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()); }; template <> struct GetLockerRequest { static GetLockerRequest* create(librados::IoCtx& ioctx, - const std::string& oid, + const std::string& oid, bool exclusive, Locker *locker, Context *on_finish) { assert(0 == "unexpected call"); } @@ -215,7 +222,7 @@ TEST_F(TestMockManagedLock, StateTransitions) { MockManagedLockImageCtx mock_image_ctx(*ictx); MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue, ictx->header_oid, mock_image_ctx.image_watcher, - true, 0); + librbd::managed_lock::EXCLUSIVE, true, 0); InSequence seq; MockAcquireRequest request_lock_acquire1; @@ -246,7 +253,7 @@ TEST_F(TestMockManagedLock, AcquireLockLockedState) { MockManagedLockImageCtx mock_image_ctx(*ictx); MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue, ictx->header_oid, mock_image_ctx.image_watcher, - true, 0); + librbd::managed_lock::EXCLUSIVE, true, 0); InSequence seq; MockAcquireRequest try_lock_acquire; @@ -266,7 +273,7 @@ TEST_F(TestMockManagedLock, AcquireLockAlreadyLocked) { MockManagedLockImageCtx mock_image_ctx(*ictx); MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue, ictx->header_oid, mock_image_ctx.image_watcher, - true, 0); + librbd::managed_lock::EXCLUSIVE, true, 0); InSequence seq; MockAcquireRequest try_lock_acquire; @@ -284,7 +291,7 @@ TEST_F(TestMockManagedLock, AcquireLockBusy) { MockManagedLockImageCtx mock_image_ctx(*ictx); MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue, ictx->header_oid, mock_image_ctx.image_watcher, - true, 0); + librbd::managed_lock::EXCLUSIVE, true, 0); InSequence seq; MockAcquireRequest try_lock_acquire; @@ -302,7 +309,7 @@ TEST_F(TestMockManagedLock, AcquireLockError) { MockManagedLockImageCtx mock_image_ctx(*ictx); MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue, ictx->header_oid, mock_image_ctx.image_watcher, - true, 0); + librbd::managed_lock::EXCLUSIVE, true, 0); InSequence seq; MockAcquireRequest try_lock_acquire; @@ -321,7 +328,7 @@ TEST_F(TestMockManagedLock, AcquireLockBlacklist) { MockManagedLockImageCtx mock_image_ctx(*ictx); MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue, ictx->header_oid, mock_image_ctx.image_watcher, - true, 0); + librbd::managed_lock::EXCLUSIVE, true, 0); InSequence seq; // will abort after seeing blacklist error (avoid infinite request loop) @@ -340,7 +347,7 @@ TEST_F(TestMockManagedLock, ReleaseLockUnlockedState) { MockManagedLockImageCtx mock_image_ctx(*ictx); MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue, ictx->header_oid, mock_image_ctx.image_watcher, - true, 0); + librbd::managed_lock::EXCLUSIVE, true, 0); InSequence seq; ASSERT_EQ(0, when_release_lock(managed_lock)); @@ -355,7 +362,7 @@ TEST_F(TestMockManagedLock, ReleaseLockError) { MockManagedLockImageCtx mock_image_ctx(*ictx); MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue, ictx->header_oid, mock_image_ctx.image_watcher, - true, 0); + librbd::managed_lock::EXCLUSIVE, true, 0); InSequence seq; MockAcquireRequest try_lock_acquire; @@ -381,7 +388,7 @@ TEST_F(TestMockManagedLock, ConcurrentRequests) { MockManagedLockImageCtx mock_image_ctx(*ictx); MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue, ictx->header_oid, mock_image_ctx.image_watcher, - true, 0); + librbd::managed_lock::EXCLUSIVE, true, 0); InSequence seq; expect_get_watch_handle(*mock_image_ctx.image_watcher); @@ -438,7 +445,7 @@ TEST_F(TestMockManagedLock, ReacquireLock) { MockManagedLockImageCtx mock_image_ctx(*ictx); MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue, ictx->header_oid, mock_image_ctx.image_watcher, - true, 0); + librbd::managed_lock::EXCLUSIVE, true, 0); InSequence seq; MockAcquireRequest request_lock_acquire; @@ -465,7 +472,7 @@ TEST_F(TestMockManagedLock, ReacquireLockError) { MockManagedLockImageCtx mock_image_ctx(*ictx); MockManagedLock managed_lock(ictx->md_ctx, ictx->op_work_queue, ictx->header_oid, mock_image_ctx.image_watcher, - true, 0); + librbd::managed_lock::EXCLUSIVE, true, 0); InSequence seq; MockAcquireRequest request_lock_acquire;