]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: API methods to directly acquire and release the exclusive lock 9592/head
authorMykola Golub <mgolub@mirantis.com>
Wed, 8 Jun 2016 12:11:02 +0000 (15:11 +0300)
committerMykola Golub <mgolub@mirantis.com>
Fri, 26 Aug 2016 12:22:05 +0000 (15:22 +0300)
Fixes: http://tracker.ceph.com/issues/15632
Signed-off-by: Mykola Golub <mgolub@mirantis.com>
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 7a6d35e420181ad6754617d694a62ce59f503d79..9af81a9ada257ac0e378c54c554128538137d1a4 100644 (file)
@@ -1210,6 +1210,7 @@ OPTION(rbd_enable_alloc_hint, OPT_BOOL, true) // when writing a object, it will
 OPTION(rbd_tracing, OPT_BOOL, false) // true if LTTng-UST tracepoints should be enabled
 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_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 700e6d6b3036c50a77e4c83084675a1495460e61..10ac86a34ca9e385117c786574eadb469e27cf17 100644 (file)
@@ -158,6 +158,11 @@ typedef struct {
   int64_t pool;
 } rbd_group_spec_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 */
@@ -325,6 +330,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 4e9b7a6fbdd1b8f40ce8b909c02c62fcf56190ad..618ce962075f2e17c22fcc5dc1fe09569d13b934 100644 (file)
@@ -236,6 +236,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 f8c08f0c908282e748445f54e2a33df715ded2d4..921c80bf2bdbae83e166076497a894970b8a85eb 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"
@@ -440,6 +441,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 {
@@ -448,8 +460,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 1eaa652c974daf5c95d3d72b18fa7061a4982c8f..c666f60448b050e1479de81d7e569f0ef2daa1a7 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 748d11a2aa53c1f5fd74a25be2001df8946042cc..5d6a2b692e76161963fc73a61ff5374f76756e49 100644 (file)
@@ -16,6 +16,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"
@@ -205,7 +206,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 58031033aa7e3f14324e291f5e5a1d37317c551c..019130c32ad465e8944ae388b3230e3cb3bc9ca8 100644 (file)
@@ -691,10 +691,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;
@@ -702,8 +700,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 271d1236bbc466b4062f2c8dc62c39b4f39240d0..8a18534e7a6a8dac21e10016aafed0faeb03befb 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 \
@@ -124,6 +125,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 8176339a2febf87d957ad317d81ed738145b9f58..0bdb94e457524bdf1939eff3a7d4f870c4f8c05c 100644 (file)
@@ -40,6 +40,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"
 
@@ -2005,6 +2007,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)
@@ -2041,7 +2114,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 d1c8834cc295c2bd65c7bec28573b84fee13b078..bd56358a84e95503fe30f3b727af25ba2ff1e128 100644 (file)
@@ -136,6 +136,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 9d91a8a56e06607cf80e323a429b9c02a5d75687..42696f60449ee29660410991e55d6daf93210d41 100644 (file)
@@ -819,6 +819,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);
@@ -2249,6 +2267,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 72b131409e216c7ac39dd8ff9eb87c11f326ce1a..4515d0ab71fb99f029a036c66b8603c10dc1788a 100644 (file)
@@ -4609,3 +4609,133 @@ TEST_F(TestLibRBD, FlushCacheWithCopyupOnExternalSnapshot) {
   ASSERT_EQ(0, read_comp->wait_for_complete());
   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 7e4f9b6c19c0417ed757143c00c5d98ef51e573f..24b98e5ddb50933afcbdceafe9366519a8838016 100644 (file)
@@ -30,10 +30,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 0726f86cff53ae7d9f4f5cd59d1c1ff4ee1c849b..ac478214f644bf4e41f4cb8ab334ca932eee95f7 100644 (file)
@@ -1832,6 +1832,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,