Skip to content

Commit

Permalink
librbd: helper methods to query and break lock
Browse files Browse the repository at this point in the history
Signed-off-by: Mykola Golub <mgolub@mirantis.com>
  • Loading branch information
Mykola Golub committed Jan 16, 2017
1 parent 91b72f0 commit f810839
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 14 deletions.
38 changes: 38 additions & 0 deletions src/librbd/ManagedLock.cc
Expand Up @@ -3,8 +3,11 @@

#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"
Expand Down Expand Up @@ -67,6 +70,14 @@ template <typename I>
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) {
Expand Down Expand Up @@ -182,6 +193,33 @@ void ManagedLock<I>::reacquire_lock(Context *on_reacquired) {
}
}

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);
Expand Down
6 changes: 6 additions & 0 deletions src/librbd/ManagedLock.h
Expand Up @@ -20,6 +20,8 @@ namespace librbd {

struct ImageCtx;

namespace managed_lock { struct Locker; }

template <typename ImageCtxT = librbd::ImageCtx>
class ManagedLock {
private:
Expand Down Expand Up @@ -50,6 +52,9 @@ class ManagedLock {
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);
Expand Down Expand Up @@ -168,6 +173,7 @@ class ManagedLock {

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);
Expand Down
42 changes: 28 additions & 14 deletions src/librbd/internal.cc
Expand Up @@ -33,8 +33,6 @@
#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"
Expand Down Expand Up @@ -1568,12 +1566,14 @@ void filter_out_mirror_watchers(ImageCtx *ictx,
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;
Expand Down Expand Up @@ -1601,12 +1601,22 @@ void filter_out_mirror_watchers(ImageCtx *ictx,
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;
Expand All @@ -1621,12 +1631,16 @@ void filter_out_mirror_watchers(ImageCtx *ictx,
}

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;
Expand Down
30 changes: 30 additions & 0 deletions src/test/librbd/test_mock_ManagedLock.cc
Expand Up @@ -5,6 +5,8 @@
#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"
Expand Down Expand Up @@ -80,6 +82,34 @@ struct ReleaseRequest<MockManagedLockImageCtx> : public BaseRequest<ReleaseReque
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

Expand Down

0 comments on commit f810839

Please sign in to comment.