#include "librbd/ManagedLock.h"
#include "librbd/managed_lock/AcquireRequest.h"
+#include "librbd/managed_lock/BreakRequest.h"
+#include "librbd/managed_lock/GetLockerRequest.h"
#include "librbd/managed_lock/ReleaseRequest.h"
#include "librbd/managed_lock/ReacquireRequest.h"
+#include "librbd/managed_lock/Types.h"
#include "librbd/Watcher.h"
#include "librbd/ImageCtx.h"
#include "cls/lock/cls_lock_client.h"
bool ManagedLock<I>::is_lock_owner() const {
Mutex::Locker locker(m_lock);
+ return is_lock_owner(m_lock);
+}
+
+template <typename I>
+bool ManagedLock<I>::is_lock_owner(Mutex &lock) const {
+
+ assert(m_lock.is_locked());
+
bool lock_owner;
switch (m_state) {
}
}
+template <typename I>
+void ManagedLock<I>::get_locker(managed_lock::Locker *locker,
+ Context *on_finish) {
+ ldout(m_cct, 10) << dendl;
+
+ auto req = managed_lock::GetLockerRequest<I>::create(
+ m_ioctx, m_oid, locker, on_finish);
+ req->send();
+}
+
+template <typename I>
+void ManagedLock<I>::break_lock(const managed_lock::Locker &locker,
+ bool force_break_lock, Context *on_finish) {
+ {
+ Mutex::Locker l(m_lock);
+ if (!is_lock_owner(m_lock)) {
+ auto req = managed_lock::BreakRequest<I>::create(
+ m_ioctx, m_work_queue, m_oid, locker, m_blacklist_on_break_lock,
+ m_blacklist_expire_seconds, force_break_lock, on_finish);
+ req->send();
+ return;
+ }
+ }
+
+ on_finish->complete(-EBUSY);
+}
+
template <typename I>
void ManagedLock<I>::shutdown_handler(int r, Context *on_finish) {
on_finish->complete(r);
struct ImageCtx;
+namespace managed_lock { struct Locker; }
+
template <typename ImageCtxT = librbd::ImageCtx>
class ManagedLock {
private:
void try_acquire_lock(Context *on_acquired);
void release_lock(Context *on_released);
void reacquire_lock(Context *on_reacquired = nullptr);
+ void get_locker(managed_lock::Locker *locker, Context *on_finish);
+ void break_lock(const managed_lock::Locker &locker, bool force_break_lock,
+ Context *on_finish);
bool is_shutdown() const {
Mutex::Locker l(m_lock);
static std::string encode_lock_cookie(uint64_t watch_handle);
+ bool is_lock_owner(Mutex &lock) const;
bool is_transition_state() const;
void append_context(Action action, Context *ctx);
#include "librbd/internal.h"
#include "librbd/Journal.h"
#include "librbd/journal/Types.h"
-#include "librbd/managed_lock/BreakRequest.h"
-#include "librbd/managed_lock/GetLockerRequest.h"
#include "librbd/managed_lock/Types.h"
#include "librbd/mirror/DisableRequest.h"
#include "librbd/mirror/EnableRequest.h"
CephContext *cct = ictx->cct;
ldout(cct, 20) << __func__ << ": ictx=" << ictx << dendl;
+ if (!ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+ lderr(cct) << "exclusive-lock feature is not enabled" << dendl;
+ return -EINVAL;
+ }
+
managed_lock::Locker locker;
C_SaferCond get_owner_ctx;
- auto get_owner_req = managed_lock::GetLockerRequest<>::create(
- ictx->md_ctx, ictx->header_oid, &locker, &get_owner_ctx);
- get_owner_req->send();
-
+ ExclusiveLock<>(*ictx).get_locker(&locker, &get_owner_ctx);
int r = get_owner_ctx.wait();
if (r == -ENOENT) {
return r;
return -EOPNOTSUPP;
}
+ if (ictx->read_only) {
+ return -EROFS;
+ }
+
managed_lock::Locker locker;
C_SaferCond get_owner_ctx;
- auto get_owner_req = managed_lock::GetLockerRequest<>::create(
- ictx->md_ctx, ictx->header_oid, &locker, &get_owner_ctx);
- get_owner_req->send();
+ {
+ RWLock::RLocker l(ictx->owner_lock);
+ if (ictx->exclusive_lock == nullptr) {
+ lderr(cct) << "exclusive-lock feature is not enabled" << dendl;
+ return -EINVAL;
+ }
+
+ ictx->exclusive_lock->get_locker(&locker, &get_owner_ctx);
+ }
int r = get_owner_ctx.wait();
if (r == -ENOENT) {
return r;
}
C_SaferCond break_ctx;
- auto break_req = managed_lock::BreakRequest<>::create(
- ictx->md_ctx, ictx->op_work_queue, ictx->header_oid, locker,
- ictx->blacklist_on_break_lock, ictx->blacklist_expire_seconds, true,
- &break_ctx);
- break_req->send();
+ {
+ RWLock::RLocker l(ictx->owner_lock);
+ if (ictx->exclusive_lock == nullptr) {
+ lderr(cct) << "exclusive-lock feature is not enabled" << dendl;
+ return -EINVAL;
+ }
+
+ ictx->exclusive_lock->break_lock(locker, true, &break_ctx);
+ }
r = break_ctx.wait();
if (r == -ENOENT) {
return r;
#include "test/librbd/test_support.h"
#include "librbd/ManagedLock.h"
#include "librbd/managed_lock/AcquireRequest.h"
+#include "librbd/managed_lock/BreakRequest.h"
+#include "librbd/managed_lock/GetLockerRequest.h"
#include "librbd/managed_lock/ReacquireRequest.h"
#include "librbd/managed_lock/ReleaseRequest.h"
#include "gmock/gmock.h"
MOCK_METHOD0(send, void());
};
+template <>
+struct GetLockerRequest<MockManagedLockImageCtx> {
+ static GetLockerRequest* create(librados::IoCtx& ioctx,
+ const std::string& oid,
+ Locker *locker, Context *on_finish) {
+ assert(0 == "unexpected call");
+ }
+
+ void send() {
+ assert(0 == "unexpected call");
+ }
+};
+
+template <>
+struct BreakRequest<MockManagedLockImageCtx> {
+ static BreakRequest* create(librados::IoCtx& ioctx, ContextWQ *work_queue,
+ const std::string& oid, const Locker &locker,
+ bool blacklist_locker,
+ uint32_t blacklist_expire_seconds,
+ bool force_break_lock, Context *on_finish) {
+ assert(0 == "unexpected call");
+ }
+
+ void send() {
+ assert(0 == "unexpected call");
+ }
+};
+
} // namespace managed_lock
} // namespace librbd