From: Mykola Golub Date: Wed, 8 Jun 2016 12:11:02 +0000 (+0300) Subject: librbd: API methods to directly acquire and release the exclusive lock X-Git-Tag: v10.2.6~66^2~9 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=d4085d34f31fa9eed73d69f241184b99e5198b22;p=ceph.git librbd: API methods to directly acquire and release the exclusive lock Fixes: http://tracker.ceph.com/issues/15632 Signed-off-by: Mykola Golub (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 --- diff --git a/src/common/config_opts.h b/src/common/config_opts.h index 78e67e2c8fc..8555128105b 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -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 diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h index 418e121e5ee..c96ebfd0169 100644 --- a/src/include/rbd/librbd.h +++ b/src/include/rbd/librbd.h @@ -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, diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp index 81179b586b1..d67f23e8cbe 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -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); diff --git a/src/librbd/AioImageRequestWQ.cc b/src/librbd/AioImageRequestWQ.cc index cfb3bb97fbb..26e265ec737 100644 --- a/src/librbd/AioImageRequestWQ.cc +++ b/src/librbd/AioImageRequestWQ.cc @@ -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 >::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); } } diff --git a/src/librbd/CMakeLists.txt b/src/librbd/CMakeLists.txt index 3e9c4b5b9c1..71c8b6a94d5 100644 --- a/src/librbd/CMakeLists.txt +++ b/src/librbd/CMakeLists.txt @@ -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 diff --git a/src/librbd/ImageCtx.cc b/src/librbd/ImageCtx.cc index 863a1235e4a..97af75bb48f 100644 --- a/src/librbd/ImageCtx.cc +++ b/src/librbd/ImageCtx.cc @@ -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); } diff --git a/src/librbd/ImageWatcher.cc b/src/librbd/ImageWatcher.cc index 7b118bf9e75..deacc55371f 100644 --- a/src/librbd/ImageWatcher.cc +++ b/src/librbd/ImageWatcher.cc @@ -697,10 +697,8 @@ bool ImageWatcher::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::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; } diff --git a/src/librbd/Makefile.am b/src/librbd/Makefile.am index 002dfe7be01..2b5e82289aa 100644 --- a/src/librbd/Makefile.am +++ b/src/librbd/Makefile.am @@ -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 index 00000000000..a27cf49a72c --- /dev/null +++ b/src/librbd/exclusive_lock/AutomaticPolicy.cc @@ -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 index 00000000000..6d15542789f --- /dev/null +++ b/src/librbd/exclusive_lock/AutomaticPolicy.h @@ -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 diff --git a/src/librbd/exclusive_lock/Policy.h b/src/librbd/exclusive_lock/Policy.h index 2ff8418b5ed..72b2945f58e 100644 --- a/src/librbd/exclusive_lock/Policy.h +++ b/src/librbd/exclusive_lock/Policy.h @@ -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 diff --git a/src/librbd/exclusive_lock/StandardPolicy.cc b/src/librbd/exclusive_lock/StandardPolicy.cc index 22f0434d803..adeaf3f7976 100644 --- a/src/librbd/exclusive_lock/StandardPolicy.cc +++ b/src/librbd/exclusive_lock/StandardPolicy.cc @@ -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 diff --git a/src/librbd/exclusive_lock/StandardPolicy.h b/src/librbd/exclusive_lock/StandardPolicy.h index ddc78cc1059..78a346d6656 100644 --- a/src/librbd/exclusive_lock/StandardPolicy.h +++ b/src/librbd/exclusive_lock/StandardPolicy.h @@ -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; diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index f02c186b19c..6c10617f269 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -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; diff --git a/src/librbd/internal.h b/src/librbd/internal.h index 8522ea088c7..f442462d701 100644 --- a/src/librbd/internal.h +++ b/src/librbd/internal.h @@ -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, diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index e1114f3e2b1..c161c5299ec 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -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(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) { diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index 51ecf36d49e..dd95cacb4d5 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -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); +} diff --git a/src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.cc b/src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.cc index be0b6715be2..1d331f906a8 100644 --- a/src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.cc +++ b/src/tools/rbd_mirror/image_replayer/OpenLocalImageRequest.cc @@ -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; } }; diff --git a/src/tracing/librbd.tp b/src/tracing/librbd.tp index 96b478b8b07..bdc495915b9 100644 --- a/src/tracing/librbd.tp +++ b/src/tracing/librbd.tp @@ -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,