]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: Support for shared locking in ManagedLock 12886/head
authorRicardo Dias <rdias@suse.com>
Thu, 5 Jan 2017 11:23:56 +0000 (11:23 +0000)
committerRicardo Dias <rdias@suse.com>
Tue, 17 Jan 2017 21:41:00 +0000 (21:41 +0000)
Signed-off-by: Ricardo Dias <rdias@suse.com>
15 files changed:
src/librbd/ExclusiveLock.cc
src/librbd/ManagedLock.cc
src/librbd/ManagedLock.h
src/librbd/managed_lock/AcquireRequest.cc
src/librbd/managed_lock/AcquireRequest.h
src/librbd/managed_lock/GetLockerRequest.cc
src/librbd/managed_lock/GetLockerRequest.h
src/librbd/managed_lock/ReacquireRequest.cc
src/librbd/managed_lock/ReacquireRequest.h
src/librbd/managed_lock/Types.h
src/test/librbd/managed_lock/test_mock_AcquireRequest.cc
src/test/librbd/managed_lock/test_mock_GetLockerRequest.cc
src/test/librbd/managed_lock/test_mock_ReacquireRequest.cc
src/test/librbd/test_mock_ExclusiveLock.cc
src/test/librbd/test_mock_ManagedLock.cc

index 2b1621ef60d3482ca53b0f8b5e25b856002f7a20..7d8e19ba296224feadc618ea44a8d0ef1fb186b7 100644 (file)
@@ -26,7 +26,8 @@ using ML = ManagedLock<I>;
 template <typename I>
 ExclusiveLock<I>::ExclusiveLock(I &image_ctx)
   : ML<I>(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)  {
index 0a5074e28b0548314071a9920e1072ffbdc882ae..18f33e184ab6ad870d428575247168e3b607edb3 100644 (file)
@@ -24,6 +24,7 @@
 namespace librbd {
 
 using std::string;
+using namespace managed_lock;
 
 namespace {
 
@@ -46,7 +47,7 @@ const std::string ManagedLock<I>::WATCHER_LOCK_TAG("internal");
 
 template <typename I>
 ManagedLock<I>::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<I>::m_lock", this)),
@@ -55,6 +56,7 @@ ManagedLock<I>::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<I>::get_locker(managed_lock::Locker *locker,
   ldout(m_cct, 10) << dendl;
 
   auto req = managed_lock::GetLockerRequest<I>::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<I>::handle_pre_acquire_lock(int r) {
 
   using managed_lock::AcquireRequest;
   AcquireRequest<I>* req = AcquireRequest<I>::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<I>, &ManagedLock<I>::handle_acquire_lock>(this));
@@ -507,7 +509,7 @@ void ManagedLock<I>::send_reacquire_lock() {
 
   using managed_lock::ReacquireRequest;
   ReacquireRequest<I>* req = ReacquireRequest<I>::create(m_ioctx, m_oid,
-      m_cookie, m_new_cookie,
+      m_cookie, m_new_cookie, m_mode == EXCLUSIVE,
       util::create_context_callback<
         ManagedLock, &ManagedLock<I>::handle_reacquire_lock>(this));
   m_work_queue->queue(new C_SendLockRequest<ReacquireRequest<I>>(req));
index 0b4893926df5b58d95df7dd9ba8e4ddff664c181..45f06b4978e25e00451c956dbc6bae04b91140a0 100644 (file)
@@ -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 <list>
 #include <string>
@@ -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;
 
index 23b0f044ee038acb15b2c77892e051a6aa510a7e..d40b0c0dbfa56b9c3af1293936e088cc6c5f3424 100644 (file)
@@ -38,24 +38,26 @@ AcquireRequest<I>* AcquireRequest<I>::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 <typename I>
 AcquireRequest<I>::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<CephContext *>(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<ContextWQ>(work_queue, on_finish)) {
@@ -76,7 +78,8 @@ void AcquireRequest<I>::send_get_locker() {
 
   Context *ctx = create_context_callback<
     AcquireRequest<I>, &AcquireRequest<I>::handle_get_locker>(this);
-  auto req = GetLockerRequest<I>::create(m_ioctx, m_oid, &m_locker, ctx);
+  auto req = GetLockerRequest<I>::create(m_ioctx, m_oid, m_exclusive,
+                                         &m_locker, ctx);
   req->send();
 }
 
@@ -105,7 +108,8 @@ void AcquireRequest<I>::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<I>::WATCHER_LOCK_TAG, "", utime_t(), 0);
 
   using klass = AcquireRequest;
index fe31595df4a3e90299968c126513819cc8ae0af8..16a5be36c787981300b4fed51e73b1d86940b704 100644 (file)
@@ -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;
index 25b182743d152e110b010dba3293704b74e3010e..9f93d305c04d641ac033b67436405bf812562c4d 100644 (file)
@@ -24,10 +24,11 @@ using util::create_rados_ack_callback;
 
 template <typename I>
 GetLockerRequest<I>::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<CephContext *>(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 <typename I>
@@ -61,8 +62,8 @@ void GetLockerRequest<I>::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<I>::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;
   }
index 97373c5f6bbdbefe13a336f83b8092951aa245c1..9a245d8820597826fd2c03d278ca36e34a03c3af 100644 (file)
@@ -23,9 +23,9 @@ template <typename ImageCtxT = ImageCtx>
 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);
index 33bd1db7136a6160b53b8d282718ea6dfcae8514..02c564d7ff4bb15ae4da31c43fdee30165444408 100644 (file)
@@ -29,9 +29,10 @@ ReacquireRequest<I>::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<I>::set_cookie() {
   ldout(cct, 10) << dendl;
 
   librados::ObjectWriteOperation op;
-  rados::cls::lock::set_cookie(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, m_old_cookie,
-                               ManagedLock<I>::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<I>::WATCHER_LOCK_TAG,
+                               m_new_cookie);
 
   librados::AioCompletion *rados_completion = create_rados_safe_callback<
     ReacquireRequest, &ReacquireRequest::handle_set_cookie>(this);
index 60256c836de6d33e9f7a43fa3d941fded9b8fa10..3f2b7d7e2110d02e8b6a0d17890a5b2773e6edca 100644 (file)
@@ -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();
index beb764ea5b521a62759048dcf59de2e3a7ea57ed..01c31b6dfb7275f86379def243dbad07549b956f 100644 (file)
@@ -17,6 +17,12 @@ struct Locker {
   uint64_t handle;
 };
 
+enum Mode {
+  EXCLUSIVE,
+  SHARED
+};
+
+
 } // namespace managed_lock
 } // namespace librbd
 
index b99f202ffeb20d056d38c29bc7252b8f5b8a0f64..5ea9ada6a04bc934c13197a11578e9279e91f1c1 100644 (file)
@@ -56,7 +56,7 @@ struct GetLockerRequest<librbd::MockImageCtx> {
 
   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<librbd::MockImageCtx>;
 #include "librbd/ManagedLock.cc"
 template class librbd::ManagedLock<librbd::MockImageCtx>;
 
+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<MockImageCtx> MockGetLockerRequest;
   typedef ManagedLock<MockImageCtx> 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());
 }
index af3bb07a36965dfa83ca07ec5a6f559d2680c950..e8b1ec76d3df8b7872b2459d3861cbe572d9caec 100644 (file)
@@ -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());
 }
