]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: API methods to directly acquire and release the exclusive lock
authorMykola Golub <mgolub@mirantis.com>
Wed, 8 Jun 2016 12:11:02 +0000 (15:11 +0300)
committerJason Dillaman <dillaman@redhat.com>
Mon, 30 Jan 2017 14:20:37 +0000 (09:20 -0500)
Fixes: http://tracker.ceph.com/issues/15632
Signed-off-by: Mykola Golub <mgolub@mirantis.com>
(cherry picked from commit 8f1b47fd5da021ec320fd0b5fc0fd68ffff8a706)

Conflicts:
src/common/config_opts.h: trivial resolution
src/include/rbd/librbd.h: trivial resolution
src/librbd/CMakeLists.txt: trivial resolution
src/librbd/Makefile.am: trivial resolution
src/test/librbd/test_librbd.cc: trivial resolution

19 files changed:
src/common/config_opts.h
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/AioImageRequestWQ.cc
src/librbd/CMakeLists.txt
src/librbd/ImageCtx.cc
src/librbd/ImageWatcher.cc
src/librbd/Makefile.am
src/librbd/exclusive_lock/AutomaticPolicy.cc [new file with mode: 0644]
src/librbd/exclusive_lock/AutomaticPolicy.h [new file with mode: 0644]
src/librbd/exclusive_lock/Policy.h
src/librbd/exclusive_lock/StandardPolicy.cc
src/librbd/exclusive_lock/StandardPolicy.h
src/librbd/internal.cc
src/librbd/internal.h
src/librbd/librbd.cc
src/test/librbd/test_librbd.cc
src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.cc
src/tracing/librbd.tp

index 78e67e2c8fc3c0d942a8cfea53e5acb0dd59337e..8555128105b097bb6666cca754ca0db24548223d 100644 (file)
@@ -1175,6 +1175,7 @@ OPTION(rbd_tracing, OPT_BOOL, false) // true if LTTng-UST tracepoints should be
 OPTION(rbd_validate_pool, OPT_BOOL, true) // true if empty pools should be validated for RBD compatibility
 OPTION(rbd_validate_names, OPT_BOOL, true) // true if image specs should be validated
 OPTION(rbd_mirroring_resync_after_disconnect, OPT_BOOL, false) // automatically start image resync after mirroring is disconnected due to being laggy
+OPTION(rbd_auto_exclusive_lock_until_manual_request, OPT_BOOL, true) // whether to automatically acquire/release exclusive lock until it is explicitly requested, i.e. before we know the user of librbd is properly using the lock API
 
 /*
  * The following options change the behavior for librbd's image creation methods that
index 418e121e5eedeac70d9a8724e01a59bb7248dc4c..c96ebfd01694d2dcc065756a645798f67624e764 100644 (file)
@@ -134,6 +134,11 @@ typedef struct {
   bool up;
 } rbd_mirror_image_status_t;
 
+typedef enum {
+  RBD_LOCK_MODE_EXCLUSIVE = 0,
+  RBD_LOCK_MODE_SHARED = 1,
+} rbd_lock_mode_t;
+
 CEPH_RBD_API void rbd_version(int *major, int *minor, int *extra);
 
 /* image options */
@@ -301,6 +306,8 @@ CEPH_RBD_API int rbd_set_image_notification(rbd_image_t image, int fd, int type)
 
 /* exclusive lock feature */
 CEPH_RBD_API int rbd_is_exclusive_lock_owner(rbd_image_t image, int *is_owner);