index 634b35385366b3c44ceea06b0af6a8bdce60a8a8..103078d252687b889a9f916c6ab7a0eb2c1caff2 100644 (file)
@@ -19,6 +19,19 @@ template class librbd::managed_lock::ReacquireRequest<librbd::MockImageCtx>;
 #include "librbd/ManagedLock.cc"
 template class librbd::ManagedLock<librbd::MockImageCtx>;
 
+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<MockImageCtx> MockReacquireRequest;
   typedef ManagedLock<MockImageCtx> 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());
 }
index 525d95b94f05cff6dbba9723cfdea364008a6124..85b5570f95f2aa7e5c7e4cb945c23de6439838ed 100644 (file)
@@ -117,11 +117,12 @@ struct AcquireRequest<MockExclusiveLockImageCtx> : public BaseRequest<AcquireReq
   static AcquireRequest* create(librados::IoCtx& ioctx,
                                 MockImageWatcher *watcher,
                                 ContextWQ *work_queue, const std::string& oid,
-                                const std::string& cookie,
+                                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);
+    return BaseRequest::create(ioctx, watcher, work_queue, oid, cookie,
+                               on_finish);
   }
   MOCK_METHOD0(send, void());
 };
@@ -130,8 +131,9 @@ template <>
 struct ReacquireRequest<MockExclusiveLockImageCtx> : public BaseRequest<ReacquireRequest<MockExclusiveLockImageCtx> > {
   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<MockExclusiveLockImageCtx> : public BaseRequest<Reacquir
 
 template <>
 struct ReleaseRequest<MockExclusiveLockImageCtx> : public BaseRequest<ReleaseRequest<MockExclusiveLockImageCtx> > {
+  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());
 };
 
index f546003b9cdef3904485620ce078bee0b7f7a60c..7e79aa241251b311a8c7bc37fa056eaa886e8e2a 100644 (file)
@@ -57,7 +57,7 @@ struct AcquireRequest<MockManagedLockImageCtx> : public BaseRequest<AcquireReque
                                MockImageWatcher *watcher,
                                 ContextWQ *work_queue, const std::string& oid,
                                 const std::string& cookie,
-                                bool blacklist_on_break_lock,
+                                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);
@@ -70,8 +70,9 @@ template <>
 struct ReacquireRequest<MockManagedLockImageCtx> : public BaseRequest<ReacquireRequest<MockManagedLockImageCtx> > {
   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<MockManagedLockImageCtx> : public BaseRequest<ReacquireR
 
 template <>
 struct ReleaseRequest<MockManagedLockImageCtx> : public BaseRequest<ReleaseRequest<MockManagedLockImageCtx> > {
+  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<MockManagedLockImageCtx> {
   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;