+CEPH_RBD_API int rbd_lock_acquire(rbd_image_t image, rbd_lock_mode_t lock_mode);
+CEPH_RBD_API int rbd_lock_release(rbd_image_t image);
 
 /* object map feature */
 CEPH_RBD_API int rbd_rebuild_object_map(rbd_image_t image,
index 81179b586b1158c48474de2701dae2c4a9440c40..d67f23e8cbe86f16609e6a610524c5f31de67d33 100644 (file)
@@ -212,6 +212,8 @@ public:
 
   /* exclusive lock feature */
   int is_exclusive_lock_owner(bool *is_owner);
+  int lock_acquire(rbd_lock_mode_t lock_mode);
+  int lock_release();
 
   /* object map feature */
   int rebuild_object_map(ProgressContext &prog_ctx);
index cfb3bb97fbb5abf4eb41bbf1426f91ab49cd7de4..26e265ec7372c57a2d6e8ea108ec1699193ad76e 100644 (file)
@@ -6,6 +6,7 @@
 #include "librbd/AioCompletion.h"
 #include "librbd/AioImageRequest.h"
 #include "librbd/ExclusiveLock.h"
+#include "librbd/exclusive_lock/Policy.h"
 #include "librbd/ImageCtx.h"
 #include "librbd/ImageState.h"
 #include "librbd/internal.h"
@@ -443,6 +444,17 @@ void AioImageRequestWQ::queue(AioImageRequest<> *req) {
 
   assert(m_image_ctx.owner_lock.is_locked());
   bool write_op = req->is_write_op();
+  bool lock_required = (write_op && is_lock_required()) ||
+    (!write_op && m_require_lock_on_read);
+
+  if (lock_required && !m_image_ctx.get_exclusive_lock_policy()->may_auto_request_lock()) {
+    lderr(cct) << "op requires exclusive lock" << dendl;
+    req->fail(-EROFS);
+    delete req;
+    finish_in_flight_op();
+    return;
+  }
+
   if (write_op) {
     m_queued_writes.inc();
   } else {
@@ -451,8 +463,7 @@ void AioImageRequestWQ::queue(AioImageRequest<> *req) {
 
   ThreadPool::PointerWQ<AioImageRequest<> >::queue(req);
 
-  if ((write_op && is_lock_required()) ||
-      (!write_op && m_require_lock_on_read)) {
+  if (lock_required) {
     m_image_ctx.exclusive_lock->request_lock(nullptr);
   }
 }
index 3e9c4b5b9c184b4e34d19055a3176c2401dc73c3..71c8b6a94d5b4ee892f56cf93e4d81f8057a0749 100644 (file)
@@ -27,6 +27,7 @@ set(librbd_internal_srcs
   Operations.cc
   Utils.cc
   exclusive_lock/AcquireRequest.cc
+  exclusive_lock/AutomaticPolicy.cc
   exclusive_lock/ReacquireRequest.cc
   exclusive_lock/ReleaseRequest.cc
   exclusive_lock/StandardPolicy.cc
index 863a1235e4aa8322ad3c0084eec557327cef4938..97af75bb48f326403ee9267f5d26620a8b5da18a 100644 (file)
@@ -15,6 +15,7 @@
 #include "librbd/AsyncOperation.h"
 #include "librbd/AsyncRequest.h"
 #include "librbd/ExclusiveLock.h"
+#include "librbd/exclusive_lock/AutomaticPolicy.h"
 #include "librbd/exclusive_lock/StandardPolicy.h"
 #include "librbd/internal.h"
 #include "librbd/ImageCtx.h"
@@ -191,7 +192,11 @@ struct C_InvalidateCache : public Context {
                                   cct->_conf->rbd_op_thread_timeout,
                                   thread_pool_singleton);
 
-    exclusive_lock_policy = new exclusive_lock::StandardPolicy(this);
+    if (cct->_conf->rbd_auto_exclusive_lock_until_manual_request) {
+      exclusive_lock_policy = new exclusive_lock::AutomaticPolicy(this);
+    } else {
+      exclusive_lock_policy = new exclusive_lock::StandardPolicy(this);
+    }
     journal_policy = new journal::StandardPolicy(this);
   }
 
index 7b118bf9e758b5a61a1e27bed5e25df4c4a85f7f..deacc55371fabc161b38752a5b2efcb333d206f6 100644 (file)
@@ -697,10 +697,8 @@ bool ImageWatcher<I>::handle_payload(const RequestLockPayload &payload,
     int r = 0;
     bool accept_request = m_image_ctx.exclusive_lock->accept_requests(&r);
 
-    // need to send something back so the client can detect a missing leader
-    ::encode(ResponseMessage(r), ack_ctx->out);
-
     if (accept_request) {
+      assert(r == 0);
       Mutex::Locker owner_client_id_locker(m_owner_client_id_lock);
       if (!m_owner_client_id.is_valid()) {
         return true;
@@ -708,8 +706,10 @@ bool ImageWatcher<I>::handle_payload(const RequestLockPayload &payload,
 
       ldout(m_image_ctx.cct, 10) << this << " queuing release of exclusive lock"
                                  << dendl;
-      m_image_ctx.get_exclusive_lock_policy()->lock_requested(payload.force);
+      r = m_image_ctx.get_exclusive_lock_policy()->lock_requested(
+        payload.force);
     }
+    ::encode(ResponseMessage(r), ack_ctx->out);
   }
   return true;
 }
index 002dfe7be01ea09f4f9a0192d156488a0d87e68b..2b5e82289aaa382ce7eb0e172bc3cb1d70e1d7f1 100644 (file)
@@ -32,6 +32,7 @@ librbd_internal_la_SOURCES = \
        librbd/Operations.cc \
        librbd/Utils.cc \
        librbd/exclusive_lock/AcquireRequest.cc \
+       librbd/exclusive_lock/AutomaticPolicy.cc \
        librbd/exclusive_lock/ReacquireRequest.cc \
        librbd/exclusive_lock/ReleaseRequest.cc \
        librbd/exclusive_lock/StandardPolicy.cc \
@@ -120,6 +121,7 @@ noinst_HEADERS += \
        librbd/Utils.h \
        librbd/WatchNotifyTypes.h \
        librbd/exclusive_lock/AcquireRequest.h \
+       librbd/exclusive_lock/AutomaticPolicy.h \
        librbd/exclusive_lock/Policy.h \
        librbd/exclusive_lock/ReacquireRequest.h \
        librbd/exclusive_lock/ReleaseRequest.h \
diff --git a/src/librbd/exclusive_lock/AutomaticPolicy.cc b/src/librbd/exclusive_lock/AutomaticPolicy.cc
new file mode 100644 (file)
index 0000000..a27cf49
--- /dev/null
@@ -0,0 +1,29 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/exclusive_lock/AutomaticPolicy.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/ExclusiveLock.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::ExclusiveLock::AutomaticPolicy "
+
+namespace librbd {
+namespace exclusive_lock {
+
+int AutomaticPolicy::lock_requested(bool force) {
+  assert(m_image_ctx->owner_lock.is_locked());
+  assert(m_image_ctx->exclusive_lock != nullptr);
+
+  ldout(m_image_ctx->cct, 20) << this << " " << __func__ << ": force=" << force
+                             << dendl;
+
+  // release the lock upon request (ignore forced requests)
+  m_image_ctx->exclusive_lock->release_lock(nullptr);
+  return 0;
+}
+
+} // namespace exclusive_lock
+} // namespace librbd
+
diff --git a/src/librbd/exclusive_lock/AutomaticPolicy.h b/src/librbd/exclusive_lock/AutomaticPolicy.h
new file mode 100644 (file)
index 0000000..6d15542
--- /dev/null
@@ -0,0 +1,34 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_EXCLUSIVE_LOCK_AUTOMATIC_POLICY_H
+#define CEPH_LIBRBD_EXCLUSIVE_LOCK_AUTOMATIC_POLICY_H
+
+#include "librbd/exclusive_lock/Policy.h"
+
+namespace librbd {
+
+struct ImageCtx;
+
+namespace exclusive_lock {
+
+class AutomaticPolicy : public Policy {
+public:
+  AutomaticPolicy(ImageCtx *image_ctx) : m_image_ctx(image_ctx) {
+  }
+
+  virtual bool may_auto_request_lock() {
+    return true;
+  }
+
+  virtual int lock_requested(bool force);
+
+private:
+  ImageCtx *m_image_ctx;
+
+};
+
+} // namespace exclusive_lock
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_EXCLUSIVE_LOCK_AUTOMATIC_POLICY_H
index 2ff8418b5ed91a69798dd4ca7f39eea473da48a4..72b2945f58e1f5b50f61393d5528120f006a1ead 100644 (file)
@@ -11,7 +11,8 @@ struct Policy {
   virtual ~Policy() {
   }
 
-  virtual void lock_requested(bool force) = 0;
+  virtual bool may_auto_request_lock() = 0;
+  virtual int lock_requested(bool force) = 0;
 };
 
 } // namespace exclusive_lock
index 22f0434d80320495344e3606d51e8aadd765925e..adeaf3f79761ea2d463f8da949514dd5f0d960f7 100644 (file)
@@ -5,15 +5,21 @@
 #include "librbd/ImageCtx.h"
 #include "librbd/ExclusiveLock.h"
 
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::ExclusiveLock::StandardPolicy "
+
 namespace librbd {
 namespace exclusive_lock {
 
-void StandardPolicy::lock_requested(bool force) {
+int StandardPolicy::lock_requested(bool force) {
   assert(m_image_ctx->owner_lock.is_locked());
   assert(m_image_ctx->exclusive_lock != nullptr);
 
-  // release the lock upon request (ignore forced requests)
-  m_image_ctx->exclusive_lock->release_lock(nullptr);
+  ldout(m_image_ctx->cct, 20) << this << " " << __func__ << ": force=" << force
+                             << dendl;
+
+  return -EROFS;
 }
 
 } // namespace exclusive_lock
index ddc78cc10594f04a0de96065178653bd8efe1f60..78a346d6656fa96934680b68efdcd07d025a9c12 100644 (file)
@@ -12,12 +12,16 @@ struct ImageCtx;
 
 namespace exclusive_lock {
 
-class StandardPolicy : public Policy{
+class StandardPolicy : public Policy {
 public:
   StandardPolicy(ImageCtx *image_ctx) : m_image_ctx(image_ctx) {
   }
 
-  virtual void lock_requested(bool force);
+  virtual bool may_auto_request_lock() {
+    return false;
+  }
+
+  virtual int lock_requested(bool force);
 
 private:
   ImageCtx *m_image_ctx;
index f02c186b19c70f753831d5e10b3714a522366fbd..6c10617f269b2d4b3116cf9f0211227131c10f41 100644 (file)
@@ -38,6 +38,8 @@
 #include "librbd/Operations.h"
 #include "librbd/parent_types.h"
 #include "librbd/Utils.h"
+#include "librbd/exclusive_lock/AutomaticPolicy.h"
+#include "librbd/exclusive_lock/StandardPolicy.h"
 #include "librbd/operation/TrimRequest.h"
 #include "include/util.h"
 
@@ -2094,6 +2096,77 @@ int mirror_image_disable_internal(ImageCtx *ictx, bool force,
     return 0;
   }
 
+  int lock_acquire(ImageCtx *ictx, rbd_lock_mode_t lock_mode)
+  {
+    if (lock_mode != RBD_LOCK_MODE_EXCLUSIVE) {
+      return -EOPNOTSUPP;
+    }
+
+    CephContext *cct = ictx->cct;
+    C_SaferCond lock_ctx;
+    {
+      RWLock::WLocker l(ictx->owner_lock);
+
+      if (ictx->exclusive_lock == nullptr) {
+       lderr(cct) << "exclusive-lock feature is not enabled" << dendl;
+       return -EINVAL;
+      }
+
+      if (ictx->get_exclusive_lock_policy()->may_auto_request_lock()) {
+       ictx->set_exclusive_lock_policy(
+         new exclusive_lock::StandardPolicy(ictx));
+      }
+
+      if (ictx->exclusive_lock->is_lock_owner()) {
+       return 0;
+      }
+
+      ictx->exclusive_lock->request_lock(&lock_ctx);
+    }
+
+    int r = lock_ctx.wait();
+    if (r < 0) {
+      lderr(cct) << "failed to request exclusive lock: " << cpp_strerror(r)
+                << dendl;
+      return r;
+    }
+
+    RWLock::RLocker l(ictx->owner_lock);
+
+    if (ictx->exclusive_lock == nullptr ||
+       !ictx->exclusive_lock->is_lock_owner()) {
+      lderr(cct) << "failed to acquire exclusive lock" << dendl;
+      return -EROFS;
+    }
+
+    return 0;
+  }
+
+  int lock_release(ImageCtx *ictx)
+  {
+    CephContext *cct = ictx->cct;
+    C_SaferCond lock_ctx;
+    {
+      RWLock::WLocker l(ictx->owner_lock);
+
+      if (ictx->exclusive_lock == nullptr ||
+         !ictx->exclusive_lock->is_lock_owner()) {
+       lderr(cct) << "not exclusive lock owner" << dendl;
+       return -EINVAL;
+      }
+
+      ictx->exclusive_lock->release_lock(&lock_ctx);
+    }
+
+    int r = lock_ctx.wait();
+    if (r < 0) {
+      lderr(cct) << "failed to release exclusive lock: " << cpp_strerror(r)
+                << dendl;
+      return r;
+    }
+    return 0;
+  }
+
   int remove(IoCtx& io_ctx, const std::string &image_name,
              const std::string &image_id, ProgressContext& prog_ctx,
              bool force)
@@ -2130,7 +2203,7 @@ int mirror_image_disable_internal(ImageCtx *ictx, bool force,
             ictx->exclusive_lock->shut_down(&ctx);
             r = ctx.wait();
             if (r < 0) {
-              lderr(cct) << "error shutting down exclusive lock"
+              lderr(cct) << "error shutting down exclusive lock"
                          << cpp_strerror(r) << dendl;
               ictx->state->close();
               return r;
index 8522ea088c718003aed1985ed41ef3c9fd38ddc0..f442462d7013f4907f9fa4afb4d6ec1a8a80295a 100644 (file)
@@ -135,6 +135,8 @@ namespace librbd {
   int get_flags(ImageCtx *ictx, uint64_t *flags);
   int set_image_notification(ImageCtx *ictx, int fd, int type);
   int is_exclusive_lock_owner(ImageCtx *ictx, bool *is_owner);
+  int lock_acquire(ImageCtx *ictx, rbd_lock_mode_t lock_mode);
+  int lock_release(ImageCtx *ictx);
 
   int remove(librados::IoCtx& io_ctx, const std::string &image_name,
              const std::string &image_id, ProgressContext& prog_ctx,
index e1114f3e2b1909d9ea70adf1df680e7c21a31316..c161c5299ec4e9c9ee059fdb3ae12bf912e241b6 100644 (file)
@@ -738,6 +738,24 @@ namespace librbd {
     return r;
   }
 
+  int Image::lock_acquire(rbd_lock_mode_t lock_mode)
+  {
+    ImageCtx *ictx = (ImageCtx *)ctx;
+    tracepoint(librbd, lock_acquire_enter, ictx, lock_mode);
+    int r = librbd::lock_acquire(ictx, lock_mode);
+    tracepoint(librbd, lock_acquire_exit, ictx, r);
+    return r;
+  }
+
+  int Image::lock_release()
+  {
+    ImageCtx *ictx = (ImageCtx *)ctx;
+    tracepoint(librbd, lock_release_enter, ictx);
+    int r = librbd::lock_release(ictx);
+    tracepoint(librbd, lock_release_exit, ictx, r);
+    return r;
+  }
+
   int Image::rebuild_object_map(ProgressContext &prog_ctx)
   {
     ImageCtx *ictx = reinterpret_cast<ImageCtx*>(ctx);
@@ -2152,6 +2170,24 @@ extern "C" int rbd_is_exclusive_lock_owner(rbd_image_t image, int *is_owner)
   return r;
 }
 
+extern "C" int rbd_lock_acquire(rbd_image_t image, rbd_lock_mode_t lock_mode)
+{
+  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+  tracepoint(librbd, lock_acquire_enter, ictx, lock_mode);
+  int r = librbd::lock_acquire(ictx, lock_mode);
+  tracepoint(librbd, lock_acquire_exit, ictx, r);
+  return r;
+}
+
+extern "C" int rbd_lock_release(rbd_image_t image)
+{
+  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+  tracepoint(librbd, lock_release_enter, ictx);
+  int r = librbd::lock_release(ictx);
+  tracepoint(librbd, lock_release_exit, ictx, r);
+  return r;
+}
+
 extern "C" int rbd_rebuild_object_map(rbd_image_t image,
                                       librbd_progress_fn_t cb, void *cbdata)
 {
index 51ecf36d49eedc6c73d8fd5c310403875088b5c3..dd95cacb4d5c3a64430dbbc6e04b95962ef02f5f 100644 (file)
@@ -4486,3 +4486,133 @@ TEST_F(TestLibRBD, DiscardAfterWrite)
   ASSERT_TRUE(read_bl.is_zero());
   read_comp->release();
 }
+
+TEST_F(TestLibRBD, ExclusiveLock)
+{
+  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+  static char buf[10];
+
+  rados_ioctx_t ioctx;
+  rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx);
+
+  std::string name = get_temp_image_name();
+  uint64_t size = 2 << 20;
+  int order = 0;
+  ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order));
+
+  rbd_image_t image1;
+  ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image1, NULL));
+
+  int lock_owner;
+  ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
+  ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
+  ASSERT_TRUE(lock_owner);
+
+  rbd_image_t image2;
+  ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image2, NULL));
+
+  ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
+  ASSERT_FALSE(lock_owner);
+
+  ASSERT_EQ(0, rbd_lock_release(image1));
+  ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
+  ASSERT_FALSE(lock_owner);
+
+  ASSERT_EQ(-EROFS, rbd_write(image1, 0, sizeof(buf), buf));
+  ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image2, 0, sizeof(buf), buf));
+
+  ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
+  ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
+  ASSERT_TRUE(lock_owner);
+
+  ASSERT_EQ(0, rbd_lock_release(image2));
+  ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
+  ASSERT_FALSE(lock_owner);
+
+  ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
+  ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
+  ASSERT_TRUE(lock_owner);
+
+  ASSERT_EQ((ssize_t)sizeof(buf), rbd_write(image1, 0, sizeof(buf), buf));
+  ASSERT_EQ(-EROFS, rbd_write(image2, 0, sizeof(buf), buf));
+
+  ASSERT_EQ(0, rbd_lock_release(image1));
+  ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
+  ASSERT_FALSE(lock_owner);
+
+  int owner_id = -1;
+  Mutex lock("ping-pong");
+  class PingPong : public Thread {
+  public:
+    explicit PingPong(int id, rbd_image_t &image, int &owner_id, Mutex &lock)
+      : m_id(id), m_image(image), m_owner_id(owner_id), m_lock(lock) {
+  };
+
+  protected:
+    void *entry() {
+      for (int i = 0; i < 10; i++) {
+       {
+         Mutex::Locker locker(m_lock);
+         if (m_owner_id == m_id) {
+           std::cout << m_id << ": releasing exclusive lock" << std::endl;
+           EXPECT_EQ(0, rbd_lock_release(m_image));
+           int lock_owner;
+           EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
+           EXPECT_FALSE(lock_owner);
+           m_owner_id = -1;
+           std::cout << m_id << ": exclusive lock released" << std::endl;
+           continue;
+         }
+       }
+
+       std::cout << m_id << ": acquiring exclusive lock" << std::endl;
+       EXPECT_EQ(0, rbd_lock_acquire(m_image, RBD_LOCK_MODE_EXCLUSIVE));
+       int lock_owner;
+       EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
+       EXPECT_TRUE(lock_owner);
+       std::cout << m_id << ": exclusive lock acquired" << std::endl;
+       {
+         Mutex::Locker locker(m_lock);
+         m_owner_id = m_id;
+       }
+       usleep(rand() % 50000);
+      }
+
+      Mutex::Locker locker(m_lock);
+      if (m_owner_id == m_id) {
+       EXPECT_EQ(0, rbd_lock_release(m_image));
+       int lock_owner;
+       EXPECT_EQ(0, rbd_is_exclusive_lock_owner(m_image, &lock_owner));
+       EXPECT_FALSE(lock_owner);
+       m_owner_id = -1;
+      }
+
+      return NULL;
+    }
+
+  private:
+    int m_id;
+    rbd_image_t &m_image;
+    int &m_owner_id;
+    Mutex &m_lock;
+  } ping(1, image1, owner_id, lock), pong(2, image2, owner_id, lock);
+
+  ping.create("ping");
+  pong.create("pong");
+  ping.join();
+  pong.join();
+
+  ASSERT_EQ(0, rbd_lock_acquire(image2, RBD_LOCK_MODE_EXCLUSIVE));
+  ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image2, &lock_owner));
+  ASSERT_TRUE(lock_owner);
+
+  ASSERT_EQ(0, rbd_close(image2));
+
+  ASSERT_EQ(0, rbd_lock_acquire(image1, RBD_LOCK_MODE_EXCLUSIVE));
+  ASSERT_EQ(0, rbd_is_exclusive_lock_owner(image1, &lock_owner));
+  ASSERT_TRUE(lock_owner);
+
+  ASSERT_EQ(0, rbd_close(image1));
+  rados_ioctx_destroy(ioctx);
+}
index be0b6715be282d30ed2eb99cafcc48519c364a9d..1d331f906a84084607f480e576a3c5626df6b521 100644 (file)
@@ -29,10 +29,15 @@ namespace {
 
 struct MirrorExclusiveLockPolicy : public librbd::exclusive_lock::Policy {
 
-  virtual void lock_requested(bool force) {
+  virtual bool may_auto_request_lock() {
+    return false;
+  }
+
+  virtual int lock_requested(bool force) {
     // TODO: interlock is being requested (e.g. local promotion)
     // Wait for demote event from peer or abort replay on forced
     // promotion.
+    return -EROFS;
   }
 
 };
index 96b478b8b07c7036940304d4e5417a535b3f013d..bdc495915b9120b37074d2cd7874b7f776b18e01 100644 (file)
@@ -1766,6 +1766,44 @@ TRACEPOINT_EVENT(librbd, is_exclusive_lock_owner_exit,
     )
 )
 
+TRACEPOINT_EVENT(librbd, lock_acquire_enter,
+    TP_ARGS(
+        void*, imagectx,
+        int, lock_mode),
+    TP_FIELDS(
+      ctf_integer_hex(void*, imagectx, imagectx)
+      ctf_integer(int, lock_mode, lock_mode)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, lock_acquire_exit,
+    TP_ARGS(
+        void*, imagectx,
+        int, retval),
+    TP_FIELDS(
+      ctf_integer_hex(void*, imagectx, imagectx)
+      ctf_integer(int, retval, retval)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, lock_release_enter,
+    TP_ARGS(
+        void*, imagectx),
+    TP_FIELDS(
+      ctf_integer_hex(void*, imagectx, imagectx)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, lock_release_exit,
+    TP_ARGS(
+        void*, imagectx,
+        int, retval),
+    TP_FIELDS(
+      ctf_integer_hex(void*, imagectx, imagectx)
+      ctf_integer(int, retval, retval)
+    )
+)
+
 TRACEPOINT_EVENT(librbd, stat_enter,
     TP_ARGS(
         void*, imagectx,