ThreadPool::PointerWQ<AioImageRequest<> >::queue(req);
if (lock_required) {
- m_image_ctx.exclusive_lock->request_lock(nullptr);
+ m_image_ctx.exclusive_lock->acquire_lock(nullptr);
}
}
// we acquire the lock
RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
if (is_lock_required() && is_lock_request_needed()) {
- m_image_ctx.exclusive_lock->request_lock(nullptr);
+ m_image_ctx.exclusive_lock->acquire_lock(nullptr);
}
}
managed_lock/ReleaseRequest.cc
managed_lock/ReacquireRequest.cc
ManagedLock.cc
- exclusive_lock/AcquireRequest.cc
+ exclusive_lock/PreAcquireRequest.cc
+ exclusive_lock/PostAcquireRequest.cc
+ exclusive_lock/PreReleaseRequest.cc
exclusive_lock/AutomaticPolicy.cc
- exclusive_lock/ReacquireRequest.cc
- exclusive_lock/ReleaseRequest.cc
exclusive_lock/StandardPolicy.cc
image/CloseRequest.cc
image/CreateRequest.cc
// vim: ts=8 sw=2 smarttab
#include "librbd/ExclusiveLock.h"
-#include "cls/lock/cls_lock_client.h"
-#include "common/dout.h"
-#include "common/errno.h"
#include "librbd/AioImageRequestWQ.h"
-#include "librbd/ImageCtx.h"
-#include "librbd/ImageState.h"
#include "librbd/ImageWatcher.h"
+#include "librbd/ImageState.h"
+#include "librbd/exclusive_lock/PreAcquireRequest.h"
+#include "librbd/exclusive_lock/PostAcquireRequest.h"
+#include "librbd/exclusive_lock/PreReleaseRequest.h"
#include "librbd/Utils.h"
-#include "librbd/exclusive_lock/AcquireRequest.h"
-#include "librbd/exclusive_lock/ReacquireRequest.h"
-#include "librbd/exclusive_lock/ReleaseRequest.h"
-#include <sstream>
+#include "common/Mutex.h"
+#include "common/dout.h"
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
-#define dout_prefix *_dout << "librbd::ExclusiveLock: "
+#define dout_prefix *_dout << "librbd::ExclusiveLock: " << this << " " << __func__
namespace librbd {
using namespace exclusive_lock;
-namespace {
-
-const std::string WATCHER_LOCK_COOKIE_PREFIX = "auto";
-
-template <typename R>
-struct C_SendRequest : public Context {
- R* request;
- explicit C_SendRequest(R* request) : request(request) {
- }
- virtual void finish(int r) override {
- request->send();
- }
-};
-
-} // anonymous namespace
-
template <typename I>
-const std::string ExclusiveLock<I>::WATCHER_LOCK_TAG("internal");
+using ML = ManagedLock<I>;
template <typename I>
ExclusiveLock<I>::ExclusiveLock(I &image_ctx)
- : m_image_ctx(image_ctx),
- m_lock(util::unique_lock_name("librbd::ExclusiveLock::m_lock", this)),
- m_state(STATE_UNINITIALIZED), m_watch_handle(0) {
-}
-
-template <typename I>
-ExclusiveLock<I>::~ExclusiveLock() {
- assert(m_state == STATE_UNINITIALIZED || m_state == STATE_SHUTDOWN);
-}
-
-template <typename I>
-bool ExclusiveLock<I>::is_lock_owner() const {
- Mutex::Locker locker(m_lock);
-
- bool lock_owner;
- switch (m_state) {
- case STATE_LOCKED:
- case STATE_POST_ACQUIRING:
- case STATE_REACQUIRING:
- case STATE_PRE_RELEASING:
- case STATE_PRE_SHUTTING_DOWN:
- lock_owner = true;
- break;
- default:
- lock_owner = false;
- break;
- }
-
- ldout(m_image_ctx.cct, 20) << this << " " << __func__ << "=" << lock_owner
- << dendl;
- return lock_owner;
+ : ML<I>(image_ctx.md_ctx, image_ctx.op_work_queue, image_ctx.header_oid,
+ image_ctx.image_watcher),
+ m_image_ctx(image_ctx), m_pre_post_callback(nullptr),
+ m_shutting_down(false) {
+ ML<I>::m_state = ML<I>::STATE_UNINITIALIZED;
}
template <typename I>
bool ExclusiveLock<I>::accept_requests(int *ret_val) const {
- Mutex::Locker locker(m_lock);
+ Mutex::Locker locker(ML<I>::m_lock);
- bool accept_requests = (!is_shutdown() && m_state == STATE_LOCKED &&
+ bool accept_requests = (!ML<I>::is_shutdown_locked() &&
+ ML<I>::m_state == ML<I>::STATE_LOCKED &&
m_request_blocked_count == 0);
*ret_val = m_request_blocked_ret_val;
- ldout(m_image_ctx.cct, 20) << this << " " << __func__ << "="
- << accept_requests << dendl;
+ ldout(m_image_ctx.cct, 20) << "=" << accept_requests << dendl;
return accept_requests;
}
template <typename I>
void ExclusiveLock<I>::block_requests(int r) {
- Mutex::Locker locker(m_lock);
+ Mutex::Locker locker(ML<I>::m_lock);
+
m_request_blocked_count++;
if (m_request_blocked_ret_val == 0) {
m_request_blocked_ret_val = r;
}
- ldout(m_image_ctx.cct, 20) << this << " " << __func__ << dendl;
+ ldout(m_image_ctx.cct, 20) << dendl;
}
template <typename I>
void ExclusiveLock<I>::unblock_requests() {
- Mutex::Locker locker(m_lock);
+ Mutex::Locker locker(ML<I>::m_lock);
+
assert(m_request_blocked_count > 0);
m_request_blocked_count--;
if (m_request_blocked_count == 0) {
m_request_blocked_ret_val = 0;
}
- ldout(m_image_ctx.cct, 20) << this << " " << __func__ << dendl;
+ ldout(m_image_ctx.cct, 20) << dendl;
}
template <typename I>
void ExclusiveLock<I>::init(uint64_t features, Context *on_init) {
assert(m_image_ctx.owner_lock.is_locked());
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << dendl;
+ ldout(m_image_ctx.cct, 10) << dendl;
{
- Mutex::Locker locker(m_lock);
- assert(m_state == STATE_UNINITIALIZED);
- m_state = STATE_INITIALIZING;
+ Mutex::Locker locker(ML<I>::m_lock);
+ assert(ML<I>::m_state == ML<I>::STATE_UNINITIALIZED);
+ ML<I>::m_state = ML<I>::STATE_INITIALIZING;
}
m_image_ctx.aio_work_queue->block_writes(new C_InitComplete(this, on_init));
template <typename I>
void ExclusiveLock<I>::shut_down(Context *on_shut_down) {
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << dendl;
+ ldout(m_image_ctx.cct, 10) << dendl;
- {
- Mutex::Locker locker(m_lock);
- assert(!is_shutdown());
- execute_action(ACTION_SHUT_DOWN, on_shut_down);
- }
+ ML<I>::shut_down(on_shut_down);
// if stalled in request state machine -- abort
handle_peer_notification();
}
-template <typename I>
-void ExclusiveLock<I>::try_lock(Context *on_tried_lock) {
- int r = 0;
- {
- Mutex::Locker locker(m_lock);
- assert(m_image_ctx.owner_lock.is_locked());
- if (is_shutdown()) {
- r = -ESHUTDOWN;
- } else if (m_state != STATE_LOCKED || !m_actions_contexts.empty()) {
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << dendl;
- execute_action(ACTION_TRY_LOCK, on_tried_lock);
- return;
- }
- }
-
- on_tried_lock->complete(r);
-}
-
-template <typename I>
-void ExclusiveLock<I>::request_lock(Context *on_locked) {
- int r = 0;
- {
- Mutex::Locker locker(m_lock);
- assert(m_image_ctx.owner_lock.is_locked());
- if (is_shutdown()) {
- r = -ESHUTDOWN;
- } else if (m_state != STATE_LOCKED || !m_actions_contexts.empty()) {
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << dendl;
- execute_action(ACTION_REQUEST_LOCK, on_locked);
- return;
- }
- }
-
- if (on_locked != nullptr) {
- on_locked->complete(r);
- }
-}
-
-template <typename I>
-void ExclusiveLock<I>::release_lock(Context *on_released) {
- int r = 0;
- {
- Mutex::Locker locker(m_lock);
- assert(m_image_ctx.owner_lock.is_locked());
- if (is_shutdown()) {
- r = -ESHUTDOWN;
- } else if (m_state != STATE_UNLOCKED || !m_actions_contexts.empty()) {
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << dendl;
- execute_action(ACTION_RELEASE_LOCK, on_released);
- return;
- }
- }
-
- on_released->complete(r);
-}
-
-template <typename I>
-void ExclusiveLock<I>::reacquire_lock(Context *on_reacquired) {
- {
- Mutex::Locker locker(m_lock);
- assert(m_image_ctx.owner_lock.is_locked());
-
- if (m_state == STATE_WAITING_FOR_REGISTER) {
- // restart the acquire lock process now that watch is valid
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << ": "
- << "woke up waiting acquire" << dendl;
- Action active_action = get_active_action();
- assert(active_action == ACTION_TRY_LOCK ||
- active_action == ACTION_REQUEST_LOCK);
- execute_next_action();
- } else if (!is_shutdown() &&
- (m_state == STATE_LOCKED ||
- m_state == STATE_ACQUIRING ||
- m_state == STATE_POST_ACQUIRING ||
- m_state == STATE_WAITING_FOR_PEER)) {
- // interlock the lock operation with other image state ops
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << dendl;
- execute_action(ACTION_REACQUIRE_LOCK, on_reacquired);
- return;
- }
- }
-
- // ignore request if shutdown or not in a locked-related state
- if (on_reacquired != nullptr) {
- on_reacquired->complete(0);
- }
-}
-
template <typename I>
void ExclusiveLock<I>::handle_peer_notification() {
- Mutex::Locker locker(m_lock);
- if (m_state != STATE_WAITING_FOR_PEER) {
+ Mutex::Locker locker(ML<I>::m_lock);
+ if (ML<I>::m_state != ML<I>::STATE_WAITING_FOR_LOCK) {
return;
}
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << dendl;
- assert(get_active_action() == ACTION_REQUEST_LOCK);
- execute_next_action();
+ ldout(m_image_ctx.cct, 10) << dendl;
+ assert(ML<I>::get_active_action() == ML<I>::ACTION_ACQUIRE_LOCK);
+ ML<I>::execute_next_action();
}
template <typename I>
-std::string ExclusiveLock<I>::encode_lock_cookie() const {
- assert(m_lock.is_locked());
-
- assert(m_watch_handle != 0);
- std::ostringstream ss;
- ss << WATCHER_LOCK_COOKIE_PREFIX << " " << m_watch_handle;
- return ss.str();
-}
-
-template <typename I>
-bool ExclusiveLock<I>::decode_lock_cookie(const std::string &tag,
- uint64_t *handle) {
- std::string prefix;
- std::istringstream ss(tag);
- if (!(ss >> prefix >> *handle) || prefix != WATCHER_LOCK_COOKIE_PREFIX) {
- return false;
- }
- return true;
-}
+void ExclusiveLock<I>::handle_init_complete() {
+ ldout(m_image_ctx.cct, 10) << dendl;
-template <typename I>
-bool ExclusiveLock<I>::is_transition_state() const {
- switch (m_state) {
- case STATE_INITIALIZING:
- case STATE_ACQUIRING:
- case STATE_WAITING_FOR_PEER:
- case STATE_WAITING_FOR_REGISTER:
- case STATE_POST_ACQUIRING:
- case STATE_REACQUIRING:
- case STATE_PRE_RELEASING:
- case STATE_RELEASING:
- case STATE_PRE_SHUTTING_DOWN:
- case STATE_SHUTTING_DOWN:
- return true;
- case STATE_UNINITIALIZED:
- case STATE_UNLOCKED:
- case STATE_LOCKED:
- case STATE_SHUTDOWN:
- break;
- }
- return false;
+ Mutex::Locker locker(ML<I>::m_lock);
+ ML<I>::m_state = ML<I>::STATE_UNLOCKED;
}
template <typename I>
-void ExclusiveLock<I>::append_context(Action action, Context *ctx) {
- assert(m_lock.is_locked());
-
- for (auto &action_ctxs : m_actions_contexts) {
- if (action == action_ctxs.first) {
- if (ctx != nullptr) {
- action_ctxs.second.push_back(ctx);
- }
- return;
- }
- }
-
- Contexts contexts;
- if (ctx != nullptr) {
- contexts.push_back(ctx);
- }
- m_actions_contexts.push_back({action, std::move(contexts)});
-}
+void ExclusiveLock<I>::shutdown_handler(int r, Context *on_finish) {
+ ldout(m_image_ctx.cct, 10) << dendl;
-template <typename I>
-void ExclusiveLock<I>::execute_action(Action action, Context *ctx) {
- assert(m_lock.is_locked());
-
- append_context(action, ctx);
- if (!is_transition_state()) {
- execute_next_action();
+ {
+ RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
+ m_image_ctx.aio_work_queue->clear_require_lock_on_read();
+ m_image_ctx.exclusive_lock = nullptr;
}
-}
-template <typename I>
-void ExclusiveLock<I>::execute_next_action() {
- assert(m_lock.is_locked());
- assert(!m_actions_contexts.empty());
- switch (get_active_action()) {
- case ACTION_TRY_LOCK:
- case ACTION_REQUEST_LOCK:
- send_acquire_lock();
- break;
- case ACTION_REACQUIRE_LOCK:
- send_reacquire_lock();
- break;
- case ACTION_RELEASE_LOCK:
- send_release_lock();
- break;
- case ACTION_SHUT_DOWN:
- send_shutdown();
- break;
- default:
- assert(false);
- break;
- }
+ m_image_ctx.aio_work_queue->unblock_writes();
+ m_image_ctx.image_watcher->flush(on_finish);
}
template <typename I>
-typename ExclusiveLock<I>::Action ExclusiveLock<I>::get_active_action() const {
- assert(m_lock.is_locked());
- assert(!m_actions_contexts.empty());
- return m_actions_contexts.front().first;
+void ExclusiveLock<I>::pre_acquire_lock_handler(Context *on_finish) {
+ PreAcquireRequest<I> *req = PreAcquireRequest<I>::create(m_image_ctx,
+ on_finish);
+ m_image_ctx.op_work_queue->queue(new FunctionContext([req](int r) {
+ req->send();
+ }));
}
template <typename I>
-void ExclusiveLock<I>::complete_active_action(State next_state, int r) {
- assert(m_lock.is_locked());
- assert(!m_actions_contexts.empty());
-
- ActionContexts action_contexts(std::move(m_actions_contexts.front()));
- m_actions_contexts.pop_front();
- m_state = next_state;
-
- m_lock.Unlock();
- for (auto ctx : action_contexts.second) {
- ctx->complete(r);
- }
- m_lock.Lock();
+void ExclusiveLock<I>::post_acquire_lock_handler(int r, Context *on_finish) {
+ ldout(m_image_ctx.cct, 10) << ": r=" << r << dendl;
- if (!is_transition_state() && !m_actions_contexts.empty()) {
- execute_next_action();
- }
-}
-template <typename I>
-bool ExclusiveLock<I>::is_shutdown() const {
- assert(m_lock.is_locked());
+ if (r < 0) {
+ ML<I>::m_lock.Lock();
+ assert(ML<I>::m_state == ML<I>::STATE_ACQUIRING);
- return ((m_state == STATE_SHUTDOWN) ||
- (!m_actions_contexts.empty() &&
- m_actions_contexts.back().first == ACTION_SHUT_DOWN));
-}
+ // PostAcquire state machine will not run, so we need complete prepare
+ m_image_ctx.state->handle_prepare_lock_complete();
-template <typename I>
-void ExclusiveLock<I>::handle_init_complete() {
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << dendl;
+ typename ML<I>::Action action = ML<I>::get_active_action();
+ if (action == ML<I>::ACTION_ACQUIRE_LOCK && r < 0 && r != -EBLACKLISTED) {
+ ML<I>::m_state = ML<I>::STATE_WAITING_FOR_LOCK;
+ ML<I>::m_lock.Unlock();
- Mutex::Locker locker(m_lock);
- m_state = STATE_UNLOCKED;
-}
+ // request the lock from a peer
+ m_image_ctx.image_watcher->notify_request_lock();
-template <typename I>
-void ExclusiveLock<I>::send_acquire_lock() {
- assert(m_lock.is_locked());
- if (m_state == STATE_LOCKED) {
- complete_active_action(STATE_LOCKED, 0);
- return;
- }
+ return;
+ }
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << this << " " << __func__ << dendl;
- m_state = STATE_ACQUIRING;
+ ML<I>::m_lock.Unlock();
+ if (r == -EAGAIN) {
+ r = 0;
+ }
- m_watch_handle = m_image_ctx.image_watcher->get_watch_handle();
- if (m_watch_handle == 0) {
- lderr(cct) << "image watcher not registered - delaying request" << dendl;
- m_state = STATE_WAITING_FOR_REGISTER;
+ on_finish->complete(r);
return;
}
- m_cookie = encode_lock_cookie();
+ Mutex::Locker locker(ML<I>::m_lock);
+ m_pre_post_callback = on_finish;
+ using EL = ExclusiveLock<I>;
+ PostAcquireRequest<I> *req = PostAcquireRequest<I>::create(m_image_ctx,
+ util::create_context_callback<EL, &EL::handle_post_acquiring_lock>(this),
+ util::create_context_callback<EL, &EL::handle_post_acquired_lock>(this));
- using el = ExclusiveLock<I>;
- AcquireRequest<I>* req = AcquireRequest<I>::create(
- m_image_ctx, m_cookie,
- util::create_context_callback<el, &el::handle_acquiring_lock>(this),
- util::create_context_callback<el, &el::handle_acquire_lock>(this));
- m_image_ctx.op_work_queue->queue(new C_SendRequest<AcquireRequest<I> >(req),
- 0);
+ m_image_ctx.op_work_queue->queue(new FunctionContext([req](int r) {
+ req->send();
+ }));
}
template <typename I>
-void ExclusiveLock<I>::handle_acquiring_lock(int r) {
- Mutex::Locker locker(m_lock);
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << dendl;
+void ExclusiveLock<I>::handle_post_acquiring_lock(int r) {
+ ldout(m_image_ctx.cct, 10) << dendl;
+
+ Mutex::Locker locker(ML<I>::m_lock);
assert(r == 0);
- assert(m_state == STATE_ACQUIRING);
+ assert(ML<I>::m_state == ML<I>::STATE_ACQUIRING);
// lock is owned at this point
- m_state = STATE_POST_ACQUIRING;
+ ML<I>::m_state = ML<I>::STATE_POST_ACQUIRING;
}
template <typename I>
-void ExclusiveLock<I>::handle_acquire_lock(int r) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
-
- if (r == -EBUSY || r == -EAGAIN) {
- ldout(cct, 5) << "unable to acquire exclusive lock" << dendl;
- } else if (r < 0) {
- lderr(cct) << "failed to acquire exclusive lock:" << cpp_strerror(r)
- << dendl;
- } else {
- ldout(cct, 5) << "successfully acquired exclusive lock" << dendl;
- }
+void ExclusiveLock<I>::handle_post_acquired_lock(int r) {
+ ldout(m_image_ctx.cct, 10) << ": r=" << r << dendl;
+ Context *on_finish = nullptr;
{
- m_lock.Lock();
- assert(m_state == STATE_ACQUIRING ||
- m_state == STATE_POST_ACQUIRING);
+ Mutex::Locker locker(ML<I>::m_lock);
+ assert(ML<I>::m_state == ML<I>::STATE_ACQUIRING ||
+ ML<I>::m_state == ML<I>::STATE_POST_ACQUIRING);
- Action action = get_active_action();
- assert(action == ACTION_TRY_LOCK || action == ACTION_REQUEST_LOCK);
- if (action == ACTION_REQUEST_LOCK && r < 0 && r != -EBLACKLISTED &&
- r != -EPERM) {
- m_state = STATE_WAITING_FOR_PEER;
- m_lock.Unlock();
-
- // request the lock from a peer
- m_image_ctx.image_watcher->notify_request_lock();
- return;
- }
- m_lock.Unlock();
+ assert (m_pre_post_callback != nullptr);
+ std::swap(m_pre_post_callback, on_finish);
}
- State next_state = (r < 0 ? STATE_UNLOCKED : STATE_LOCKED);
- if (r == -EAGAIN) {
- r = 0;
- }
-
- if (next_state == STATE_LOCKED) {
+ if (r >= 0) {
m_image_ctx.image_watcher->notify_acquired_lock();
m_image_ctx.aio_work_queue->clear_require_lock_on_read();
m_image_ctx.aio_work_queue->unblock_writes();
}
- Mutex::Locker locker(m_lock);
- complete_active_action(next_state, r);
+ on_finish->complete(r);
}
template <typename I>
-void ExclusiveLock<I>::send_reacquire_lock() {
- assert(m_lock.is_locked());
-
- CephContext *cct = m_image_ctx.cct;
- if (m_state != STATE_LOCKED) {
- complete_active_action(m_state, 0);
- return;
- }
-
- m_watch_handle = m_image_ctx.image_watcher->get_watch_handle();
- if (m_watch_handle == 0) {
- // watch (re)failed while recovering
- lderr(cct) << this << " " << __func__ << ": "
- << "aborting reacquire due to invalid watch handle" << dendl;
- complete_active_action(STATE_LOCKED, 0);
- return;
- }
+void ExclusiveLock<I>::pre_release_lock_handler(bool shutting_down,
+ Context *on_finish) {
+ ldout(m_image_ctx.cct, 10) << dendl;
+ Mutex::Locker locker(ML<I>::m_lock);
- m_new_cookie = encode_lock_cookie();
- if (m_cookie == m_new_cookie) {
- ldout(cct, 10) << this << " " << __func__ << ": "
- << "skipping reacquire since cookie still valid" << dendl;
- complete_active_action(STATE_LOCKED, 0);
- return;
- }
+ m_shutting_down = shutting_down;
- ldout(cct, 10) << this << " " << __func__ << dendl;
- m_state = STATE_REACQUIRING;
+ using EL = ExclusiveLock<I>;
+ PreReleaseRequest<I> *req = PreReleaseRequest<I>::create(m_image_ctx,
+ util::create_context_callback<EL, &EL::handle_pre_releasing_lock>(this),
+ on_finish, shutting_down);
- using el = ExclusiveLock<I>;
- ReacquireRequest<I>* req = ReacquireRequest<I>::create(
- m_image_ctx, m_cookie, m_new_cookie,
- util::create_context_callback<el, &el::handle_reacquire_lock>(this));
- req->send();
+ m_image_ctx.op_work_queue->queue(new FunctionContext([req](int r) {
+ req->send();
+ }));
}
template <typename I>
-void ExclusiveLock<I>::handle_reacquire_lock(int r) {
- Mutex::Locker locker(m_lock);
+void ExclusiveLock<I>::handle_pre_releasing_lock(int r) {
+ ldout(m_image_ctx.cct, 10) << dendl;
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
+ Mutex::Locker locker(ML<I>::m_lock);
- assert(m_state == STATE_REACQUIRING);
- if (r < 0) {
- if (r == -EOPNOTSUPP) {
- ldout(cct, 10) << this << " " << __func__ << ": "
- << "updating lock is not supported" << dendl;
- } else {
- lderr(cct) << this << " " << __func__ << ": "
- << "failed to update lock cookie: " << cpp_strerror(r)
- << dendl;
- }
+ assert(r == 0);
+ if (!m_shutting_down) {
+ assert(ML<I>::m_state == ML<I>::STATE_PRE_RELEASING);
- if (!is_shutdown()) {
- // queue a release and re-acquire of the lock since cookie cannot
- // be updated on older OSDs
- execute_action(ACTION_RELEASE_LOCK, nullptr);
-
- assert(!m_actions_contexts.empty());
- ActionContexts &action_contexts(m_actions_contexts.front());
-
- // reacquire completes when the request lock completes
- Contexts contexts;
- std::swap(contexts, action_contexts.second);
- if (contexts.empty()) {
- execute_action(ACTION_REQUEST_LOCK, nullptr);
- } else {
- for (auto ctx : contexts) {
- ctx = new FunctionContext([ctx, r](int acquire_ret_val) {
- if (acquire_ret_val >= 0) {
- acquire_ret_val = r;
- }
- ctx->complete(acquire_ret_val);
- });
- execute_action(ACTION_REQUEST_LOCK, ctx);
- }
- }
- }
+ // all IO and ops should be blocked/canceled by this point
+ ML<I>::m_state = ML<I>::STATE_RELEASING;
} else {
- m_cookie = m_new_cookie;
- }
+ assert(ML<I>::m_state == ML<I>::STATE_PRE_SHUTTING_DOWN);
- complete_active_action(STATE_LOCKED, 0);
-}
-
-template <typename I>
-void ExclusiveLock<I>::send_release_lock() {
- assert(m_lock.is_locked());
- if (m_state == STATE_UNLOCKED) {
- complete_active_action(STATE_UNLOCKED, 0);
- return;
+ // all IO and ops should be blocked/canceled by this point
+ ML<I>::m_state = ML<I>::STATE_SHUTTING_DOWN;
}
-
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << dendl;
- m_state = STATE_PRE_RELEASING;
-
- using el = ExclusiveLock<I>;
- ReleaseRequest<I>* req = ReleaseRequest<I>::create(
- m_image_ctx, m_cookie,
- util::create_context_callback<el, &el::handle_releasing_lock>(this),
- util::create_context_callback<el, &el::handle_release_lock>(this),
- false);
- m_image_ctx.op_work_queue->queue(new C_SendRequest<ReleaseRequest<I> >(req),
- 0);
-}
-
-template <typename I>
-void ExclusiveLock<I>::handle_releasing_lock(int r) {
- Mutex::Locker locker(m_lock);
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << dendl;
-
- assert(r == 0);
- assert(m_state == STATE_PRE_RELEASING);
-
- // all IO and ops should be blocked/canceled by this point
- m_state = STATE_RELEASING;
}
template <typename I>
-void ExclusiveLock<I>::handle_release_lock(int r) {
- bool lock_request_needed = false;
- {
- Mutex::Locker locker(m_lock);
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << ": r=" << r
- << dendl;
+void ExclusiveLock<I>::post_release_lock_handler(bool shutting_down, int r,
+ Context *on_finish) {
+ ldout(m_image_ctx.cct, 10) << ": r=" << r << " shutting_down="
+ << shutting_down << dendl;
+ if (!shutting_down) {
+ {
+ Mutex::Locker locker(ML<I>::m_lock);
+ assert(ML<I>::m_state == ML<I>::STATE_PRE_RELEASING ||
+ ML<I>::m_state == ML<I>::STATE_RELEASING);
+ }
- assert(m_state == STATE_PRE_RELEASING ||
- m_state == STATE_RELEASING);
if (r >= 0) {
- m_lock.Unlock();
m_image_ctx.image_watcher->notify_released_lock();
- lock_request_needed = m_image_ctx.aio_work_queue->is_lock_request_needed();
- m_lock.Lock();
-
- m_cookie = "";
- m_watch_handle = 0;
+ if (m_image_ctx.aio_work_queue->is_lock_request_needed()) {
+ // if we have blocked IO -- re-request the lock
+ RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
+ ML<I>::acquire_lock(nullptr);
+ }
}
- complete_active_action(r < 0 ? STATE_LOCKED : STATE_UNLOCKED, r);
- }
-
- if (r >= 0 && lock_request_needed) {
- // if we have blocked IO -- re-request the lock
- RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
- request_lock(nullptr);
- }
-}
-
-template <typename I>
-void ExclusiveLock<I>::send_shutdown() {
- assert(m_lock.is_locked());
- if (m_state == STATE_UNLOCKED) {
- m_state = STATE_SHUTTING_DOWN;
- m_image_ctx.op_work_queue->queue(util::create_context_callback<
- ExclusiveLock<I>, &ExclusiveLock<I>::handle_shutdown>(this), 0);
- return;
- }
-
- ldout(m_image_ctx.cct, 10) << this << " " << __func__ << dendl;
- assert(m_state == STATE_LOCKED);
- m_state = STATE_PRE_SHUTTING_DOWN;
-
- m_lock.Unlock();
- m_image_ctx.op_work_queue->queue(new C_ShutDownRelease(this), 0);
- m_lock.Lock();
-}
-
-template <typename I>
-void ExclusiveLock<I>::send_shutdown_release() {
- std::string cookie;
- {
- Mutex::Locker locker(m_lock);
- cookie = m_cookie;
- }
-
- using el = ExclusiveLock<I>;
- ReleaseRequest<I>* req = ReleaseRequest<I>::create(
- m_image_ctx, cookie,
- util::create_context_callback<el, &el::handle_shutdown_releasing>(this),
- util::create_context_callback<el, &el::handle_shutdown_released>(this),
- true);
- req->send();
-}
-
-template <typename I>
-void ExclusiveLock<I>::handle_shutdown_releasing(int r) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
-
- assert(r == 0);
- assert(m_state == STATE_PRE_SHUTTING_DOWN);
-
- // all IO and ops should be blocked/canceled by this point
- m_state = STATE_SHUTTING_DOWN;
-}
-
-template <typename I>
-void ExclusiveLock<I>::handle_shutdown_released(int r) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
-
- {
- RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
- m_image_ctx.aio_work_queue->clear_require_lock_on_read();
- m_image_ctx.exclusive_lock = nullptr;
- }
-
- if (r < 0) {
- lderr(cct) << "failed to shut down exclusive lock: " << cpp_strerror(r)
- << dendl;
} else {
- m_image_ctx.aio_work_queue->unblock_writes();
- }
-
- m_image_ctx.image_watcher->notify_released_lock();
- complete_shutdown(r);
-}
-
-template <typename I>
-void ExclusiveLock<I>::handle_shutdown(int r) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
-
- {
- RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
- m_image_ctx.aio_work_queue->clear_require_lock_on_read();
- m_image_ctx.exclusive_lock = nullptr;
- }
-
- m_image_ctx.aio_work_queue->unblock_writes();
- m_image_ctx.image_watcher->flush(util::create_context_callback<
- ExclusiveLock<I>, &ExclusiveLock<I>::complete_shutdown>(this));
-}
+ {
+ RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
+ m_image_ctx.aio_work_queue->clear_require_lock_on_read();
+ m_image_ctx.exclusive_lock = nullptr;
+ }
-template <typename I>
-void ExclusiveLock<I>::complete_shutdown(int r) {
- ActionContexts action_contexts;
- {
- Mutex::Locker locker(m_lock);
- assert(m_lock.is_locked());
- assert(m_actions_contexts.size() == 1);
+ if (r >= 0) {
+ m_image_ctx.aio_work_queue->unblock_writes();
+ }
- action_contexts = std::move(m_actions_contexts.front());
- m_actions_contexts.pop_front();
- m_state = STATE_SHUTDOWN;
+ m_image_ctx.image_watcher->notify_released_lock();
}
- // expect to be destroyed after firing callback
- for (auto ctx : action_contexts.second) {
- ctx->complete(r);
- }
+ on_finish->complete(r);
}
} // namespace librbd
#ifndef CEPH_LIBRBD_EXCLUSIVE_LOCK_H
#define CEPH_LIBRBD_EXCLUSIVE_LOCK_H
-#include "include/int_types.h"
-#include "include/Context.h"
-#include "include/rados/librados.hpp"
-#include "common/Mutex.h"
-#include <list>
-#include <string>
-#include <utility>
+#include "librbd/ManagedLock.h"
+#include "librbd/ImageCtx.h"
namespace librbd {
-class ImageCtx;
-
template <typename ImageCtxT = ImageCtx>
-class ExclusiveLock {
+class ExclusiveLock : public ManagedLock<ImageCtxT> {
public:
- static const std::string WATCHER_LOCK_TAG;
-
static ExclusiveLock *create(ImageCtxT &image_ctx) {
return new ExclusiveLock<ImageCtxT>(image_ctx);
}
ExclusiveLock(ImageCtxT &image_ctx);
- ~ExclusiveLock();
- bool is_lock_owner() const;
bool accept_requests(int *ret_val) const;
void block_requests(int r);
void init(uint64_t features, Context *on_init);
void shut_down(Context *on_shutdown);
- void try_lock(Context *on_tried_lock);
- void request_lock(Context *on_locked);
- void release_lock(Context *on_released);
-
- void reacquire_lock(Context *on_reacquired = nullptr);
-
void handle_peer_notification();
- static bool decode_lock_cookie(const std::string &cookie, uint64_t *handle);
+protected:
+ virtual void shutdown_handler(int r, Context *on_finish);
+ virtual void pre_acquire_lock_handler(Context *on_finish);
+ virtual void post_acquire_lock_handler(int r, Context *on_finish);
+ virtual void pre_release_lock_handler(bool shutting_down,
+ Context *on_finish);
+ virtual void post_release_lock_handler(bool shutting_down, int r,
+ Context *on_finish);
private:
*
* @endverbatim
*/
- enum State {
- STATE_UNINITIALIZED,
- STATE_UNLOCKED,
- STATE_LOCKED,
- STATE_INITIALIZING,
- STATE_ACQUIRING,
- STATE_POST_ACQUIRING,
- STATE_WAITING_FOR_PEER,
- STATE_WAITING_FOR_REGISTER,
- STATE_REACQUIRING,
- STATE_PRE_RELEASING,
- STATE_RELEASING,
- STATE_PRE_SHUTTING_DOWN,
- STATE_SHUTTING_DOWN,
- STATE_SHUTDOWN
- };
-
- enum Action {
- ACTION_TRY_LOCK,
- ACTION_REQUEST_LOCK,
- ACTION_REACQUIRE_LOCK,
- ACTION_RELEASE_LOCK,
- ACTION_SHUT_DOWN
- };
-
- typedef std::list<Context *> Contexts;
- typedef std::pair<Action, Contexts> ActionContexts;
- typedef std::list<ActionContexts> ActionsContexts;
struct C_InitComplete : public Context {
ExclusiveLock *exclusive_lock;
}
};
- struct C_ShutDownRelease : public Context {
- ExclusiveLock *exclusive_lock;
- C_ShutDownRelease(ExclusiveLock *exclusive_lock)
- : exclusive_lock(exclusive_lock) {
- }
- virtual void finish(int r) override {
- exclusive_lock->send_shutdown_release();
- }
- };
-
- ImageCtxT &m_image_ctx;
-
- mutable Mutex m_lock;
- State m_state;
- std::string m_cookie;
- std::string m_new_cookie;
- uint64_t m_watch_handle;
-
- ActionsContexts m_actions_contexts;
+ ImageCtxT& m_image_ctx;
+ Context *m_pre_post_callback;
+ bool m_shutting_down;
uint32_t m_request_blocked_count = 0;
int m_request_blocked_ret_val = 0;
- std::string encode_lock_cookie() const;
-
- bool is_transition_state() const;
-
- void append_context(Action action, Context *ctx);
- void execute_action(Action action, Context *ctx);
- void execute_next_action();
-
- Action get_active_action() const;
- void complete_active_action(State next_state, int r);
-
- bool is_shutdown() const;
-
void handle_init_complete();
-
- void send_acquire_lock();
- void handle_acquiring_lock(int r);
- void handle_acquire_lock(int r);
-
- void send_reacquire_lock();
- void handle_reacquire_lock(int r);
-
- void send_release_lock();
- void handle_releasing_lock(int r);
- void handle_release_lock(int r);
-
- void send_shutdown();
- void send_shutdown_release();
- void handle_shutdown_releasing(int r);
- void handle_shutdown_released(int r);
- void handle_shutdown(int r);
- void complete_shutdown(int r);
+ void handle_post_acquiring_lock(int r);
+ void handle_post_acquired_lock(int r);
+ void handle_pre_releasing_lock(int r);
};
} // namespace librbd
-extern template class librbd::ExclusiveLock<librbd::ImageCtx>;
-
#endif // CEPH_LIBRBD_EXCLUSIVE_LOCK_H
// current lock owner doesn't support op -- try to perform
// the action locally
request_lock = false;
- image_ctx.exclusive_lock->request_lock(ctx);
+ image_ctx.exclusive_lock->acquire_lock(ctx);
} else {
- image_ctx.exclusive_lock->try_lock(ctx);
+ image_ctx.exclusive_lock->try_acquire_lock(ctx);
}
owner_lock.put_read();
}
!m_image_ctx.exclusive_lock->is_lock_owner()) {
C_SaferCond lock_ctx;
- m_image_ctx.exclusive_lock->request_lock(&lock_ctx);
+ m_image_ctx.exclusive_lock->acquire_lock(&lock_ctx);
r = lock_ctx.wait();
if (r < 0) {
return r;
!m_image_ctx.exclusive_lock->is_lock_owner()) {
C_SaferCond lock_ctx;
- m_image_ctx.exclusive_lock->request_lock(&lock_ctx);
+ m_image_ctx.exclusive_lock->acquire_lock(&lock_ctx);
r = lock_ctx.wait();
if (r < 0) {
return r;
!m_image_ctx.exclusive_lock->is_lock_owner()) {
C_SaferCond lock_ctx;
- m_image_ctx.exclusive_lock->request_lock(&lock_ctx);
+ m_image_ctx.exclusive_lock->acquire_lock(&lock_ctx);
r = lock_ctx.wait();
if (r < 0) {
return r;
if (m_image_ctx.exclusive_lock != nullptr &&
(!m_image_ctx.exclusive_lock->is_lock_owner() ||
!m_image_ctx.exclusive_lock->accept_requests(&r))) {
- m_image_ctx.exclusive_lock->try_lock(&ctx);
+ m_image_ctx.exclusive_lock->try_acquire_lock(&ctx);
trying_lock = true;
}
}
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "librbd/exclusive_lock/AcquireRequest.h"
-#include "cls/lock/cls_lock_client.h"
-#include "cls/lock/cls_lock_types.h"
-#include "common/dout.h"
-#include "common/errno.h"
-#include "common/WorkQueue.h"
-#include "include/stringify.h"
-#include "librbd/ExclusiveLock.h"
-#include "librbd/ImageCtx.h"
-#include "librbd/ImageState.h"
-#include "librbd/ImageWatcher.h"
-#include "librbd/Journal.h"
-#include "librbd/ObjectMap.h"
-#include "librbd/Utils.h"
-#include "librbd/image/RefreshRequest.h"
-#include "librbd/journal/Policy.h"
-
-#define dout_subsys ceph_subsys_rbd
-#undef dout_prefix
-#define dout_prefix *_dout << "librbd::exclusive_lock::AcquireRequest: "
-
-namespace librbd {
-namespace exclusive_lock {
-
-using util::create_async_context_callback;
-using util::create_context_callback;
-using util::create_rados_ack_callback;
-using util::create_rados_safe_callback;
-
-namespace {
-
-template <typename I>
-struct C_BlacklistClient : public Context {
- I &image_ctx;
- std::string locker_address;
- Context *on_finish;
-
- C_BlacklistClient(I &image_ctx, const std::string &locker_address,
- Context *on_finish)
- : image_ctx(image_ctx), locker_address(locker_address),
- on_finish(on_finish) {
- }
-
- virtual void finish(int r) override {
- librados::Rados rados(image_ctx.md_ctx);
- r = rados.blacklist_add(locker_address,
- image_ctx.blacklist_expire_seconds);
- on_finish->complete(r);
- }
-};
-
-} // anonymous namespace
-
-template <typename I>
-AcquireRequest<I>* AcquireRequest<I>::create(I &image_ctx,
- const std::string &cookie,
- Context *on_acquire,
- Context *on_finish) {
- return new AcquireRequest(image_ctx, cookie, on_acquire, on_finish);
-}
-
-template <typename I>
-AcquireRequest<I>::AcquireRequest(I &image_ctx, const std::string &cookie,
- Context *on_acquire, Context *on_finish)
- : m_image_ctx(image_ctx), m_cookie(cookie), m_on_acquire(on_acquire),
- m_on_finish(create_async_context_callback(image_ctx, on_finish)),
- m_object_map(nullptr), m_journal(nullptr), m_error_result(0) {
-}
-
-template <typename I>
-AcquireRequest<I>::~AcquireRequest() {
- if (!m_prepare_lock_completed) {
- m_image_ctx.state->handle_prepare_lock_complete();
- }
- delete m_on_acquire;
-}
-
-template <typename I>
-void AcquireRequest<I>::send() {
- send_prepare_lock();
-}
-
-template <typename I>
-void AcquireRequest<I>::send_prepare_lock() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- // acquire the lock if the image is not busy performing other actions
- Context *ctx = create_context_callback<
- AcquireRequest<I>, &AcquireRequest<I>::handle_prepare_lock>(this);
- m_image_ctx.state->prepare_lock(ctx);
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_prepare_lock(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- send_flush_notifies();
- return nullptr;
-}
-
-template <typename I>
-void AcquireRequest<I>::send_flush_notifies() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- using klass = AcquireRequest<I>;
- Context *ctx = create_context_callback<klass, &klass::handle_flush_notifies>(
- this);
- m_image_ctx.image_watcher->flush(ctx);
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_flush_notifies(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- assert(*ret_val == 0);
- send_lock();
- return nullptr;
-}
-
-template <typename I>
-void AcquireRequest<I>::send_lock() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- librados::ObjectWriteOperation op;
- rados::cls::lock::lock(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, m_cookie,
- ExclusiveLock<>::WATCHER_LOCK_TAG, "", utime_t(), 0);
-
- using klass = AcquireRequest<I>;
- librados::AioCompletion *rados_completion =
- create_rados_safe_callback<klass, &klass::handle_lock>(this);
- int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
- rados_completion, &op);
- assert(r == 0);
- rados_completion->release();
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_lock(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val == 0) {
- return send_refresh();
- } else if (*ret_val != -EBUSY) {
- lderr(cct) << "failed to lock: " << cpp_strerror(*ret_val) << dendl;
- return m_on_finish;
- }
-
- send_get_lockers();
- return nullptr;
-}
-
-template <typename I>
-Context *AcquireRequest<I>::send_refresh() {
- if (!m_image_ctx.state->is_refresh_required()) {
- return send_open_object_map();
- }
-
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- using klass = AcquireRequest<I>;
- Context *ctx = create_async_context_callback(
- m_image_ctx, create_context_callback<klass, &klass::handle_refresh>(this));
-
- // ImageState is blocked waiting for lock to complete -- safe to directly
- // refresh
- image::RefreshRequest<I> *req = image::RefreshRequest<I>::create(
- m_image_ctx, true, ctx);
- req->send();
- return nullptr;
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_refresh(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val == -ERESTART) {
- // next issued IO or op will (re)-refresh the image and shut down lock
- ldout(cct, 5) << ": exclusive lock dynamically disabled" << dendl;
- *ret_val = 0;
- } else if (*ret_val < 0) {
- lderr(cct) << "failed to refresh image: " << cpp_strerror(*ret_val)
- << dendl;
- m_error_result = *ret_val;
- send_unlock();
- return nullptr;
- }
-
- return send_open_object_map();
-}
-
-template <typename I>
-Context *AcquireRequest<I>::send_open_journal() {
- // alert caller that we now own the exclusive lock
- m_on_acquire->complete(0);
- m_on_acquire = nullptr;
-
- bool journal_enabled;
- {
- RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
- journal_enabled = (m_image_ctx.test_features(RBD_FEATURE_JOURNALING,
- m_image_ctx.snap_lock) &&
- !m_image_ctx.get_journal_policy()->journal_disabled());
- }
- if (!journal_enabled) {
- apply();
- return m_on_finish;
- }
-
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- using klass = AcquireRequest<I>;
- Context *ctx = create_context_callback<klass, &klass::handle_open_journal>(
- this);
- m_journal = m_image_ctx.create_journal();
-
- // journal playback requires object map (if enabled) and itself
- apply();
-
- m_journal->open(ctx);
- return nullptr;
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_open_journal(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val < 0) {
- lderr(cct) << "failed to open journal: " << cpp_strerror(*ret_val) << dendl;
- m_error_result = *ret_val;
- send_close_journal();
- return nullptr;
- }
-
- send_allocate_journal_tag();
- return nullptr;
-}
-
-template <typename I>
-void AcquireRequest<I>::send_allocate_journal_tag() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
- using klass = AcquireRequest<I>;
- Context *ctx = create_context_callback<
- klass, &klass::handle_allocate_journal_tag>(this);
- m_image_ctx.get_journal_policy()->allocate_tag_on_lock(ctx);
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_allocate_journal_tag(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val < 0) {
- lderr(cct) << "failed to allocate journal tag: " << cpp_strerror(*ret_val)
- << dendl;
- m_error_result = *ret_val;
- send_close_journal();
- return nullptr;
- }
- return m_on_finish;
-}
-
-template <typename I>
-void AcquireRequest<I>::send_close_journal() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- using klass = AcquireRequest<I>;
- Context *ctx = create_context_callback<klass, &klass::handle_close_journal>(
- this);
- m_journal->close(ctx);
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_close_journal(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val < 0) {
- lderr(cct) << "failed to close journal: " << cpp_strerror(*ret_val)
- << dendl;
- }
-
- send_close_object_map();
- return nullptr;
-}
-
-template <typename I>
-Context *AcquireRequest<I>::send_open_object_map() {
- if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
- return send_open_journal();
- }
-
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- using klass = AcquireRequest<I>;
- Context *ctx = create_context_callback<klass, &klass::handle_open_object_map>(
- this);
-
- m_object_map = m_image_ctx.create_object_map(CEPH_NOSNAP);
- m_object_map->open(ctx);
- return nullptr;
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_open_object_map(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val < 0) {
- lderr(cct) << "failed to open object map: " << cpp_strerror(*ret_val)
- << dendl;
-
- *ret_val = 0;
- delete m_object_map;
- m_object_map = nullptr;
- }
-
- return send_open_journal();
-}
-
-template <typename I>
-void AcquireRequest<I>::send_close_object_map() {
- if (m_object_map == nullptr) {
- send_unlock();
- return;
- }
-
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- using klass = AcquireRequest<I>;
- Context *ctx = create_context_callback<
- klass, &klass::handle_close_object_map>(this);
- m_object_map->close(ctx);
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_close_object_map(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- // object map should never result in an error
- assert(*ret_val == 0);
- send_unlock();
- return nullptr;
-}
-
-template <typename I>
-void AcquireRequest<I>::send_unlock() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- librados::ObjectWriteOperation op;
- rados::cls::lock::unlock(&op, RBD_LOCK_NAME, m_cookie);
-
- using klass = AcquireRequest<I>;
- librados::AioCompletion *rados_completion =
- create_rados_safe_callback<klass, &klass::handle_unlock>(this);
- int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
- rados_completion, &op);
- assert(r == 0);
- rados_completion->release();
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_unlock(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val < 0) {
- lderr(cct) << "failed to unlock image: " << cpp_strerror(*ret_val) << dendl;
- }
-
- revert(ret_val);
- return m_on_finish;
-}
-
-template <typename I>
-void AcquireRequest<I>::send_get_lockers() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- librados::ObjectReadOperation op;
- rados::cls::lock::get_lock_info_start(&op, RBD_LOCK_NAME);
-
- using klass = AcquireRequest<I>;
- librados::AioCompletion *rados_completion =
- create_rados_ack_callback<klass, &klass::handle_get_lockers>(this);
- m_out_bl.clear();
- int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
- rados_completion, &op, &m_out_bl);
- assert(r == 0);
- rados_completion->release();
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_get_lockers(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- std::map<rados::cls::lock::locker_id_t,
- rados::cls::lock::locker_info_t> lockers;
- ClsLockType lock_type = LOCK_NONE;
- std::string lock_tag;
- if (*ret_val == 0) {
- bufferlist::iterator it = m_out_bl.begin();
- *ret_val = rados::cls::lock::get_lock_info_finish(&it, &lockers,
- &lock_type, &lock_tag);
- }
-
- if (*ret_val < 0) {
- lderr(cct) << "failed to retrieve lockers: " << cpp_strerror(*ret_val)
- << dendl;
- return m_on_finish;
- }
-
- if (lockers.empty()) {
- ldout(cct, 20) << "no lockers detected" << dendl;
- send_lock();
- return nullptr;
- }
-
- if (lock_tag != ExclusiveLock<>::WATCHER_LOCK_TAG) {
- ldout(cct, 5) <<"locked by external mechanism: tag=" << lock_tag << dendl;
- *ret_val = -EBUSY;
- return m_on_finish;
- }
-
- if (lock_type == LOCK_SHARED) {
- ldout(cct, 5) << "shared lock type detected" << dendl;
- *ret_val = -EBUSY;
- return m_on_finish;
- }
-
- std::map<rados::cls::lock::locker_id_t,
- rados::cls::lock::locker_info_t>::iterator iter = lockers.begin();
- if (!ExclusiveLock<>::decode_lock_cookie(iter->first.cookie,
- &m_locker_handle)) {
- ldout(cct, 5) << "locked by external mechanism: "
- << "cookie=" << iter->first.cookie << dendl;
- *ret_val = -EBUSY;
- return m_on_finish;
- }
-
- m_locker_entity = iter->first.locker;
- m_locker_cookie = iter->first.cookie;
- m_locker_address = stringify(iter->second.addr);
- if (m_locker_cookie.empty() || m_locker_address.empty()) {
- ldout(cct, 20) << "no valid lockers detected" << dendl;
- send_lock();
- return nullptr;
- }
-
- ldout(cct, 10) << "retrieved exclusive locker: "
- << m_locker_entity << "@" << m_locker_address << dendl;
- send_get_watchers();
- return nullptr;
-}
-
-template <typename I>
-void AcquireRequest<I>::send_get_watchers() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- librados::ObjectReadOperation op;
- op.list_watchers(&m_watchers, &m_watchers_ret_val);
-
- using klass = AcquireRequest<I>;
- librados::AioCompletion *rados_completion =
- create_rados_ack_callback<klass, &klass::handle_get_watchers>(this);
- m_out_bl.clear();
- int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
- rados_completion, &op, &m_out_bl);
- assert(r == 0);
- rados_completion->release();
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_get_watchers(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val == 0) {
- *ret_val = m_watchers_ret_val;
- }
- if (*ret_val < 0) {
- lderr(cct) << "failed to retrieve watchers: " << cpp_strerror(*ret_val)
- << dendl;
- return m_on_finish;
- }
-
- for (auto &watcher : m_watchers) {
- if ((strncmp(m_locker_address.c_str(),
- watcher.addr, sizeof(watcher.addr)) == 0) &&
- (m_locker_handle == watcher.cookie)) {
- ldout(cct, 10) << "lock owner is still alive" << dendl;
-
- *ret_val = -EAGAIN;
- return m_on_finish;
- }
- }
-
- send_blacklist();
- return nullptr;
-}
-
-template <typename I>
-void AcquireRequest<I>::send_blacklist() {
- if (!m_image_ctx.blacklist_on_break_lock) {
- send_break_lock();
- return;
- }
-
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- // TODO: need async version of RadosClient::blacklist_add
- using klass = AcquireRequest<I>;
- Context *ctx = create_context_callback<klass, &klass::handle_blacklist>(
- this);
- m_image_ctx.op_work_queue->queue(new C_BlacklistClient<I>(m_image_ctx,
- m_locker_address,
- ctx), 0);
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_blacklist(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val < 0) {
- lderr(cct) << "failed to blacklist lock owner: " << cpp_strerror(*ret_val)
- << dendl;
- return m_on_finish;
- }
- send_break_lock();
- return nullptr;
-}
-
-template <typename I>
-void AcquireRequest<I>::send_break_lock() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- librados::ObjectWriteOperation op;
- rados::cls::lock::break_lock(&op, RBD_LOCK_NAME, m_locker_cookie,
- m_locker_entity);
-
- using klass = AcquireRequest<I>;
- librados::AioCompletion *rados_completion =
- create_rados_safe_callback<klass, &klass::handle_break_lock>(this);
- int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
- rados_completion, &op);
- assert(r == 0);
- rados_completion->release();
-}
-
-template <typename I>
-Context *AcquireRequest<I>::handle_break_lock(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val == -ENOENT) {
- *ret_val = 0;
- } else if (*ret_val < 0) {
- lderr(cct) << "failed to break lock: " << cpp_strerror(*ret_val) << dendl;
- return m_on_finish;
- }
-
- send_lock();
- return nullptr;
-}
-
-template <typename I>
-void AcquireRequest<I>::apply() {
- {
- RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
- assert(m_image_ctx.object_map == nullptr);
- m_image_ctx.object_map = m_object_map;
-
- assert(m_image_ctx.journal == nullptr);
- m_image_ctx.journal = m_journal;
- }
-
- m_prepare_lock_completed = true;
- m_image_ctx.state->handle_prepare_lock_complete();
-}
-
-template <typename I>
-void AcquireRequest<I>::revert(int *ret_val) {
- RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
- m_image_ctx.object_map = nullptr;
- m_image_ctx.journal = nullptr;
-
- delete m_object_map;
- delete m_journal;
-
- assert(m_error_result < 0);
- *ret_val = m_error_result;
-}
-
-} // namespace exclusive_lock
-} // namespace librbd
-
-template class librbd::exclusive_lock::AcquireRequest<librbd::ImageCtx>;
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#ifndef CEPH_LIBRBD_EXCLUSIVE_LOCK_ACQUIRE_REQUEST_H
-#define CEPH_LIBRBD_EXCLUSIVE_LOCK_ACQUIRE_REQUEST_H
-
-#include "include/int_types.h"
-#include "include/buffer.h"
-#include "librbd/ImageCtx.h"
-#include "msg/msg_types.h"
-#include <string>
-
-class Context;
-
-namespace librbd {
-
-template <typename> class Journal;
-
-namespace exclusive_lock {
-
-template <typename ImageCtxT = ImageCtx>
-class AcquireRequest {
-public:
- static AcquireRequest* create(ImageCtxT &image_ctx, const std::string &cookie,
- Context *on_acquire, Context *on_finish);
-
- ~AcquireRequest();
- void send();
-
-private:
-
- /**
- * @verbatim
- *
- * <start>
- * |
- * v
- * PREPARE_LOCK
- * |
- * v
- * FLUSH_NOTIFIES
- * |
- * | /-----------------------------------------------------------\
- * | | |
- * | | (no lockers) |
- * | | . . . . . . . . . . . . . . . . . . . . . . |
- * | | . . |
- * | v v (EBUSY) . |
- * \--> LOCK_IMAGE * * * * * * * * > GET_LOCKERS . . . . |
- * | | |
- * v v |
- * REFRESH (skip if not GET_WATCHERS |
- * | needed) | |
- * v v |
- * OPEN_OBJECT_MAP (skip if BLACKLIST (skip if blacklist |
- * | disabled) | disabled) |
- * v v |
- * OPEN_JOURNAL (skip if BREAK_LOCK |
- * | * disabled) | |
- * | * \-----------------------------/
- * | * * * * * * * *
- * v *
- * ALLOCATE_JOURNAL_TAG *
- * | * *
- * | * *
- * | v v
- * | CLOSE_JOURNAL
- * | |
- * | v
- * | CLOSE_OBJECT_MAP
- * | |
- * | v
- * | UNLOCK_IMAGE
- * | |
- * v |
- * <finish> <----------/
- *
- * @endverbatim
- */
-
- AcquireRequest(ImageCtxT &image_ctx, const std::string &cookie,
- Context *on_acquire, Context *on_finish);
-
- ImageCtxT &m_image_ctx;
- std::string m_cookie;
- Context *m_on_acquire;
- Context *m_on_finish;
-
- bufferlist m_out_bl;
-
- std::list<obj_watch_t> m_watchers;
- int m_watchers_ret_val;
-
- decltype(m_image_ctx.object_map) m_object_map;
- decltype(m_image_ctx.journal) m_journal;
-
- entity_name_t m_locker_entity;
- std::string m_locker_cookie;
- std::string m_locker_address;
- uint64_t m_locker_handle;
-
- int m_error_result;
- bool m_prepare_lock_completed = false;
-
- void send_prepare_lock();
- Context *handle_prepare_lock(int *ret_val);
-
- void send_flush_notifies();
- Context *handle_flush_notifies(int *ret_val);
-
- void send_lock();
- Context *handle_lock(int *ret_val);
-
- Context *send_refresh();
- Context *handle_refresh(int *ret_val);
-
- Context *send_open_journal();
- Context *handle_open_journal(int *ret_val);
-
- void send_allocate_journal_tag();
- Context *handle_allocate_journal_tag(int *ret_val);
-
- Context *send_open_object_map();
- Context *handle_open_object_map(int *ret_val);
-
- void send_close_journal();
- Context *handle_close_journal(int *ret_val);
-
- void send_close_object_map();
- Context *handle_close_object_map(int *ret_val);
-
- void send_unlock();
- Context *handle_unlock(int *ret_val);
-
- void send_get_lockers();
- Context *handle_get_lockers(int *ret_val);
-
- void send_get_watchers();
- Context *handle_get_watchers(int *ret_val);
-
- void send_blacklist();
- Context *handle_blacklist(int *ret_val);
-
- void send_break_lock();
- Context *handle_break_lock(int *ret_val);
-
- void apply();
- void revert(int *ret_val);
-};
-
-} // namespace exclusive_lock
-} // namespace librbd
-
-extern template class librbd::exclusive_lock::AcquireRequest<librbd::ImageCtx>;
-
-#endif // CEPH_LIBRBD_EXCLUSIVE_LOCK_ACQUIRE_REQUEST_H
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/exclusive_lock/PostAcquireRequest.h"
+#include "cls/lock/cls_lock_client.h"
+#include "cls/lock/cls_lock_types.h"
+#include "common/dout.h"
+#include "common/errno.h"
+#include "common/WorkQueue.h"
+#include "include/stringify.h"
+#include "librbd/ExclusiveLock.h"
+#include "librbd/ManagedLock.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/ImageState.h"
+#include "librbd/ImageWatcher.h"
+#include "librbd/Journal.h"
+#include "librbd/ObjectMap.h"
+#include "librbd/Utils.h"
+#include "librbd/image/RefreshRequest.h"
+#include "librbd/journal/Policy.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::exclusive_lock::PostAcquireRequest: "
+
+namespace librbd {
+namespace exclusive_lock {
+
+using util::create_async_context_callback;
+using util::create_context_callback;
+using util::create_rados_ack_callback;
+using util::create_rados_safe_callback;
+
+
+template <typename I>
+PostAcquireRequest<I>* PostAcquireRequest<I>::create(I &image_ctx,
+ Context *on_acquire,
+ Context *on_finish) {
+ return new PostAcquireRequest(image_ctx, on_acquire, on_finish);
+}
+
+template <typename I>
+PostAcquireRequest<I>::PostAcquireRequest(I &image_ctx, Context *on_acquire,
+ Context *on_finish)
+ : m_image_ctx(image_ctx),
+ m_on_acquire(on_acquire),
+ m_on_finish(create_async_context_callback(image_ctx, on_finish)),
+ m_object_map(nullptr), m_journal(nullptr), m_error_result(0) {
+}
+
+template <typename I>
+PostAcquireRequest<I>::~PostAcquireRequest() {
+ if (!m_prepare_lock_completed) {
+ m_image_ctx.state->handle_prepare_lock_complete();
+ }
+ delete m_on_acquire;
+}
+
+template <typename I>
+void PostAcquireRequest<I>::send() {
+ send_refresh();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::send_refresh() {
+ if (!m_image_ctx.state->is_refresh_required()) {
+ send_open_object_map();
+ return;
+ }
+
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ using klass = PostAcquireRequest<I>;
+ Context *ctx = create_async_context_callback(
+ m_image_ctx, create_context_callback<klass, &klass::handle_refresh>(this));
+
+ // ImageState is blocked waiting for lock to complete -- safe to directly
+ // refresh
+ image::RefreshRequest<I> *req = image::RefreshRequest<I>::create(
+ m_image_ctx, true, ctx);
+ req->send();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::handle_refresh(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << ": r=" << r << dendl;
+
+ if (r == -ERESTART) {
+ // next issued IO or op will (re)-refresh the image and shut down lock
+ ldout(cct, 5) << ": exclusive lock dynamically disabled" << dendl;
+ r = 0;
+ } else if (r < 0) {
+ lderr(cct) << "failed to refresh image: " << cpp_strerror(r) << dendl;
+ save_result(r);
+ revert();
+ finish();
+ return;
+ }
+
+ send_open_object_map();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::send_open_journal() {
+ // alert caller that we now own the exclusive lock
+ m_on_acquire->complete(0);
+ m_on_acquire = nullptr;
+
+ bool journal_enabled;
+ {
+ RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
+ journal_enabled = (m_image_ctx.test_features(RBD_FEATURE_JOURNALING,
+ m_image_ctx.snap_lock) &&
+ !m_image_ctx.get_journal_policy()->journal_disabled());
+ }
+ if (!journal_enabled) {
+ apply();
+ finish();
+ return;
+ }
+
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ using klass = PostAcquireRequest<I>;
+ Context *ctx = create_context_callback<klass, &klass::handle_open_journal>(
+ this);
+ m_journal = m_image_ctx.create_journal();
+
+ // journal playback requires object map (if enabled) and itself
+ apply();
+
+ m_journal->open(ctx);
+}
+
+template <typename I>
+void PostAcquireRequest<I>::handle_open_journal(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << ": r=" << r << dendl;
+
+ save_result(r);
+ if (r < 0) {
+ lderr(cct) << "failed to open journal: " << cpp_strerror(r) << dendl;
+ send_close_journal();
+ return;
+ }
+
+ send_allocate_journal_tag();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::send_allocate_journal_tag() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
+ using klass = PostAcquireRequest<I>;
+ Context *ctx = create_context_callback<
+ klass, &klass::handle_allocate_journal_tag>(this);
+ m_image_ctx.get_journal_policy()->allocate_tag_on_lock(ctx);
+}
+
+template <typename I>
+void PostAcquireRequest<I>::handle_allocate_journal_tag(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << ": r=" << r << dendl;
+
+ save_result(r);
+ if (r < 0) {
+ lderr(cct) << "failed to allocate journal tag: " << cpp_strerror(r)
+ << dendl;
+ send_close_journal();
+ return;
+ }
+
+ finish();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::send_close_journal() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ using klass = PostAcquireRequest<I>;
+ Context *ctx = create_context_callback<klass, &klass::handle_close_journal>(
+ this);
+ m_journal->close(ctx);
+}
+
+template <typename I>
+void PostAcquireRequest<I>::handle_close_journal(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << ": r=" << r << dendl;
+
+ save_result(r);
+ if (r < 0) {
+ lderr(cct) << "failed to close journal: " << cpp_strerror(r) << dendl;
+ }
+
+ send_close_object_map();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::send_open_object_map() {
+ if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
+ send_open_journal();
+ return;
+ }
+
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ using klass = PostAcquireRequest<I>;
+ Context *ctx = create_context_callback<klass, &klass::handle_open_object_map>(
+ this);
+
+ m_object_map = m_image_ctx.create_object_map(CEPH_NOSNAP);
+ m_object_map->open(ctx);
+}
+
+template <typename I>
+void PostAcquireRequest<I>::handle_open_object_map(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << ": r=" << r << dendl;
+
+ if (r < 0) {
+ lderr(cct) << "failed to open object map: " << cpp_strerror(r) << dendl;
+
+ r = 0;
+ delete m_object_map;
+ m_object_map = nullptr;
+ }
+
+ send_open_journal();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::send_close_object_map() {
+ if (m_object_map == nullptr) {
+ revert();
+ finish();
+ return;
+ }
+
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ using klass = PostAcquireRequest<I>;
+ Context *ctx = create_context_callback<
+ klass, &klass::handle_close_object_map>(this);
+ m_object_map->close(ctx);
+}
+
+template <typename I>
+void PostAcquireRequest<I>::handle_close_object_map(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << ": r=" << r << dendl;
+
+ // object map should never result in an error
+ assert(r == 0);
+ revert();
+ finish();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::apply() {
+ {
+ RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
+ assert(m_image_ctx.object_map == nullptr);
+ m_image_ctx.object_map = m_object_map;
+
+ assert(m_image_ctx.journal == nullptr);
+ m_image_ctx.journal = m_journal;
+ }
+
+ m_prepare_lock_completed = true;
+ m_image_ctx.state->handle_prepare_lock_complete();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::revert() {
+ RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
+ m_image_ctx.object_map = nullptr;
+ m_image_ctx.journal = nullptr;
+
+ delete m_object_map;
+ delete m_journal;
+
+ assert(m_error_result < 0);
+}
+
+template <typename I>
+void PostAcquireRequest<I>::finish() {
+ m_on_finish->complete(m_error_result);
+ delete this;
+}
+
+} // namespace exclusive_lock
+} // namespace librbd
+
+template class librbd::exclusive_lock::PostAcquireRequest<librbd::ImageCtx>;
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_EXCLUSIVE_LOCK_POST_ACQUIRE_REQUEST_H
+#define CEPH_LIBRBD_EXCLUSIVE_LOCK_POST_ACQUIRE_REQUEST_H
+
+#include "include/int_types.h"
+#include "include/buffer.h"
+#include "librbd/ImageCtx.h"
+#include "msg/msg_types.h"
+#include <string>
+
+class Context;
+
+namespace librbd {
+
+template <typename> class Journal;
+template <typename> class ManagedLock;
+
+namespace exclusive_lock {
+
+template <typename ImageCtxT = ImageCtx>
+class PostAcquireRequest {
+public:
+ static PostAcquireRequest* create(ImageCtxT &image_ctx, Context *on_acquire,
+ Context *on_finish);
+
+ ~PostAcquireRequest();
+ void send();
+
+private:
+
+ /**
+ * @verbatim
+ *
+ * <start>
+ * |
+ * |
+ * v
+ * REFRESH (skip if not
+ * | needed)
+ * v
+ * OPEN_OBJECT_MAP (skip if
+ * | disabled)
+ * v
+ * OPEN_JOURNAL (skip if
+ * | * disabled)
+ * | *
+ * | * * * * * * * *
+ * v *
+ * ALLOCATE_JOURNAL_TAG *
+ * | * *
+ * | * *
+ * | v v
+ * | CLOSE_JOURNAL
+ * | |
+ * | v
+ * | CLOSE_OBJECT_MAP
+ * | |
+ * v |
+ * <finish> <----------/
+ *
+ * @endverbatim
+ */
+
+ PostAcquireRequest(ImageCtxT &image_ctx, Context *on_acquire,
+ Context *on_finish);
+
+ ImageCtxT &m_image_ctx;
+ Context *m_on_acquire;
+ Context *m_on_finish;
+
+ decltype(m_image_ctx.object_map) m_object_map;
+ decltype(m_image_ctx.journal) m_journal;
+
+ bool m_prepare_lock_completed = false;
+ int m_error_result;
+
+ void send_refresh();
+ void handle_refresh(int r);
+
+ void send_open_journal();
+ void handle_open_journal(int r);
+
+ void send_allocate_journal_tag();
+ void handle_allocate_journal_tag(int r);
+
+ void send_open_object_map();
+ void handle_open_object_map(int r);
+
+ void send_close_journal();
+ void handle_close_journal(int r);
+
+ void send_close_object_map();
+ void handle_close_object_map(int r);
+
+ void apply();
+ void revert();
+
+ void finish();
+
+ void save_result(int result) {
+ if (m_error_result == 0 && result < 0) {
+ m_error_result = result;
+ }
+ }
+};
+
+} // namespace exclusive_lock
+} // namespace librbd
+
+extern template class librbd::exclusive_lock::PostAcquireRequest<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_EXCLUSIVE_LOCK_POST_ACQUIRE_REQUEST_H
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/exclusive_lock/PreAcquireRequest.h"
+#include "librbd/Utils.h"
+#include "common/dout.h"
+#include "common/errno.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/ImageWatcher.h"
+#include "librbd/ImageState.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::exclusive_lock::PreAcquireRequest: "
+
+namespace librbd {
+namespace exclusive_lock {
+
+using util::create_async_context_callback;
+using util::create_context_callback;
+using util::create_rados_ack_callback;
+using util::create_rados_safe_callback;
+
+
+template <typename I>
+PreAcquireRequest<I>* PreAcquireRequest<I>::create(I &image_ctx,
+ Context *on_finish) {
+ return new PreAcquireRequest(image_ctx, on_finish);
+}
+
+template <typename I>
+PreAcquireRequest<I>::PreAcquireRequest(I &image_ctx, Context *on_finish)
+ : m_image_ctx(image_ctx),
+ m_on_finish(create_async_context_callback(image_ctx, on_finish)),
+ m_error_result(0) {
+}
+
+template <typename I>
+PreAcquireRequest<I>::~PreAcquireRequest() {
+}
+
+template <typename I>
+void PreAcquireRequest<I>::send() {
+ send_prepare_lock();
+}
+
+template <typename I>
+void PreAcquireRequest<I>::send_prepare_lock() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ // acquire the lock if the image is not busy performing other actions
+ Context *ctx = create_context_callback<
+ PreAcquireRequest<I>, &PreAcquireRequest<I>::handle_prepare_lock>(this);
+ m_image_ctx.state->prepare_lock(ctx);
+}
+
+template <typename I>
+void PreAcquireRequest<I>::handle_prepare_lock(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << ": r=" << r << dendl;
+
+ send_flush_notifies();
+}
+
+template <typename I>
+void PreAcquireRequest<I>::send_flush_notifies() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ using klass = PreAcquireRequest<I>;
+ Context *ctx = create_context_callback<klass, &klass::handle_flush_notifies>(
+ this);
+ m_image_ctx.image_watcher->flush(ctx);
+}
+
+template <typename I>
+void PreAcquireRequest<I>::handle_flush_notifies(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ assert(r == 0);
+ finish();
+}
+
+template <typename I>
+void PreAcquireRequest<I>::finish() {
+ m_on_finish->complete(m_error_result);
+ delete this;
+}
+
+} // namespace exclusive_lock
+} // namespace librbd
+
+template class librbd::exclusive_lock::PreAcquireRequest<librbd::ImageCtx>;
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_EXCLUSIVE_LOCK_PRE_ACQUIRE_REQUEST_H
+#define CEPH_LIBRBD_EXCLUSIVE_LOCK_PRE_ACQUIRE_REQUEST_H
+
+#include "include/int_types.h"
+#include "include/buffer.h"
+#include "librbd/ImageCtx.h"
+#include "msg/msg_types.h"
+#include <string>
+
+class Context;
+
+namespace librbd {
+
+namespace exclusive_lock {
+
+template <typename ImageCtxT = ImageCtx>
+class PreAcquireRequest {
+public:
+ static PreAcquireRequest* create(ImageCtxT &image_ctx, Context *on_finish);
+
+ ~PreAcquireRequest();
+ void send();
+
+private:
+
+ /**
+ * @verbatim
+ *
+ * <start>
+ * |
+ * v
+ * PREPARE_LOCK
+ * |
+ * v
+ * FLUSH_NOTIFIES
+ * |
+ * |
+ * |
+ v
+ * <finish>
+ *
+ * @endverbatim
+ */
+
+ PreAcquireRequest(ImageCtxT &image_ctx, Context *on_finish);
+
+ ImageCtxT &m_image_ctx;
+ Context *m_on_finish;
+
+ int m_error_result;
+
+ void send_prepare_lock();
+ void handle_prepare_lock(int r);
+
+ void send_flush_notifies();
+ void handle_flush_notifies(int r);
+
+ void finish();
+
+ void save_result(int result) {
+ if (m_error_result == 0 && result < 0) {
+ m_error_result = result;
+ }
+ }
+};
+
+} // namespace exclusive_lock
+} // namespace librbd
+
+extern template class librbd::exclusive_lock::PreAcquireRequest<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_EXCLUSIVE_LOCK_ACQUIRE_REQUEST_H
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/exclusive_lock/PreReleaseRequest.h"
+#include "common/dout.h"
+#include "common/errno.h"
+#include "librbd/AioImageRequestWQ.h"
+#include "librbd/ExclusiveLock.h"
+#include "librbd/ManagedLock.h"
+#include "librbd/ImageState.h"
+#include "librbd/ImageWatcher.h"
+#include "librbd/Journal.h"
+#include "librbd/ObjectMap.h"
+#include "librbd/Utils.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::exclusive_lock::PreReleaseRequest: "
+
+namespace librbd {
+namespace exclusive_lock {
+
+using util::create_async_context_callback;
+using util::create_context_callback;
+
+template <typename I>
+PreReleaseRequest<I>* PreReleaseRequest<I>::create(I &image_ctx,
+ Context *on_releasing,
+ Context *on_finish,
+ bool shutting_down) {
+ return new PreReleaseRequest(image_ctx, on_releasing, on_finish,
+ shutting_down);
+}
+
+template <typename I>
+PreReleaseRequest<I>::PreReleaseRequest(I &image_ctx, Context *on_releasing,
+ Context *on_finish, bool shutting_down)
+ : m_image_ctx(image_ctx), m_on_releasing(on_releasing),
+ m_on_finish(create_async_context_callback(image_ctx, on_finish)),
+ m_shutting_down(shutting_down), m_error_result(0), m_object_map(nullptr),
+ m_journal(nullptr) {
+}
+
+template <typename I>
+PreReleaseRequest<I>::~PreReleaseRequest() {
+ if (!m_shutting_down) {
+ m_image_ctx.state->handle_prepare_lock_complete();
+ }
+ delete m_on_releasing;
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send() {
+ send_prepare_lock();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send_prepare_lock() {
+ if (m_shutting_down) {
+ send_cancel_op_requests();
+ return;
+ }
+
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ // release the lock if the image is not busy performing other actions
+ Context *ctx = create_context_callback<
+ PreReleaseRequest<I>, &PreReleaseRequest<I>::handle_prepare_lock>(this);
+ m_image_ctx.state->prepare_lock(ctx);
+}
+
+template <typename I>
+void PreReleaseRequest<I>::handle_prepare_lock(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << ": r=" << r << dendl;
+
+ send_cancel_op_requests();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send_cancel_op_requests() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ using klass = PreReleaseRequest<I>;
+ Context *ctx = create_context_callback<
+ klass, &klass::handle_cancel_op_requests>(this);
+ m_image_ctx.cancel_async_requests(ctx);
+}
+
+template <typename I>
+void PreReleaseRequest<I>::handle_cancel_op_requests(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << ": r=" << r << dendl;
+
+ assert(r == 0);
+
+ send_block_writes();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send_block_writes() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ using klass = PreReleaseRequest<I>;
+ Context *ctx = create_context_callback<
+ klass, &klass::handle_block_writes>(this);
+
+ {
+ RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
+ if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
+ m_image_ctx.aio_work_queue->set_require_lock_on_read();
+ }
+ m_image_ctx.aio_work_queue->block_writes(ctx);
+ }
+}
+
+template <typename I>
+void PreReleaseRequest<I>::handle_block_writes(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << ": r=" << r << dendl;
+
+ save_result(r);
+ if (r < 0) {
+ m_image_ctx.aio_work_queue->unblock_writes();
+ finish();
+ return;
+ }
+
+ send_image_flush_notifies();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send_image_flush_notifies() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ using klass = PreReleaseRequest<I>;
+ Context *ctx =
+ create_context_callback<klass, &klass::handle_image_flush_notifies>(this);
+ m_image_ctx.image_watcher->flush(ctx);
+}
+
+template <typename I>
+void PreReleaseRequest<I>::handle_image_flush_notifies(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ assert(r == 0);
+ send_close_journal();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send_close_journal() {
+ {
+ RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
+ std::swap(m_journal, m_image_ctx.journal);
+ }
+
+ if (m_journal == nullptr) {
+ send_close_object_map();
+ return;
+ }
+
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ using klass = PreReleaseRequest<I>;
+ Context *ctx = create_context_callback<klass, &klass::handle_close_journal>(
+ this);
+ m_journal->close(ctx);
+}
+
+template <typename I>
+void PreReleaseRequest<I>::handle_close_journal(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << ": r=" << r << dendl;
+
+ if (r < 0) {
+ // error implies some journal events were not flushed -- continue
+ lderr(cct) << "failed to close journal: " << cpp_strerror(r) << dendl;
+ }
+
+ delete m_journal;
+
+ send_close_object_map();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send_close_object_map() {
+ {
+ RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
+ std::swap(m_object_map, m_image_ctx.object_map);
+ }
+
+ if (m_object_map == nullptr) {
+ send_unlock();
+ return;
+ }
+
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ using klass = PreReleaseRequest<I>;
+ Context *ctx = create_context_callback<
+ klass, &klass::handle_close_object_map>(this);
+ m_object_map->close(ctx);
+}
+
+template <typename I>
+void PreReleaseRequest<I>::handle_close_object_map(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << ": r=" << r << dendl;
+
+ // object map shouldn't return errors
+ assert(r == 0);
+ delete m_object_map;
+
+ send_unlock();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send_unlock() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << __func__ << dendl;
+
+ if (m_on_releasing != nullptr) {
+ // alert caller that we no longer own the exclusive lock
+ m_on_releasing->complete(0);
+ m_on_releasing = nullptr;
+ }
+
+ finish();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::finish() {
+ m_on_finish->complete(m_error_result);
+ delete this;
+}
+
+} // namespace exclusive_lock
+} // namespace librbd
+
+template class librbd::exclusive_lock::PreReleaseRequest<librbd::ImageCtx>;
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_EXCLUSIVE_LOCK_PRE_RELEASE_REQUEST_H
+#define CEPH_LIBRBD_EXCLUSIVE_LOCK_PRE_RELEASE_REQUEST_H
+
+#include "librbd/ImageCtx.h"
+#include <string>
+
+class Context;
+
+namespace librbd {
+
+struct ImageCtx;
+template <typename> class ManagedLock;
+template <typename> class Journal;
+
+namespace exclusive_lock {
+
+template <typename ImageCtxT = ImageCtx>
+class PreReleaseRequest {
+public:
+ static PreReleaseRequest* create(ImageCtxT &image_ctx, Context *on_releasing,
+ Context *on_finish, bool shutting_down);
+
+ ~PreReleaseRequest();
+ void send();
+
+private:
+ /**
+ * @verbatim
+ *
+ * <start>
+ * |
+ * v
+ * PREPARE_LOCK
+ * |
+ * v
+ * CANCEL_OP_REQUESTS
+ * |
+ * v
+ * BLOCK_WRITES
+ * |
+ * v
+ * FLUSH_NOTIFIES . . . . . . . . . . . . . .
+ * | .
+ * v .
+ * CLOSE_JOURNAL .
+ * | (journal disabled, .
+ * v object map enabled) .
+ * CLOSE_OBJECT_MAP < . . . . . . . . . . . .
+ * | .
+ * v (object map disabled) .
+ * <finish> < . . . . . . . . . . . . . . . . .
+ *
+ * @endverbatim
+ */
+
+ PreReleaseRequest(ImageCtxT &image_ctx, Context *on_releasing,
+ Context *on_finish, bool shutting_down);
+
+ ImageCtxT &m_image_ctx;
+ Context *m_on_releasing;
+ Context *m_on_finish;
+ bool m_shutting_down;
+
+ int m_error_result;
+
+ decltype(m_image_ctx.object_map) m_object_map;
+ decltype(m_image_ctx.journal) m_journal;
+
+ void send_prepare_lock();
+ void handle_prepare_lock(int r);
+
+ void send_cancel_op_requests();
+ void handle_cancel_op_requests(int r);
+
+ void send_block_writes();
+ void handle_block_writes(int r);
+
+ void send_image_flush_notifies();
+ void handle_image_flush_notifies(int r);
+
+ void send_close_journal();
+ void handle_close_journal(int r);
+
+ void send_close_object_map();
+ void handle_close_object_map(int r);
+
+ void send_unlock();
+
+ void finish();
+
+ void save_result(int result) {
+ if (m_error_result == 0 && result < 0) {
+ m_error_result = result;
+ }
+ }
+
+};
+
+} // namespace exclusive_lock
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_EXCLUSIVE_LOCK_PRE_RELEASE_REQUEST_H
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "librbd/exclusive_lock/ReacquireRequest.h"
-#include "cls/lock/cls_lock_client.h"
-#include "cls/lock/cls_lock_types.h"
-#include "common/dout.h"
-#include "common/errno.h"
-#include "librbd/ExclusiveLock.h"
-#include "librbd/ImageCtx.h"
-#include "librbd/Utils.h"
-
-#define dout_subsys ceph_subsys_rbd
-#undef dout_prefix
-#define dout_prefix *_dout << "librbd::exclusive_lock::ReacquireRequest: " \
- << this << ": " << __func__
-
-namespace librbd {
-namespace exclusive_lock {
-
-using librbd::util::create_rados_safe_callback;
-
-template <typename I>
-ReacquireRequest<I>::ReacquireRequest(I &image_ctx,
- const std::string &old_cookie,
- const std::string &new_cookie,
- Context *on_finish)
- : m_image_ctx(image_ctx), m_old_cookie(old_cookie), m_new_cookie(new_cookie),
- m_on_finish(on_finish) {
-}
-
-template <typename I>
-void ReacquireRequest<I>::send() {
- set_cookie();
-}
-
-template <typename I>
-void ReacquireRequest<I>::set_cookie() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << dendl;
-
- librados::ObjectWriteOperation op;
- rados::cls::lock::set_cookie(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, m_old_cookie,
- ExclusiveLock<>::WATCHER_LOCK_TAG, m_new_cookie);
-
- librados::AioCompletion *rados_completion = create_rados_safe_callback<
- ReacquireRequest<I>, &ReacquireRequest<I>::handle_set_cookie>(this);
- int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
- rados_completion, &op);
- assert(r == 0);
- rados_completion->release();
-}
-
-template <typename I>
-void ReacquireRequest<I>::handle_set_cookie(int r) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << ": r=" << r << dendl;
-
- if (r == -EOPNOTSUPP) {
- ldout(cct, 10) << ": OSD doesn't support updating lock" << dendl;
- } else if (r < 0) {
- lderr(cct) << ": failed to update lock: " << cpp_strerror(r) << dendl;
- }
-
- m_on_finish->complete(r);
- delete this;
-}
-
-} // namespace exclusive_lock
-} // namespace librbd
-
-template class librbd::exclusive_lock::ReacquireRequest<librbd::ImageCtx>;
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#ifndef CEPH_LIBRBD_EXCLUSIVE_LOCK_REACQUIRE_REQUEST_H
-#define CEPH_LIBRBD_EXCLUSIVE_LOCK_REACQUIRE_REQUEST_H
-
-#include "include/int_types.h"
-#include <string>
-
-class Context;
-
-namespace librbd {
-
-class ImageCtx;
-
-namespace exclusive_lock {
-
-template <typename ImageCtxT = ImageCtx>
-class ReacquireRequest {
-public:
-
- static ReacquireRequest *create(ImageCtxT &image_ctx,
- const std::string &old_cookie,
- const std::string &new_cookie,
- Context *on_finish) {
- return new ReacquireRequest(image_ctx, old_cookie, new_cookie, on_finish);
- }
-
- ReacquireRequest(ImageCtxT &image_ctx, const std::string &old_cookie,
- const std::string &new_cookie, Context *on_finish);
-
- void send();
-
-private:
- /**
- * @verbatim
- *
- * <start>
- * |
- * v
- * SET_COOKIE
- * |
- * v
- * <finish>
- *
- * @endverbatim
- */
- ImageCtxT &m_image_ctx;
- std::string m_old_cookie;
- std::string m_new_cookie;
- Context *m_on_finish;
-
- void set_cookie();
- void handle_set_cookie(int r);
-
-};
-
-} // namespace exclusive_lock
-} // namespace librbd
-
-extern template class librbd::exclusive_lock::ReacquireRequest<librbd::ImageCtx>;
-
-#endif // CEPH_LIBRBD_EXCLUSIVE_LOCK_REACQUIRE_REQUEST_H
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "librbd/exclusive_lock/ReleaseRequest.h"
-#include "cls/lock/cls_lock_client.h"
-#include "cls/lock/cls_lock_types.h"
-#include "common/dout.h"
-#include "common/errno.h"
-#include "librbd/AioImageRequestWQ.h"
-#include "librbd/ExclusiveLock.h"
-#include "librbd/ImageState.h"
-#include "librbd/ImageWatcher.h"
-#include "librbd/Journal.h"
-#include "librbd/ObjectMap.h"
-#include "librbd/Utils.h"
-
-#define dout_subsys ceph_subsys_rbd
-#undef dout_prefix
-#define dout_prefix *_dout << "librbd::exclusive_lock::ReleaseRequest: "
-
-namespace librbd {
-namespace exclusive_lock {
-
-using util::create_async_context_callback;
-using util::create_context_callback;
-using util::create_rados_safe_callback;
-
-template <typename I>
-ReleaseRequest<I>* ReleaseRequest<I>::create(I &image_ctx,
- const std::string &cookie,
- Context *on_releasing,
- Context *on_finish,
- bool shutting_down) {
- return new ReleaseRequest(image_ctx, cookie, on_releasing, on_finish,
- shutting_down);
-}
-
-template <typename I>
-ReleaseRequest<I>::ReleaseRequest(I &image_ctx, const std::string &cookie,
- Context *on_releasing, Context *on_finish,
- bool shutting_down)
- : m_image_ctx(image_ctx), m_cookie(cookie), m_on_releasing(on_releasing),
- m_on_finish(create_async_context_callback(image_ctx, on_finish)),
- m_shutting_down(shutting_down), m_object_map(nullptr), m_journal(nullptr) {
-}
-
-template <typename I>
-ReleaseRequest<I>::~ReleaseRequest() {
- if (!m_shutting_down) {
- m_image_ctx.state->handle_prepare_lock_complete();
- }
- delete m_on_releasing;
-}
-
-template <typename I>
-void ReleaseRequest<I>::send() {
- send_prepare_lock();
-}
-
-template <typename I>
-void ReleaseRequest<I>::send_prepare_lock() {
- if (m_shutting_down) {
- send_cancel_op_requests();
- return;
- }
-
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- // release the lock if the image is not busy performing other actions
- Context *ctx = create_context_callback<
- ReleaseRequest<I>, &ReleaseRequest<I>::handle_prepare_lock>(this);
- m_image_ctx.state->prepare_lock(ctx);
-}
-
-template <typename I>
-Context *ReleaseRequest<I>::handle_prepare_lock(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- send_cancel_op_requests();
- return nullptr;
-}
-
-template <typename I>
-void ReleaseRequest<I>::send_cancel_op_requests() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- using klass = ReleaseRequest<I>;
- Context *ctx = create_context_callback<
- klass, &klass::handle_cancel_op_requests>(this);
- m_image_ctx.cancel_async_requests(ctx);
-}
-
-template <typename I>
-Context *ReleaseRequest<I>::handle_cancel_op_requests(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- assert(*ret_val == 0);
-
- send_block_writes();
- return nullptr;
-}
-
-template <typename I>
-void ReleaseRequest<I>::send_block_writes() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- using klass = ReleaseRequest<I>;
- Context *ctx = create_context_callback<
- klass, &klass::handle_block_writes>(this);
-
- {
- RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
- if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
- m_image_ctx.aio_work_queue->set_require_lock_on_read();
- }
- m_image_ctx.aio_work_queue->block_writes(ctx);
- }
-}
-
-template <typename I>
-Context *ReleaseRequest<I>::handle_block_writes(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val < 0) {
- m_image_ctx.aio_work_queue->unblock_writes();
- return m_on_finish;
- }
-
- send_flush_notifies();
- return nullptr;
-}
-
-template <typename I>
-void ReleaseRequest<I>::send_flush_notifies() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- using klass = ReleaseRequest<I>;
- Context *ctx = create_context_callback<
- klass, &klass::handle_flush_notifies>(this);
- m_image_ctx.image_watcher->flush(ctx);
-}
-
-template <typename I>
-Context *ReleaseRequest<I>::handle_flush_notifies(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- assert(*ret_val == 0);
- send_close_journal();
- return nullptr;
-}
-
-template <typename I>
-void ReleaseRequest<I>::send_close_journal() {
- {
- RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
- std::swap(m_journal, m_image_ctx.journal);
- }
-
- if (m_journal == nullptr) {
- send_close_object_map();
- return;
- }
-
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- using klass = ReleaseRequest<I>;
- Context *ctx = create_context_callback<klass, &klass::handle_close_journal>(
- this);
- m_journal->close(ctx);
-}
-
-template <typename I>
-Context *ReleaseRequest<I>::handle_close_journal(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val < 0) {
- // error implies some journal events were not flushed -- continue
- lderr(cct) << "failed to close journal: " << cpp_strerror(*ret_val)
- << dendl;
- }
-
- delete m_journal;
-
- send_close_object_map();
- return nullptr;
-}
-
-template <typename I>
-void ReleaseRequest<I>::send_close_object_map() {
- {
- RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
- std::swap(m_object_map, m_image_ctx.object_map);
- }
-
- if (m_object_map == nullptr) {
- send_unlock();
- return;
- }
-
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- using klass = ReleaseRequest<I>;
- Context *ctx = create_context_callback<
- klass, &klass::handle_close_object_map>(this);
- m_object_map->close(ctx);
-}
-
-template <typename I>
-Context *ReleaseRequest<I>::handle_close_object_map(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- // object map shouldn't return errors
- assert(*ret_val == 0);
- delete m_object_map;
-
- send_unlock();
- return nullptr;
-}
-
-template <typename I>
-void ReleaseRequest<I>::send_unlock() {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << dendl;
-
- if (m_on_releasing != nullptr) {
- // alert caller that we no longer own the exclusive lock
- m_on_releasing->complete(0);
- m_on_releasing = nullptr;
- }
-
- librados::ObjectWriteOperation op;
- rados::cls::lock::unlock(&op, RBD_LOCK_NAME, m_cookie);
-
- using klass = ReleaseRequest<I>;
- librados::AioCompletion *rados_completion =
- create_rados_safe_callback<klass, &klass::handle_unlock>(this);
- int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid,
- rados_completion, &op);
- assert(r == 0);
- rados_completion->release();
-}
-
-template <typename I>
-Context *ReleaseRequest<I>::handle_unlock(int *ret_val) {
- CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
-
- if (*ret_val < 0 && *ret_val != -ENOENT) {
- lderr(cct) << "failed to unlock: " << cpp_strerror(*ret_val) << dendl;
- }
-
- // treat errors as the image is unlocked
- *ret_val = 0;
- return m_on_finish;
-}
-
-} // namespace exclusive_lock
-} // namespace librbd
-
-template class librbd::exclusive_lock::ReleaseRequest<librbd::ImageCtx>;
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#ifndef CEPH_LIBRBD_EXCLUSIVE_LOCK_RELEASE_REQUEST_H
-#define CEPH_LIBRBD_EXCLUSIVE_LOCK_RELEASE_REQUEST_H
-
-#include "librbd/ImageCtx.h"
-#include <string>
-
-class Context;
-
-namespace librbd {
-
-class ImageCtx;
-template <typename> class Journal;
-
-namespace exclusive_lock {
-
-template <typename ImageCtxT = ImageCtx>
-class ReleaseRequest {
-public:
- static ReleaseRequest* create(ImageCtxT &image_ctx, const std::string &cookie,
- Context *on_releasing, Context *on_finish,
- bool shutting_down);
-
- ~ReleaseRequest();
- void send();
-
-private:
- /**
- * @verbatim
- *
- * <start>
- * |
- * v
- * PREPARE_LOCK
- * |
- * v
- * CANCEL_OP_REQUESTS
- * |
- * v
- * BLOCK_WRITES
- * |
- * v
- * FLUSH_NOTIFIES . . . . . . . . . . . . . .
- * | .
- * v .
- * CLOSE_JOURNAL .
- * | (journal disabled, .
- * v object map enabled) .
- * CLOSE_OBJECT_MAP < . . . . . . . . . . . .
- * | .
- * v (object map disabled) .
- * UNLOCK < . . . . . . . . . . . . . . . . .
- * |
- * v
- * <finish>
- *
- * @endverbatim
- */
-
- ReleaseRequest(ImageCtxT &image_ctx, const std::string &cookie,
- Context *on_releasing, Context *on_finish,
- bool shutting_down);
-
- ImageCtxT &m_image_ctx;
- std::string m_cookie;
- Context *m_on_releasing;
- Context *m_on_finish;
- bool m_shutting_down;
-
- decltype(m_image_ctx.object_map) m_object_map;
- decltype(m_image_ctx.journal) m_journal;
-
- void send_prepare_lock();
- Context *handle_prepare_lock(int *ret_val);
-
- void send_cancel_op_requests();
- Context *handle_cancel_op_requests(int *ret_val);
-
- void send_block_writes();
- Context *handle_block_writes(int *ret_val);
-
- void send_flush_notifies();
- Context *handle_flush_notifies(int *ret_val);
-
- void send_close_journal();
- Context *handle_close_journal(int *ret_val);
-
- void send_close_object_map();
- Context *handle_close_object_map(int *ret_val);
-
- void send_unlock();
- Context *handle_unlock(int *ret_val);
-
-};
-
-} // namespace exclusive_lock
-} // namespace librbd
-
-extern template class librbd::exclusive_lock::ReleaseRequest<librbd::ImageCtx>;
-
-#endif // CEPH_LIBRBD_EXCLUSIVE_LOCK_RELEASE_REQUEST_H
return 0;
}
- ictx->exclusive_lock->request_lock(&lock_ctx);
+ ictx->exclusive_lock->acquire_lock(&lock_ctx);
}
int r = lock_ctx.wait();
};
C_SaferCond lock_ctx;
- ictx->exclusive_lock->request_lock(&lock_ctx);
+ ictx->exclusive_lock->acquire_lock(&lock_ctx);
// don't block holding lock since refresh might be required
ictx->owner_lock.put_read();
std::map<rados::cls::lock::locker_id_t,
rados::cls::lock::locker_info_t> lockers;
- ClsLockType lock_type;
+ ClsLockType lock_type = LOCK_NONE;
std::string lock_tag;
if (r == 0) {
!image_ctx.exclusive_lock->is_lock_owner()) {
m_acquired_lock = true;
- image_ctx.exclusive_lock->request_lock(ctx);
+ image_ctx.exclusive_lock->acquire_lock(ctx);
return;
}
}
test_mock_ExclusiveLock.cc
test_mock_Journal.cc
test_mock_ObjectMap.cc
- exclusive_lock/test_mock_AcquireRequest.cc
- exclusive_lock/test_mock_ReacquireRequest.cc
- exclusive_lock/test_mock_ReleaseRequest.cc
+ exclusive_lock/test_mock_PreAcquireRequest.cc
+ exclusive_lock/test_mock_PostAcquireRequest.cc
+ exclusive_lock/test_mock_PreReleaseRequest.cc
image/test_mock_RefreshRequest.cc
journal/test_mock_OpenRequest.cc
journal/test_mock_PromoteRequest.cc
+++ /dev/null
-// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "test/librbd/test_mock_fixture.h"
-#include "test/librbd/test_support.h"
-#include "test/librbd/mock/MockImageCtx.h"
-#include "test/librbd/mock/MockImageState.h"
-#include "test/librbd/mock/MockJournal.h"
-#include "test/librbd/mock/MockJournalPolicy.h"
-#include "test/librbd/mock/MockObjectMap.h"
-#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
-#include "test/librados_test_stub/MockTestMemRadosClient.h"
-#include "cls/lock/cls_lock_ops.h"
-#include "librbd/ExclusiveLock.h"
-#include "librbd/exclusive_lock/AcquireRequest.h"
-#include "librbd/image/RefreshRequest.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include <arpa/inet.h>
-#include <list>
-
-namespace librbd {
-namespace {
-
-struct MockTestImageCtx : public librbd::MockImageCtx {
- MockTestImageCtx(librbd::ImageCtx &image_ctx)
- : librbd::MockImageCtx(image_ctx) {
- }
-};
-
-} // anonymous namespace
-
-namespace image {
-
-template<>
-struct RefreshRequest<librbd::MockTestImageCtx> {
- static RefreshRequest *s_instance;
- Context *on_finish;
-
- static RefreshRequest *create(librbd::MockTestImageCtx &image_ctx,
- bool acquire_lock_refresh,
- Context *on_finish) {
- EXPECT_TRUE(acquire_lock_refresh);
- assert(s_instance != nullptr);
- s_instance->on_finish = on_finish;
- return s_instance;
- }
-
- RefreshRequest() {
- s_instance = this;
- }
- MOCK_METHOD0(send, void());
-};
-
-RefreshRequest<librbd::MockTestImageCtx> *RefreshRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-
-} // namespace image
-} // namespace librbd
-
-// template definitions
-#include "librbd/Journal.cc"
-#include "librbd/exclusive_lock/AcquireRequest.cc"
-template class librbd::exclusive_lock::AcquireRequest<librbd::MockTestImageCtx>;
-
-namespace librbd {
-namespace exclusive_lock {
-
-using ::testing::_;
-using ::testing::DoAll;
-using ::testing::InSequence;
-using ::testing::Invoke;
-using ::testing::Return;
-using ::testing::SetArgPointee;
-using ::testing::StrEq;
-using ::testing::WithArg;
-
-static const std::string TEST_COOKIE("auto 123");
-
-class TestMockExclusiveLockAcquireRequest : public TestMockFixture {
-public:
- typedef AcquireRequest<MockTestImageCtx> MockAcquireRequest;
- typedef ExclusiveLock<MockTestImageCtx> MockExclusiveLock;
- typedef librbd::image::RefreshRequest<MockTestImageCtx> MockRefreshRequest;
-
- void expect_test_features(MockTestImageCtx &mock_image_ctx, uint64_t features,
- bool enabled) {
- EXPECT_CALL(mock_image_ctx, test_features(features))
- .WillOnce(Return(enabled));
- }
-
- void expect_test_features(MockTestImageCtx &mock_image_ctx, uint64_t features,
- RWLock &lock, bool enabled) {
- EXPECT_CALL(mock_image_ctx, test_features(features, _))
- .WillOnce(Return(enabled));
- }
-
- void expect_lock(MockTestImageCtx &mock_image_ctx, int r) {
- EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("lock"), StrEq("lock"), _, _, _))
- .WillOnce(Return(r));
- }
-
- void expect_unlock(MockTestImageCtx &mock_image_ctx, int r) {
- EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("lock"), StrEq("unlock"), _, _, _))
- .WillOnce(Return(r));
- }
-
- void expect_is_refresh_required(MockTestImageCtx &mock_image_ctx, bool required) {
- EXPECT_CALL(*mock_image_ctx.state, is_refresh_required())
- .WillOnce(Return(required));
- }
-
- void expect_refresh(MockTestImageCtx &mock_image_ctx,
- MockRefreshRequest &mock_refresh_request, int r) {
- EXPECT_CALL(mock_refresh_request, send())
- .WillOnce(FinishRequest(&mock_refresh_request, r,
- &mock_image_ctx));
- }
-
- void expect_create_object_map(MockTestImageCtx &mock_image_ctx,
- MockObjectMap *mock_object_map) {
- EXPECT_CALL(mock_image_ctx, create_object_map(_))
- .WillOnce(Return(mock_object_map));
- }
-
- void expect_open_object_map(MockTestImageCtx &mock_image_ctx,
- MockObjectMap &mock_object_map, int r) {
- EXPECT_CALL(mock_object_map, open(_))
- .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
- }
-
- void expect_close_object_map(MockTestImageCtx &mock_image_ctx,
- MockObjectMap &mock_object_map) {
- EXPECT_CALL(mock_object_map, close(_))
- .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
- }
-
- void expect_create_journal(MockTestImageCtx &mock_image_ctx,
- MockJournal *mock_journal) {
- EXPECT_CALL(mock_image_ctx, create_journal())
- .WillOnce(Return(mock_journal));
- }
-
- void expect_open_journal(MockTestImageCtx &mock_image_ctx,
- MockJournal &mock_journal, int r) {
- EXPECT_CALL(mock_journal, open(_))
- .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
- }
-
- void expect_close_journal(MockTestImageCtx &mock_image_ctx,
- MockJournal &mock_journal) {
- EXPECT_CALL(mock_journal, close(_))
- .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
- }
-
- void expect_get_journal_policy(MockTestImageCtx &mock_image_ctx,
- MockJournalPolicy &mock_journal_policy) {
- EXPECT_CALL(mock_image_ctx, get_journal_policy())
- .WillOnce(Return(&mock_journal_policy));
- }
-
- void expect_journal_disabled(MockJournalPolicy &mock_journal_policy,
- bool disabled) {
- EXPECT_CALL(mock_journal_policy, journal_disabled())
- .WillOnce(Return(disabled));
- }
-
- void expect_allocate_journal_tag(MockTestImageCtx &mock_image_ctx,
- MockJournalPolicy &mock_journal_policy,
- int r) {
- EXPECT_CALL(mock_journal_policy, allocate_tag_on_lock(_))
- .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
- }
-
- void expect_get_lock_info(MockTestImageCtx &mock_image_ctx, int r,
- const entity_name_t &locker_entity,
- const std::string &locker_address,
- const std::string &locker_cookie,
- const std::string &lock_tag,
- ClsLockType lock_type) {
- auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("lock"),
- StrEq("get_info"), _, _, _));
- if (r < 0 && r != -ENOENT) {
- expect.WillOnce(Return(r));
- } else {
- entity_name_t entity(locker_entity);
- entity_addr_t entity_addr;
- entity_addr.parse(locker_address.c_str(), NULL);
-
- cls_lock_get_info_reply reply;
- if (r != -ENOENT) {
- reply.lockers = decltype(reply.lockers){
- {rados::cls::lock::locker_id_t(entity, locker_cookie),
- rados::cls::lock::locker_info_t(utime_t(), entity_addr, "")}};
- reply.tag = lock_tag;
- reply.lock_type = lock_type;
- }
-
- bufferlist bl;
- ::encode(reply, bl, CEPH_FEATURES_SUPPORTED_DEFAULT);
-
- std::string str(bl.c_str(), bl.length());
- expect.WillOnce(DoAll(WithArg<5>(CopyInBufferlist(str)), Return(0)));
- }
- }
-
- void expect_list_watchers(MockTestImageCtx &mock_image_ctx, int r,
- const std::string &address, uint64_t watch_handle) {
- auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- list_watchers(mock_image_ctx.header_oid, _));
- if (r < 0) {
- expect.WillOnce(Return(r));
- } else {
- obj_watch_t watcher;
- strcpy(watcher.addr, (address + ":0/0").c_str());
- watcher.cookie = watch_handle;
-
- std::list<obj_watch_t> watchers;
- watchers.push_back(watcher);
-
- expect.WillOnce(DoAll(SetArgPointee<1>(watchers), Return(0)));
- }
- }
-
- void expect_blacklist_add(MockTestImageCtx &mock_image_ctx, int r) {
- EXPECT_CALL(get_mock_rados_client(), blacklist_add(_, _))
- .WillOnce(Return(r));
- }
-
- void expect_break_lock(MockTestImageCtx &mock_image_ctx, int r) {
- EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("lock"), StrEq("break_lock"), _, _, _))
- .WillOnce(Return(r));
- }
-
- void expect_flush_notifies(MockTestImageCtx &mock_image_ctx) {
- EXPECT_CALL(*mock_image_ctx.image_watcher, flush(_))
- .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
- }
-
- void expect_prepare_lock(MockTestImageCtx &mock_image_ctx) {
- EXPECT_CALL(*mock_image_ctx.state, prepare_lock(_))
- .WillOnce(Invoke([](Context *on_ready) {
- on_ready->complete(0);
- }));
- }
-
- void expect_handle_prepare_lock_complete(MockTestImageCtx &mock_image_ctx) {
- EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
- }
-
-};
-
-TEST_F(TestMockExclusiveLockAcquireRequest, Success) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, 0);
- expect_is_refresh_required(mock_image_ctx, false);
-
- MockObjectMap mock_object_map;
- expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, true);
- expect_create_object_map(mock_image_ctx, &mock_object_map);
- expect_open_object_map(mock_image_ctx, mock_object_map, 0);
-
- MockJournal mock_journal;
- MockJournalPolicy mock_journal_policy;
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
- mock_image_ctx.snap_lock, true);
- expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
- expect_journal_disabled(mock_journal_policy, false);
- expect_create_journal(mock_image_ctx, &mock_journal);
- expect_handle_prepare_lock_complete(mock_image_ctx);
- expect_open_journal(mock_image_ctx, mock_journal, 0);
- expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
- expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
-
- C_SaferCond acquire_ctx;
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- &acquire_ctx, &ctx);
- req->send();
- ASSERT_EQ(0, acquire_ctx.wait());
- ASSERT_EQ(0, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, SuccessRefresh) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- MockRefreshRequest mock_refresh_request;
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, 0);
- expect_is_refresh_required(mock_image_ctx, true);
- expect_refresh(mock_image_ctx, mock_refresh_request, 0);
-
- MockObjectMap mock_object_map;
- expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
- mock_image_ctx.snap_lock, false);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond acquire_ctx;
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- &acquire_ctx, &ctx);
- req->send();
- ASSERT_EQ(0, acquire_ctx.wait());
- ASSERT_EQ(0, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, SuccessJournalDisabled) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, 0);
- expect_is_refresh_required(mock_image_ctx, false);
-
- MockObjectMap mock_object_map;
- expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, true);
- expect_create_object_map(mock_image_ctx, &mock_object_map);
- expect_open_object_map(mock_image_ctx, mock_object_map, 0);
-
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
- mock_image_ctx.snap_lock, false);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond acquire_ctx;
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- &acquire_ctx, &ctx);
- req->send();
- ASSERT_EQ(0, acquire_ctx.wait());
- ASSERT_EQ(0, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, SuccessObjectMapDisabled) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, 0);
- expect_is_refresh_required(mock_image_ctx, false);
-
- expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
-
- MockJournal mock_journal;
- MockJournalPolicy mock_journal_policy;
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
- mock_image_ctx.snap_lock, true);
- expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
- expect_journal_disabled(mock_journal_policy, false);
- expect_create_journal(mock_image_ctx, &mock_journal);
- expect_handle_prepare_lock_complete(mock_image_ctx);
- expect_open_journal(mock_image_ctx, mock_journal, 0);
- expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
- expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
-
- C_SaferCond acquire_ctx;
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- &acquire_ctx, &ctx);
- req->send();
- ASSERT_EQ(0, acquire_ctx.wait());
- ASSERT_EQ(0, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, RefreshError) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- MockRefreshRequest mock_refresh_request;
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, 0);
- expect_is_refresh_required(mock_image_ctx, true);
- expect_refresh(mock_image_ctx, mock_refresh_request, -EINVAL);
- expect_unlock(mock_image_ctx, 0);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond *acquire_ctx = new C_SaferCond();
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- acquire_ctx, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, RefreshLockDisabled) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- MockRefreshRequest mock_refresh_request;
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, 0);
- expect_is_refresh_required(mock_image_ctx, true);
- expect_refresh(mock_image_ctx, mock_refresh_request, -ERESTART);
-
- MockObjectMap mock_object_map;
- expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
- mock_image_ctx.snap_lock, false);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond acquire_ctx;
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- &acquire_ctx, &ctx);
- req->send();
- ASSERT_EQ(0, acquire_ctx.wait());
- ASSERT_EQ(0, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, JournalError) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, 0);
- expect_is_refresh_required(mock_image_ctx, false);
-
- MockObjectMap *mock_object_map = new MockObjectMap();
- expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, true);
- expect_create_object_map(mock_image_ctx, mock_object_map);
- expect_open_object_map(mock_image_ctx, *mock_object_map, 0);
-
- MockJournal *mock_journal = new MockJournal();
- MockJournalPolicy mock_journal_policy;
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
- mock_image_ctx.snap_lock, true);
- expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
- expect_journal_disabled(mock_journal_policy, false);
- expect_create_journal(mock_image_ctx, mock_journal);
- expect_handle_prepare_lock_complete(mock_image_ctx);
- expect_open_journal(mock_image_ctx, *mock_journal, -EINVAL);
- expect_close_journal(mock_image_ctx, *mock_journal);
- expect_close_object_map(mock_image_ctx, *mock_object_map);
- expect_unlock(mock_image_ctx, 0);
-
- C_SaferCond acquire_ctx;
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- &acquire_ctx, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, AllocateJournalTagError) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, 0);
- expect_is_refresh_required(mock_image_ctx, false);
-
- MockObjectMap *mock_object_map = new MockObjectMap();
- expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, true);
- expect_create_object_map(mock_image_ctx, mock_object_map);
- expect_open_object_map(mock_image_ctx, *mock_object_map, 0);
-
- MockJournal *mock_journal = new MockJournal();
- MockJournalPolicy mock_journal_policy;
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
- mock_image_ctx.snap_lock, true);
- expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
- expect_journal_disabled(mock_journal_policy, false);
- expect_create_journal(mock_image_ctx, mock_journal);
- expect_handle_prepare_lock_complete(mock_image_ctx);
- expect_open_journal(mock_image_ctx, *mock_journal, 0);
- expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
- expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, -EPERM);
- expect_close_journal(mock_image_ctx, *mock_journal);
- expect_close_object_map(mock_image_ctx, *mock_object_map);
- expect_unlock(mock_image_ctx, 0);
-
- C_SaferCond acquire_ctx;
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- &acquire_ctx, &ctx);
- req->send();
- ASSERT_EQ(-EPERM, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, LockBusy) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, -EBUSY);
- expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
- "auto 123", ExclusiveLock<>::WATCHER_LOCK_TAG,
- LOCK_EXCLUSIVE);
- expect_list_watchers(mock_image_ctx, 0, "dead client", 123);
- expect_blacklist_add(mock_image_ctx, 0);
- expect_break_lock(mock_image_ctx, 0);
- expect_lock(mock_image_ctx, -ENOENT);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx);
- req->send();
- ASSERT_EQ(-ENOENT, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, GetLockInfoError) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, -EBUSY);
- expect_get_lock_info(mock_image_ctx, -EINVAL, entity_name_t::CLIENT(1), "",
- "", "", LOCK_EXCLUSIVE);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, GetLockInfoEmpty) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, -EBUSY);
- expect_get_lock_info(mock_image_ctx, -ENOENT, entity_name_t::CLIENT(1), "",
- "", "", LOCK_EXCLUSIVE);
- expect_lock(mock_image_ctx, -EINVAL);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, GetLockInfoExternalTag) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, -EBUSY);
- expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
- "auto 123", "external tag", LOCK_EXCLUSIVE);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx);
- req->send();
- ASSERT_EQ(-EBUSY, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, GetLockInfoShared) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, -EBUSY);
- expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
- "auto 123", ExclusiveLock<>::WATCHER_LOCK_TAG,
- LOCK_SHARED);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx);
- req->send();
- ASSERT_EQ(-EBUSY, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, GetLockInfoExternalCookie) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, -EBUSY);
- expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
- "external cookie", ExclusiveLock<>::WATCHER_LOCK_TAG,
- LOCK_EXCLUSIVE);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx);
- req->send();
- ASSERT_EQ(-EBUSY, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, GetWatchersError) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, -EBUSY);
- expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
- "auto 123", ExclusiveLock<>::WATCHER_LOCK_TAG,
- LOCK_EXCLUSIVE);
- expect_list_watchers(mock_image_ctx, -EINVAL, "dead client", 123);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, GetWatchersAlive) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, -EBUSY);
- expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
- "auto 123", ExclusiveLock<>::WATCHER_LOCK_TAG,
- LOCK_EXCLUSIVE);
- expect_list_watchers(mock_image_ctx, 0, "1.2.3.4", 123);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx);
- req->send();
- ASSERT_EQ(-EAGAIN, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, BlacklistDisabled) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
- mock_image_ctx.blacklist_on_break_lock = false;
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, -EBUSY);
- expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
- "auto 123", ExclusiveLock<>::WATCHER_LOCK_TAG,
- LOCK_EXCLUSIVE);
- expect_list_watchers(mock_image_ctx, 0, "dead client", 123);
- expect_break_lock(mock_image_ctx, 0);
- expect_lock(mock_image_ctx, -ENOENT);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx);
- req->send();
- ASSERT_EQ(-ENOENT, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, BlacklistError) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, -EBUSY);
- expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
- "auto 123", ExclusiveLock<>::WATCHER_LOCK_TAG,
- LOCK_EXCLUSIVE);
- expect_list_watchers(mock_image_ctx, 0, "dead client", 123);
- expect_blacklist_add(mock_image_ctx, -EINVAL);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, BreakLockMissing) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, -EBUSY);
- expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
- "auto 123", ExclusiveLock<>::WATCHER_LOCK_TAG,
- LOCK_EXCLUSIVE);
- expect_list_watchers(mock_image_ctx, 0, "dead client", 123);
- expect_blacklist_add(mock_image_ctx, 0);
- expect_break_lock(mock_image_ctx, -ENOENT);
- expect_lock(mock_image_ctx, -EINVAL);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, BreakLockError) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, -EBUSY);
- expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
- "auto 123", ExclusiveLock<>::WATCHER_LOCK_TAG,
- LOCK_EXCLUSIVE);
- expect_list_watchers(mock_image_ctx, 0, "dead client", 123);
- expect_blacklist_add(mock_image_ctx, 0);
- expect_break_lock(mock_image_ctx, -EINVAL);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockAcquireRequest, OpenObjectMapError) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockTestImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_flush_notifies(mock_image_ctx);
- expect_lock(mock_image_ctx, 0);
- expect_is_refresh_required(mock_image_ctx, false);
-
- MockObjectMap *mock_object_map = new MockObjectMap();
- expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, true);
- expect_create_object_map(mock_image_ctx, mock_object_map);
- expect_open_object_map(mock_image_ctx, *mock_object_map, -EFBIG);
-
- MockJournal mock_journal;
- MockJournalPolicy mock_journal_policy;
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
- mock_image_ctx.snap_lock, true);
- expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
- expect_journal_disabled(mock_journal_policy, false);
- expect_create_journal(mock_image_ctx, &mock_journal);
- expect_handle_prepare_lock_complete(mock_image_ctx);
- expect_open_journal(mock_image_ctx, mock_journal, 0);
- expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
- expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
-
- C_SaferCond acquire_ctx;
- C_SaferCond ctx;
- MockAcquireRequest *req = MockAcquireRequest::create(mock_image_ctx,
- TEST_COOKIE,
- &acquire_ctx, &ctx);
- req->send();
- ASSERT_EQ(0, acquire_ctx.wait());
- ASSERT_EQ(0, ctx.wait());
- ASSERT_EQ(nullptr, mock_image_ctx.object_map);
-}
-
-} // namespace exclusive_lock
-} // namespace librbd
--- /dev/null
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/librbd/test_mock_fixture.h"
+#include "test/librbd/test_support.h"
+#include "test/librbd/mock/MockImageCtx.h"
+#include "test/librbd/mock/MockImageState.h"
+#include "test/librbd/mock/MockJournal.h"
+#include "test/librbd/mock/MockJournalPolicy.h"
+#include "test/librbd/mock/MockObjectMap.h"
+#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
+#include "test/librados_test_stub/MockTestMemRadosClient.h"
+#include "librbd/exclusive_lock/PostAcquireRequest.h"
+#include "librbd/image/RefreshRequest.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <arpa/inet.h>
+#include <list>
+
+namespace librbd {
+namespace {
+
+struct MockTestImageCtx : public librbd::MockImageCtx {
+ MockTestImageCtx(librbd::ImageCtx &image_ctx)
+ : librbd::MockImageCtx(image_ctx) {
+ }
+};
+
+inline ImageCtx &get_image_ctx(MockTestImageCtx &image_ctx) {
+ return *(image_ctx.image_ctx);
+}
+
+} // anonymous namespace
+
+namespace image {
+
+template<>
+struct RefreshRequest<librbd::MockTestImageCtx> {
+ static RefreshRequest *s_instance;
+ Context *on_finish;
+
+ static RefreshRequest *create(librbd::MockTestImageCtx &image_ctx,
+ bool acquire_lock_refresh,
+ Context *on_finish) {
+ EXPECT_TRUE(acquire_lock_refresh);
+ assert(s_instance != nullptr);
+ s_instance->on_finish = on_finish;
+ return s_instance;
+ }
+
+ RefreshRequest() {
+ s_instance = this;
+ }
+ MOCK_METHOD0(send, void());
+};
+
+RefreshRequest<librbd::MockTestImageCtx> *RefreshRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+
+} // namespace image
+} // namespace librbd
+
+// template definitions
+#include "librbd/Journal.cc"
+
+#include "librbd/exclusive_lock/PostAcquireRequest.cc"
+template class librbd::exclusive_lock::PostAcquireRequest<librbd::MockTestImageCtx>;
+
+ACTION_P3(FinishRequest2, request, r, mock) {
+ mock->image_ctx->op_work_queue->queue(request->on_finish, r);
+}
+
+
+namespace librbd {
+namespace exclusive_lock {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::StrEq;
+using ::testing::WithArg;
+
+static const std::string TEST_COOKIE("auto 123");
+
+class TestMockExclusiveLockPostAcquireRequest : public TestMockFixture {
+public:
+ typedef PostAcquireRequest<MockTestImageCtx> MockPostAcquireRequest;
+ typedef librbd::image::RefreshRequest<MockTestImageCtx> MockRefreshRequest;
+
+ void expect_test_features(MockTestImageCtx &mock_image_ctx, uint64_t features,
+ bool enabled) {
+ EXPECT_CALL(mock_image_ctx, test_features(features))
+ .WillOnce(Return(enabled));
+ }
+
+ void expect_test_features(MockTestImageCtx &mock_image_ctx, uint64_t features,
+ RWLock &lock, bool enabled) {
+ EXPECT_CALL(mock_image_ctx, test_features(features, _))
+ .WillOnce(Return(enabled));
+ }
+
+ void expect_is_refresh_required(MockTestImageCtx &mock_image_ctx, bool required) {
+ EXPECT_CALL(*mock_image_ctx.state, is_refresh_required())
+ .WillOnce(Return(required));
+ }
+
+ void expect_refresh(MockTestImageCtx &mock_image_ctx,
+ MockRefreshRequest &mock_refresh_request, int r) {
+ EXPECT_CALL(mock_refresh_request, send())
+ .WillOnce(FinishRequest2(&mock_refresh_request, r,
+ &mock_image_ctx));
+ }
+
+ void expect_create_object_map(MockTestImageCtx &mock_image_ctx,
+ MockObjectMap *mock_object_map) {
+ EXPECT_CALL(mock_image_ctx, create_object_map(_))
+ .WillOnce(Return(mock_object_map));
+ }
+
+ void expect_open_object_map(MockTestImageCtx &mock_image_ctx,
+ MockObjectMap &mock_object_map, int r) {
+ EXPECT_CALL(mock_object_map, open(_))
+ .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
+ void expect_close_object_map(MockTestImageCtx &mock_image_ctx,
+ MockObjectMap &mock_object_map) {
+ EXPECT_CALL(mock_object_map, close(_))
+ .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
+ void expect_create_journal(MockTestImageCtx &mock_image_ctx,
+ MockJournal *mock_journal) {
+ EXPECT_CALL(mock_image_ctx, create_journal())
+ .WillOnce(Return(mock_journal));
+ }
+
+ void expect_open_journal(MockTestImageCtx &mock_image_ctx,
+ MockJournal &mock_journal, int r) {
+ EXPECT_CALL(mock_journal, open(_))
+ .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
+ void expect_close_journal(MockTestImageCtx &mock_image_ctx,
+ MockJournal &mock_journal) {
+ EXPECT_CALL(mock_journal, close(_))
+ .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
+ void expect_get_journal_policy(MockTestImageCtx &mock_image_ctx,
+ MockJournalPolicy &mock_journal_policy) {
+ EXPECT_CALL(mock_image_ctx, get_journal_policy())
+ .WillOnce(Return(&mock_journal_policy));
+ }
+
+ void expect_journal_disabled(MockJournalPolicy &mock_journal_policy,
+ bool disabled) {
+ EXPECT_CALL(mock_journal_policy, journal_disabled())
+ .WillOnce(Return(disabled));
+ }
+
+ void expect_allocate_journal_tag(MockTestImageCtx &mock_image_ctx,
+ MockJournalPolicy &mock_journal_policy,
+ int r) {
+ EXPECT_CALL(mock_journal_policy, allocate_tag_on_lock(_))
+ .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
+ void expect_handle_prepare_lock_complete(MockTestImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
+ }
+
+};
+
+TEST_F(TestMockExclusiveLockPostAcquireRequest, Success) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_is_refresh_required(mock_image_ctx, false);
+
+ MockObjectMap mock_object_map;
+ expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, true);
+ expect_create_object_map(mock_image_ctx, &mock_object_map);
+ expect_open_object_map(mock_image_ctx, mock_object_map, 0);
+
+ MockJournal mock_journal;
+ MockJournalPolicy mock_journal_policy;
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, true);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_journal_disabled(mock_journal_policy, false);
+ expect_create_journal(mock_image_ctx, &mock_journal);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
+ expect_open_journal(mock_image_ctx, mock_journal, 0);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
+
+ C_SaferCond acquire_ctx;
+ C_SaferCond ctx;
+ MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
+ &acquire_ctx,
+ &ctx);
+ req->send();
+ ASSERT_EQ(0, acquire_ctx.wait());
+ ASSERT_EQ(0, ctx.wait());
+ }
+
+TEST_F(TestMockExclusiveLockPostAcquireRequest, SuccessRefresh) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ MockRefreshRequest mock_refresh_request;
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_is_refresh_required(mock_image_ctx, true);
+ expect_refresh(mock_image_ctx, mock_refresh_request, 0);
+
+ MockObjectMap mock_object_map;
+ expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, false);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
+
+ C_SaferCond acquire_ctx;
+ C_SaferCond ctx;
+ MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
+ &acquire_ctx,
+ &ctx);
+ req->send();
+ ASSERT_EQ(0, acquire_ctx.wait());
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockPostAcquireRequest, SuccessJournalDisabled) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_is_refresh_required(mock_image_ctx, false);
+
+ MockObjectMap mock_object_map;
+ expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, true);
+ expect_create_object_map(mock_image_ctx, &mock_object_map);
+ expect_open_object_map(mock_image_ctx, mock_object_map, 0);
+
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, false);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
+
+ C_SaferCond acquire_ctx;
+ C_SaferCond ctx;
+ MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
+ &acquire_ctx,
+ &ctx);
+ req->send();
+ ASSERT_EQ(0, acquire_ctx.wait());
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockPostAcquireRequest, SuccessObjectMapDisabled) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_is_refresh_required(mock_image_ctx, false);
+
+ expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
+
+ MockJournal mock_journal;
+ MockJournalPolicy mock_journal_policy;
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, true);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_journal_disabled(mock_journal_policy, false);
+ expect_create_journal(mock_image_ctx, &mock_journal);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
+ expect_open_journal(mock_image_ctx, mock_journal, 0);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
+
+ C_SaferCond acquire_ctx;
+ C_SaferCond ctx;
+ MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
+ &acquire_ctx,
+ &ctx);
+ req->send();
+ ASSERT_EQ(0, acquire_ctx.wait());
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockPostAcquireRequest, RefreshError) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ MockRefreshRequest mock_refresh_request;
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_is_refresh_required(mock_image_ctx, true);
+ expect_refresh(mock_image_ctx, mock_refresh_request, -EINVAL);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
+
+ C_SaferCond *acquire_ctx = new C_SaferCond();
+ C_SaferCond ctx;
+ MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
+ acquire_ctx,
+ &ctx);
+ req->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockPostAcquireRequest, RefreshLockDisabled) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ MockRefreshRequest mock_refresh_request;
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_is_refresh_required(mock_image_ctx, true);
+ expect_refresh(mock_image_ctx, mock_refresh_request, -ERESTART);
+
+ MockObjectMap mock_object_map;
+ expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, false);
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, false);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
+
+ C_SaferCond acquire_ctx;
+ C_SaferCond ctx;
+ MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
+ &acquire_ctx,
+ &ctx);
+ req->send();
+ ASSERT_EQ(0, acquire_ctx.wait());
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockPostAcquireRequest, JournalError) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_is_refresh_required(mock_image_ctx, false);
+
+ MockObjectMap *mock_object_map = new MockObjectMap();
+ expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, true);
+ expect_create_object_map(mock_image_ctx, mock_object_map);
+ expect_open_object_map(mock_image_ctx, *mock_object_map, 0);
+
+ MockJournal *mock_journal = new MockJournal();
+ MockJournalPolicy mock_journal_policy;
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, true);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_journal_disabled(mock_journal_policy, false);
+ expect_create_journal(mock_image_ctx, mock_journal);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
+ expect_open_journal(mock_image_ctx, *mock_journal, -EINVAL);
+ expect_close_journal(mock_image_ctx, *mock_journal);
+ expect_close_object_map(mock_image_ctx, *mock_object_map);
+
+ C_SaferCond acquire_ctx;
+ C_SaferCond ctx;
+ MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
+ &acquire_ctx,
+ &ctx);
+ req->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockPostAcquireRequest, AllocateJournalTagError) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_is_refresh_required(mock_image_ctx, false);
+
+ MockObjectMap *mock_object_map = new MockObjectMap();
+ expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, true);
+ expect_create_object_map(mock_image_ctx, mock_object_map);
+ expect_open_object_map(mock_image_ctx, *mock_object_map, 0);
+
+ MockJournal *mock_journal = new MockJournal();
+ MockJournalPolicy mock_journal_policy;
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, true);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_journal_disabled(mock_journal_policy, false);
+ expect_create_journal(mock_image_ctx, mock_journal);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
+ expect_open_journal(mock_image_ctx, *mock_journal, 0);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, -EPERM);
+ expect_close_journal(mock_image_ctx, *mock_journal);
+ expect_close_object_map(mock_image_ctx, *mock_object_map);
+
+ C_SaferCond acquire_ctx;
+ C_SaferCond ctx;
+ MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
+ &acquire_ctx,
+ &ctx);
+ req->send();
+ ASSERT_EQ(-EPERM, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockPostAcquireRequest, OpenObjectMapError) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_is_refresh_required(mock_image_ctx, false);
+
+ MockObjectMap *mock_object_map = new MockObjectMap();
+ expect_test_features(mock_image_ctx, RBD_FEATURE_OBJECT_MAP, true);
+ expect_create_object_map(mock_image_ctx, mock_object_map);
+ expect_open_object_map(mock_image_ctx, *mock_object_map, -EFBIG);
+
+ MockJournal mock_journal;
+ MockJournalPolicy mock_journal_policy;
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ mock_image_ctx.snap_lock, true);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_journal_disabled(mock_journal_policy, false);
+ expect_create_journal(mock_image_ctx, &mock_journal);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
+ expect_open_journal(mock_image_ctx, mock_journal, 0);
+ expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
+ expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
+
+ C_SaferCond acquire_ctx;
+ C_SaferCond ctx;
+ MockPostAcquireRequest *req = MockPostAcquireRequest::create(mock_image_ctx,
+ &acquire_ctx,
+ &ctx);
+ req->send();
+ ASSERT_EQ(0, acquire_ctx.wait());
+ ASSERT_EQ(0, ctx.wait());
+ ASSERT_EQ(nullptr, mock_image_ctx.object_map);
+}
+
+} // namespace exclusive_lock
+} // namespace librbd
--- /dev/null
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/librbd/test_mock_fixture.h"
+#include "test/librbd/test_support.h"
+#include "test/librbd/mock/MockImageCtx.h"
+#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
+#include "test/librados_test_stub/MockTestMemRadosClient.h"
+#include "librbd/exclusive_lock/PreAcquireRequest.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <arpa/inet.h>
+#include <list>
+
+namespace librbd {
+namespace {
+
+struct MockTestImageCtx : public librbd::MockImageCtx {
+ MockTestImageCtx(librbd::ImageCtx &image_ctx)
+ : librbd::MockImageCtx(image_ctx) {
+ }
+};
+
+inline ImageCtx &get_image_ctx(MockTestImageCtx &image_ctx) {
+ return *(image_ctx.image_ctx);
+}
+
+} // anonymous namespace
+} // namespace librbd
+
+// template definitions
+#include "librbd/exclusive_lock/PreAcquireRequest.cc"
+template class librbd::exclusive_lock::PreAcquireRequest<librbd::MockTestImageCtx>;
+
+namespace librbd {
+namespace exclusive_lock {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::StrEq;
+using ::testing::WithArg;
+
+static const std::string TEST_COOKIE("auto 123");
+
+class TestMockExclusiveLockPreAcquireRequest : public TestMockFixture {
+public:
+ typedef PreAcquireRequest<MockTestImageCtx> MockPreAcquireRequest;
+
+ void expect_flush_notifies(MockTestImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.image_watcher, flush(_))
+ .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
+ void expect_prepare_lock(MockTestImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.state, prepare_lock(_))
+ .WillOnce(Invoke([](Context *on_ready) {
+ on_ready->complete(0);
+ }));
+ }
+
+ void expect_handle_prepare_lock_complete(MockTestImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
+ }
+
+};
+
+TEST_F(TestMockExclusiveLockPreAcquireRequest, Success) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
+ expect_flush_notifies(mock_image_ctx);
+
+ C_SaferCond ctx;
+ MockPreAcquireRequest *req = MockPreAcquireRequest::create(mock_image_ctx,
+ &ctx);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+ }
+
+} // namespace exclusive_lock
+} // namespace librbd
--- /dev/null
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/librbd/test_mock_fixture.h"
+#include "test/librbd/test_support.h"
+#include "test/librbd/mock/MockImageCtx.h"
+#include "test/librbd/mock/MockJournal.h"
+#include "test/librbd/mock/MockObjectMap.h"
+#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
+#include "librbd/exclusive_lock/PreReleaseRequest.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <list>
+
+// template definitions
+#include "librbd/exclusive_lock/PreReleaseRequest.cc"
+template class librbd::exclusive_lock::PreReleaseRequest<librbd::MockImageCtx>;
+
+namespace librbd {
+
+using librbd::ManagedLock;
+
+namespace exclusive_lock {
+
+namespace {
+
+struct MockContext : public Context {
+ MOCK_METHOD1(complete, void(int));
+ MOCK_METHOD1(finish, void(int));
+};
+
+} // anonymous namespace
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::StrEq;
+
+static const std::string TEST_COOKIE("auto 123");
+
+class TestMockExclusiveLockPreReleaseRequest : public TestMockFixture {
+public:
+ typedef PreReleaseRequest<MockImageCtx> MockPreReleaseRequest;
+
+ void expect_complete_context(MockContext &mock_context, int r) {
+ EXPECT_CALL(mock_context, complete(r));
+ }
+
+ void expect_test_features(MockImageCtx &mock_image_ctx, uint64_t features,
+ bool enabled) {
+ EXPECT_CALL(mock_image_ctx, test_features(features))
+ .WillOnce(Return(enabled));
+ }
+
+ void expect_set_require_lock_on_read(MockImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.aio_work_queue, set_require_lock_on_read());
+ }
+
+ void expect_block_writes(MockImageCtx &mock_image_ctx, int r) {
+ expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
+ ((mock_image_ctx.features & RBD_FEATURE_JOURNALING) != 0));
+ if ((mock_image_ctx.features & RBD_FEATURE_JOURNALING) != 0) {
+ expect_set_require_lock_on_read(mock_image_ctx);
+ }
+ EXPECT_CALL(*mock_image_ctx.aio_work_queue, block_writes(_))
+ .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
+ void expect_unblock_writes(MockImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.aio_work_queue, unblock_writes());
+ }
+
+ void expect_cancel_op_requests(MockImageCtx &mock_image_ctx, int r) {
+ EXPECT_CALL(mock_image_ctx, cancel_async_requests(_))
+ .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
+ void expect_close_journal(MockImageCtx &mock_image_ctx,
+ MockJournal &mock_journal, int r) {
+ EXPECT_CALL(mock_journal, close(_))
+ .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
+ void expect_close_object_map(MockImageCtx &mock_image_ctx,
+ MockObjectMap &mock_object_map) {
+ EXPECT_CALL(mock_object_map, close(_))
+ .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
+ void expect_flush_notifies(MockImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.image_watcher, flush(_))
+ .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
+ void expect_prepare_lock(MockImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.state, prepare_lock(_))
+ .WillOnce(Invoke([](Context *on_ready) {
+ on_ready->complete(0);
+ }));
+ }
+
+ void expect_handle_prepare_lock_complete(MockImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
+ }
+
+};
+
+TEST_F(TestMockExclusiveLockPreReleaseRequest, Success) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockImageCtx mock_image_ctx(*ictx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+
+ expect_prepare_lock(mock_image_ctx);
+ expect_cancel_op_requests(mock_image_ctx, 0);
+ expect_block_writes(mock_image_ctx, 0);
+ expect_flush_notifies(mock_image_ctx);
+
+ MockJournal *mock_journal = new MockJournal();
+ mock_image_ctx.journal = mock_journal;
+ expect_close_journal(mock_image_ctx, *mock_journal, -EINVAL);
+
+ MockObjectMap *mock_object_map = new MockObjectMap();
+ mock_image_ctx.object_map = mock_object_map;
+ expect_close_object_map(mock_image_ctx, *mock_object_map);
+
+ MockContext mock_releasing_ctx;
+ expect_complete_context(mock_releasing_ctx, 0);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
+
+ C_SaferCond ctx;
+ MockPreReleaseRequest *req = MockPreReleaseRequest::create(mock_image_ctx,
+ &mock_releasing_ctx,
+ &ctx, false);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockPreReleaseRequest, SuccessJournalDisabled) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockImageCtx mock_image_ctx(*ictx);
+
+ expect_block_writes(mock_image_ctx, 0);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
+ expect_cancel_op_requests(mock_image_ctx, 0);
+ expect_flush_notifies(mock_image_ctx);
+
+ MockObjectMap *mock_object_map = new MockObjectMap();
+ mock_image_ctx.object_map = mock_object_map;
+ expect_close_object_map(mock_image_ctx, *mock_object_map);
+
+ expect_handle_prepare_lock_complete(mock_image_ctx);
+
+ C_SaferCond release_ctx;
+ C_SaferCond ctx;
+ MockPreReleaseRequest *req = MockPreReleaseRequest::create(mock_image_ctx,
+ &release_ctx, &ctx,
+ false);
+ req->send();
+ ASSERT_EQ(0, release_ctx.wait());
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockPreReleaseRequest, SuccessObjectMapDisabled) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockImageCtx mock_image_ctx(*ictx);
+
+ expect_block_writes(mock_image_ctx, 0);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_cancel_op_requests(mock_image_ctx, 0);
+ expect_flush_notifies(mock_image_ctx);
+
+ C_SaferCond release_ctx;
+ C_SaferCond ctx;
+ MockPreReleaseRequest *req = MockPreReleaseRequest::create(mock_image_ctx,
+ &release_ctx, &ctx,
+ true);
+ req->send();
+ ASSERT_EQ(0, release_ctx.wait());
+ ASSERT_EQ(0, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockPreReleaseRequest, BlockWritesError) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockImageCtx mock_image_ctx(*ictx);
+
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_cancel_op_requests(mock_image_ctx, 0);
+ expect_block_writes(mock_image_ctx, -EINVAL);
+ expect_unblock_writes(mock_image_ctx);
+
+ C_SaferCond ctx;
+ MockPreReleaseRequest *req = MockPreReleaseRequest::create(mock_image_ctx,
+ nullptr, &ctx,
+ true);
+ req->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
+TEST_F(TestMockExclusiveLockPreReleaseRequest, UnlockError) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockImageCtx mock_image_ctx(*ictx);
+
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_cancel_op_requests(mock_image_ctx, 0);
+ expect_block_writes(mock_image_ctx, 0);
+ expect_flush_notifies(mock_image_ctx);
+
+ C_SaferCond ctx;
+ MockPreReleaseRequest *req = MockPreReleaseRequest::create(mock_image_ctx,
+ nullptr, &ctx,
+ true);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+}
+
+} // namespace exclusive_lock
+} // namespace librbd
+++ /dev/null
-// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "test/librbd/test_mock_fixture.h"
-#include "test/librbd/test_support.h"
-#include "test/librbd/mock/MockImageCtx.h"
-#include "test/librbd/mock/MockImageState.h"
-#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
-#include "test/librados_test_stub/MockTestMemRadosClient.h"
-#include "cls/lock/cls_lock_ops.h"
-#include "librbd/ExclusiveLock.h"
-#include "librbd/exclusive_lock/ReacquireRequest.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include <arpa/inet.h>
-#include <list>
-
-// template definitions
-#include "librbd/exclusive_lock/ReacquireRequest.cc"
-template class librbd::exclusive_lock::ReacquireRequest<librbd::MockImageCtx>;
-
-namespace librbd {
-namespace exclusive_lock {
-
-using ::testing::_;
-using ::testing::InSequence;
-using ::testing::Return;
-using ::testing::StrEq;
-
-class TestMockExclusiveLockReacquireRequest : public TestMockFixture {
-public:
- typedef ReacquireRequest<MockImageCtx> MockReacquireRequest;
- typedef ExclusiveLock<MockImageCtx> MockExclusiveLock;
-
- void expect_set_cookie(MockImageCtx &mock_image_ctx, int r) {
- EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("lock"),
- StrEq("set_cookie"), _, _, _))
- .WillOnce(Return(r));
- }
-};
-
-TEST_F(TestMockExclusiveLockReacquireRequest, Success) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockImageCtx mock_image_ctx(*ictx);
-
- InSequence seq;
- expect_set_cookie(mock_image_ctx, 0);
-
- C_SaferCond ctx;
- MockReacquireRequest *req = MockReacquireRequest::create(mock_image_ctx,
- "old cookie",
- "new cookie", &ctx);
- req->send();
- ASSERT_EQ(0, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockReacquireRequest, NotSupported) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockImageCtx mock_image_ctx(*ictx);
-
- InSequence seq;
- expect_set_cookie(mock_image_ctx, -EOPNOTSUPP);
-
- C_SaferCond ctx;
- MockReacquireRequest *req = MockReacquireRequest::create(mock_image_ctx,
- "old cookie",
- "new cookie", &ctx);
- req->send();
- ASSERT_EQ(-EOPNOTSUPP, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockReacquireRequest, Error) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockImageCtx mock_image_ctx(*ictx);
-
- InSequence seq;
- expect_set_cookie(mock_image_ctx, -EBUSY);
-
- C_SaferCond ctx;
- MockReacquireRequest *req = MockReacquireRequest::create(mock_image_ctx,
- "old cookie",
- "new cookie", &ctx);
- req->send();
- ASSERT_EQ(-EBUSY, ctx.wait());
-}
-
-} // namespace exclusive_lock
-} // namespace librbd
+++ /dev/null
-// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "test/librbd/test_mock_fixture.h"
-#include "test/librbd/test_support.h"
-#include "test/librbd/mock/MockImageCtx.h"
-#include "test/librbd/mock/MockJournal.h"
-#include "test/librbd/mock/MockObjectMap.h"
-#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
-#include "librbd/exclusive_lock/ReleaseRequest.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include <list>
-
-// template definitions
-#include "librbd/exclusive_lock/ReleaseRequest.cc"
-template class librbd::exclusive_lock::ReleaseRequest<librbd::MockImageCtx>;
-
-namespace librbd {
-namespace exclusive_lock {
-
-namespace {
-
-struct MockContext : public Context {
- MOCK_METHOD1(complete, void(int));
- MOCK_METHOD1(finish, void(int));
-};
-
-} // anonymous namespace
-
-using ::testing::_;
-using ::testing::InSequence;
-using ::testing::Invoke;
-using ::testing::Return;
-using ::testing::StrEq;
-
-static const std::string TEST_COOKIE("auto 123");
-
-class TestMockExclusiveLockReleaseRequest : public TestMockFixture {
-public:
- typedef ReleaseRequest<MockImageCtx> MockReleaseRequest;
-
- void expect_complete_context(MockContext &mock_context, int r) {
- EXPECT_CALL(mock_context, complete(r));
- }
-
- void expect_test_features(MockImageCtx &mock_image_ctx, uint64_t features,
- bool enabled) {
- EXPECT_CALL(mock_image_ctx, test_features(features))
- .WillOnce(Return(enabled));
- }
-
- void expect_set_require_lock_on_read(MockImageCtx &mock_image_ctx) {
- EXPECT_CALL(*mock_image_ctx.aio_work_queue, set_require_lock_on_read());
- }
-
- void expect_block_writes(MockImageCtx &mock_image_ctx, int r) {
- expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING,
- ((mock_image_ctx.features & RBD_FEATURE_JOURNALING) != 0));
- if ((mock_image_ctx.features & RBD_FEATURE_JOURNALING) != 0) {
- expect_set_require_lock_on_read(mock_image_ctx);
- }
- EXPECT_CALL(*mock_image_ctx.aio_work_queue, block_writes(_))
- .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
- }
-
- void expect_unblock_writes(MockImageCtx &mock_image_ctx) {
- EXPECT_CALL(*mock_image_ctx.aio_work_queue, unblock_writes());
- }
-
- void expect_cancel_op_requests(MockImageCtx &mock_image_ctx, int r) {
- EXPECT_CALL(mock_image_ctx, cancel_async_requests(_))
- .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
- }
-
- void expect_unlock(MockImageCtx &mock_image_ctx, int r) {
- EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("lock"), StrEq("unlock"), _, _, _))
- .WillOnce(Return(r));
- }
-
- void expect_close_journal(MockImageCtx &mock_image_ctx,
- MockJournal &mock_journal, int r) {
- EXPECT_CALL(mock_journal, close(_))
- .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
- }
-
- void expect_close_object_map(MockImageCtx &mock_image_ctx,
- MockObjectMap &mock_object_map) {
- EXPECT_CALL(mock_object_map, close(_))
- .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
- }
-
- void expect_flush_notifies(MockImageCtx &mock_image_ctx) {
- EXPECT_CALL(*mock_image_ctx.image_watcher, flush(_))
- .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
- }
-
- void expect_prepare_lock(MockImageCtx &mock_image_ctx) {
- EXPECT_CALL(*mock_image_ctx.state, prepare_lock(_))
- .WillOnce(Invoke([](Context *on_ready) {
- on_ready->complete(0);
- }));
- }
-
- void expect_handle_prepare_lock_complete(MockImageCtx &mock_image_ctx) {
- EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
- }
-
-};
-
-TEST_F(TestMockExclusiveLockReleaseRequest, Success) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_cancel_op_requests(mock_image_ctx, 0);
- expect_block_writes(mock_image_ctx, 0);
- expect_flush_notifies(mock_image_ctx);
-
- MockJournal *mock_journal = new MockJournal();
- mock_image_ctx.journal = mock_journal;
- expect_close_journal(mock_image_ctx, *mock_journal, -EINVAL);
-
- MockObjectMap *mock_object_map = new MockObjectMap();
- mock_image_ctx.object_map = mock_object_map;
- expect_close_object_map(mock_image_ctx, *mock_object_map);
-
- MockContext mock_releasing_ctx;
- expect_complete_context(mock_releasing_ctx, 0);
- expect_unlock(mock_image_ctx, 0);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond ctx;
- MockReleaseRequest *req = MockReleaseRequest::create(mock_image_ctx,
- TEST_COOKIE,
- &mock_releasing_ctx,
- &ctx, false);
- req->send();
- ASSERT_EQ(0, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockReleaseRequest, SuccessJournalDisabled) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockImageCtx mock_image_ctx(*ictx);
- expect_block_writes(mock_image_ctx, 0);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_prepare_lock(mock_image_ctx);
- expect_cancel_op_requests(mock_image_ctx, 0);
- expect_flush_notifies(mock_image_ctx);
-
- MockObjectMap *mock_object_map = new MockObjectMap();
- mock_image_ctx.object_map = mock_object_map;
- expect_close_object_map(mock_image_ctx, *mock_object_map);
-
- expect_unlock(mock_image_ctx, 0);
- expect_handle_prepare_lock_complete(mock_image_ctx);
-
- C_SaferCond release_ctx;
- C_SaferCond ctx;
- MockReleaseRequest *req = MockReleaseRequest::create(mock_image_ctx,
- TEST_COOKIE,
- &release_ctx, &ctx,
- false);
- req->send();
- ASSERT_EQ(0, release_ctx.wait());
- ASSERT_EQ(0, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockReleaseRequest, SuccessObjectMapDisabled) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockImageCtx mock_image_ctx(*ictx);
- expect_block_writes(mock_image_ctx, 0);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_cancel_op_requests(mock_image_ctx, 0);
- expect_flush_notifies(mock_image_ctx);
-
- expect_unlock(mock_image_ctx, 0);
-
- C_SaferCond release_ctx;
- C_SaferCond ctx;
- MockReleaseRequest *req = MockReleaseRequest::create(mock_image_ctx,
- TEST_COOKIE,
- &release_ctx, &ctx,
- true);
- req->send();
- ASSERT_EQ(0, release_ctx.wait());
- ASSERT_EQ(0, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockReleaseRequest, BlockWritesError) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_cancel_op_requests(mock_image_ctx, 0);
- expect_block_writes(mock_image_ctx, -EINVAL);
- expect_unblock_writes(mock_image_ctx);
-
- C_SaferCond ctx;
- MockReleaseRequest *req = MockReleaseRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx,
- true);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockExclusiveLockReleaseRequest, UnlockError) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- MockImageCtx mock_image_ctx(*ictx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_cancel_op_requests(mock_image_ctx, 0);
- expect_block_writes(mock_image_ctx, 0);
- expect_flush_notifies(mock_image_ctx);
-
- expect_unlock(mock_image_ctx, -EINVAL);
-
- C_SaferCond ctx;
- MockReleaseRequest *req = MockReleaseRequest::create(mock_image_ctx,
- TEST_COOKIE,
- nullptr, &ctx,
- true);
- req->send();
- ASSERT_EQ(0, ctx.wait());
-}
-
-} // namespace exclusive_lock
-} // namespace librbd
C_SaferCond lock_ctx;
{
RWLock::WLocker owner_locker(ictx->owner_lock);
- ictx->exclusive_lock->request_lock(&lock_ctx);
+ ictx->exclusive_lock->acquire_lock(&lock_ctx);
}
int r = lock_ctx.wait();
if (r < 0) {
MOCK_METHOD1(block_requests, void(int));
MOCK_METHOD0(unblock_requests, void());
- MOCK_METHOD1(request_lock, void(Context *));
+ MOCK_METHOD1(acquire_lock, void(Context *));
MOCK_METHOD1(release_lock, void(Context *));
};
}
};
-TEST_F(TestImageWatcher, NotifyRequestLock) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- ASSERT_EQ(0, register_image_watch(*ictx));
-
- m_notify_acks = {{NOTIFY_OP_REQUEST_LOCK, {}}};
- ictx->image_watcher->notify_request_lock();
-
- C_SaferCond ctx;
- ictx->image_watcher->flush(&ctx);
- ctx.wait();
-
- ASSERT_TRUE(wait_for_notifies(*ictx));
-
- NotifyOps expected_notify_ops;
- expected_notify_ops += NOTIFY_OP_REQUEST_LOCK;
- ASSERT_EQ(expected_notify_ops, m_notifies);
-}
-
-TEST_F(TestImageWatcher, NotifyReleasedLock) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- ASSERT_EQ(0, register_image_watch(*ictx));
-
- m_notify_acks = {{NOTIFY_OP_RELEASED_LOCK, {}}};
- ictx->image_watcher->notify_released_lock();
-
- ASSERT_TRUE(wait_for_notifies(*ictx));
-
- NotifyOps expected_notify_ops;
- expected_notify_ops += NOTIFY_OP_RELEASED_LOCK;
- ASSERT_EQ(expected_notify_ops, m_notifies);
-}
-
-TEST_F(TestImageWatcher, NotifyAcquiredLock) {
- REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
- librbd::ImageCtx *ictx;
- ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
- ASSERT_EQ(0, register_image_watch(*ictx));
-
- m_notify_acks = {{NOTIFY_OP_ACQUIRED_LOCK, {}}};
- ictx->image_watcher->notify_acquired_lock();
-
- ASSERT_TRUE(wait_for_notifies(*ictx));
-
- NotifyOps expected_notify_ops;
- expected_notify_ops += NOTIFY_OP_ACQUIRED_LOCK;
- ASSERT_EQ(expected_notify_ops, m_notifies);
-}
-
TEST_F(TestImageWatcher, NotifyHeaderUpdate) {
REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
C_SaferCond lock_ctx;
{
RWLock::WLocker owner_locker(ictx->owner_lock);
- ictx->exclusive_lock->try_lock(&lock_ctx);
+ ictx->exclusive_lock->try_acquire_lock(&lock_ctx);
}
ASSERT_EQ(0, lock_ctx.wait());
C_SaferCond lock_ctx;
{
RWLock::WLocker owner_locker(ictx->owner_lock);
- ictx->exclusive_lock->try_lock(&lock_ctx);
+ ictx->exclusive_lock->try_acquire_lock(&lock_ctx);
}
ASSERT_EQ(0, lock_ctx.wait());
C_SaferCond lock_ctx;
{
RWLock::WLocker owner_locker(ictx->owner_lock);
- ictx->exclusive_lock->try_lock(&lock_ctx);
+ ictx->exclusive_lock->try_acquire_lock(&lock_ctx);
}
ASSERT_EQ(0, lock_ctx.wait());
C_SaferCond ctx;
{
RWLock::WLocker l(ictx->owner_lock);
- ictx->exclusive_lock->try_lock(&ctx);
+ ictx->exclusive_lock->try_acquire_lock(&ctx);
}
ASSERT_EQ(0, ctx.wait());
ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner));
C_SaferCond ctx;
{
RWLock::WLocker l(ictx->owner_lock);
- ictx->exclusive_lock->try_lock(&ctx);
+ ictx->exclusive_lock->try_acquire_lock(&ctx);
}
ASSERT_EQ(0, ctx.wait());
C_SaferCond ctx;
{
RWLock::WLocker l(ictx->owner_lock);
- ictx->exclusive_lock->try_lock(&ctx);
+ ictx->exclusive_lock->try_acquire_lock(&ctx);
}
RWLock::RLocker owner_locker(ictx->owner_lock);
#include "test/librbd/test_support.h"
#include "test/librbd/mock/MockImageCtx.h"
#include "librbd/ExclusiveLock.h"
-#include "librbd/exclusive_lock/AcquireRequest.h"
-#include "librbd/exclusive_lock/ReacquireRequest.h"
-#include "librbd/exclusive_lock/ReleaseRequest.h"
+#include "librbd/ManagedLock.h"
+#include "librbd/exclusive_lock/PreAcquireRequest.h"
+#include "librbd/exclusive_lock/PostAcquireRequest.h"
+#include "librbd/exclusive_lock/PreReleaseRequest.h"
+#include "librbd/managed_lock/AcquireRequest.h"
+#include "librbd/managed_lock/ReacquireRequest.h"
+#include "librbd/managed_lock/ReleaseRequest.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <list>
namespace {
struct MockExclusiveLockImageCtx : public MockImageCtx {
+ ContextWQ *op_work_queue;
+
MockExclusiveLockImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
+ op_work_queue = image_ctx.op_work_queue;
}
};
} // anonymous namespace
+namespace watcher {
+template <>
+struct Traits<MockExclusiveLockImageCtx> {
+ typedef librbd::MockImageWatcher Watcher;
+};
+}
+
namespace exclusive_lock {
+using librbd::ImageWatcher;
+
template<typename T>
struct BaseRequest {
static std::list<T *> s_requests;
Context *on_lock_unlock = nullptr;
Context *on_finish = nullptr;
- static T* create(MockExclusiveLockImageCtx &image_ctx, const std::string &cookie,
+ static T* create(MockExclusiveLockImageCtx &image_ctx,
Context *on_lock_unlock, Context *on_finish,
bool shutting_down = false) {
assert(!s_requests.empty());
template<typename T>
std::list<T *> BaseRequest<T>::s_requests;
+template <>
+struct PreAcquireRequest<MockExclusiveLockImageCtx> : public BaseRequest<PreAcquireRequest<MockExclusiveLockImageCtx> > {
+ static PreAcquireRequest<MockExclusiveLockImageCtx> *create(
+ MockExclusiveLockImageCtx &image_ctx, Context *on_finish) {
+ return BaseRequest::create(image_ctx, nullptr, on_finish);
+ }
+ MOCK_METHOD0(send, void());
+};
+
+template <>
+struct PostAcquireRequest<MockExclusiveLockImageCtx> : public BaseRequest<PostAcquireRequest<MockExclusiveLockImageCtx> > {
+ MOCK_METHOD0(send, void());
+};
+
+template <>
+struct PreReleaseRequest<MockExclusiveLockImageCtx> : public BaseRequest<PreReleaseRequest<MockExclusiveLockImageCtx> > {
+ MOCK_METHOD0(send, void());
+};
+
+} // namespace exclusive_lock
+
+namespace managed_lock {
+
+template<typename T>
+struct BaseRequest {
+ static std::list<T *> s_requests;
+ Context *on_finish = nullptr;
+
+ static T* create(librados::IoCtx& ioctx, MockImageWatcher *watcher,
+ ContextWQ *work_queue, const std::string& oid,
+ const std::string& cookie, Context *on_finish) {
+ assert(!s_requests.empty());
+ T* req = s_requests.front();
+ req->on_finish = on_finish;
+ s_requests.pop_front();
+ return req;
+ }
+
+ BaseRequest() {
+ s_requests.push_back(reinterpret_cast<T*>(this));
+ }
+};
+
+template<typename T>
+std::list<T *> BaseRequest<T>::s_requests;
+
template <>
struct AcquireRequest<MockExclusiveLockImageCtx> : public BaseRequest<AcquireRequest<MockExclusiveLockImageCtx> > {
MOCK_METHOD0(send, void());
template <>
struct ReacquireRequest<MockExclusiveLockImageCtx> : public BaseRequest<ReacquireRequest<MockExclusiveLockImageCtx> > {
- static ReacquireRequest* create(MockExclusiveLockImageCtx &image_ctx,
- const std::string &cookie,
- const std::string &new_cookie,
- Context *on_finish) {
- return BaseRequest::create(image_ctx, cookie, nullptr, on_finish);
+ static ReacquireRequest* create(librados::IoCtx &ioctx, const std::string& oid,
+ const string& old_cookie, const std::string& new_cookie,
+ Context *on_finish) {
+ return BaseRequest::create(ioctx, nullptr, nullptr, oid, new_cookie, on_finish);
}
MOCK_METHOD0(send, void());
MOCK_METHOD0(send, void());
};
-} // namespace exclusive_lock
+
+} // namespace managed_lock
} // namespace librbd
// template definitions
#include "librbd/ExclusiveLock.cc"
template class librbd::ExclusiveLock<librbd::MockExclusiveLockImageCtx>;
+#include "librbd/ManagedLock.cc"
+template class librbd::ManagedLock<librbd::MockExclusiveLockImageCtx>;
+
ACTION_P(FinishLockUnlock, request) {
if (request->on_lock_unlock != nullptr) {
request->on_lock_unlock->complete(0);
}
}
+ACTION_P2(CompleteRequest, request, ret) {
+ request->on_finish->complete(ret);
+}
+
namespace librbd {
using ::testing::_;
class TestMockExclusiveLock : public TestMockFixture {
public:
typedef ExclusiveLock<MockExclusiveLockImageCtx> MockExclusiveLock;
- typedef exclusive_lock::AcquireRequest<MockExclusiveLockImageCtx> MockAcquireRequest;
- typedef exclusive_lock::ReacquireRequest<MockExclusiveLockImageCtx> MockReacquireRequest;
- typedef exclusive_lock::ReleaseRequest<MockExclusiveLockImageCtx> MockReleaseRequest;
+ typedef exclusive_lock::PreAcquireRequest<MockExclusiveLockImageCtx> MockPreAcquireRequest;
+ typedef exclusive_lock::PostAcquireRequest<MockExclusiveLockImageCtx> MockPostAcquireRequest;
+ typedef exclusive_lock::PreReleaseRequest<MockExclusiveLockImageCtx> MockPreReleaseRequest;
+ typedef managed_lock::AcquireRequest<MockExclusiveLockImageCtx> MockManagedAcquireRequest;
+ typedef managed_lock::ReacquireRequest<MockExclusiveLockImageCtx> MockManagedReacquireRequest;
+ typedef managed_lock::ReleaseRequest<MockExclusiveLockImageCtx> MockManagedReleaseRequest;
void expect_get_watch_handle(MockExclusiveLockImageCtx &mock_image_ctx,
uint64_t watch_handle = 1234567890) {
EXPECT_CALL(*mock_image_ctx.image_watcher, get_watch_handle())
- .WillRepeatedly(Return(watch_handle));
+ .WillOnce(Return(watch_handle));
}
void expect_set_require_lock_on_read(MockExclusiveLockImageCtx &mock_image_ctx) {
}
void expect_acquire_lock(MockExclusiveLockImageCtx &mock_image_ctx,
- MockAcquireRequest &acquire_request, int r) {
+ MockPreAcquireRequest &pre_acquire_request,
+ MockManagedAcquireRequest &managed_acquire_request,
+ MockPostAcquireRequest *post_acquire_request,
+ int pre_r, int managed_r, int post_r) {
+
expect_get_watch_handle(mock_image_ctx);
- EXPECT_CALL(acquire_request, send())
- .WillOnce(DoAll(FinishLockUnlock(&acquire_request),
- FinishRequest(&acquire_request, r, &mock_image_ctx)));
- if (r == 0) {
+
+ EXPECT_CALL(pre_acquire_request, send())
+ .WillOnce(CompleteRequest(&pre_acquire_request, pre_r));
+ EXPECT_CALL(managed_acquire_request, send())
+ .WillOnce(CompleteRequest(&managed_acquire_request, managed_r));
+ if (managed_r == 0) {
+ assert(post_acquire_request != nullptr);
+ EXPECT_CALL(*post_acquire_request, send())
+ .WillOnce(DoAll(FinishLockUnlock(post_acquire_request),
+ CompleteRequest(post_acquire_request, post_r)));
+ }
+
+ if (pre_r == 0 && managed_r == 0 && post_r == 0) {
expect_notify_acquired_lock(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
}
}
void expect_release_lock(MockExclusiveLockImageCtx &mock_image_ctx,
- MockReleaseRequest &release_request, int r,
- bool shutting_down = false) {
- EXPECT_CALL(release_request, send())
- .WillOnce(DoAll(FinishLockUnlock(&release_request),
- FinishRequest(&release_request, r, &mock_image_ctx)));
- if (r == 0) {
+ MockPreReleaseRequest &pre_release_request,
+ MockManagedReleaseRequest &managed_release_request,
+ int pre_r, int managed_r, bool shutting_down = false) {
+ EXPECT_CALL(pre_release_request, send())
+ .WillOnce(DoAll(FinishLockUnlock(&pre_release_request),
+ CompleteRequest(&pre_release_request, pre_r)));
+ EXPECT_CALL(managed_release_request, send())
+ .WillOnce(CompleteRequest(&managed_release_request, managed_r));
+
+ if (pre_r == 0 && managed_r == 0) {
if (shutting_down) {
expect_unblock_writes(mock_image_ctx);
}
}
void expect_reacquire_lock(MockExclusiveLockImageCtx &mock_image_ctx,
- MockReacquireRequest &mock_reacquire_request,
+ MockManagedReacquireRequest &mock_reacquire_request,
int r) {
- expect_get_watch_handle(mock_image_ctx, 98765);
+ EXPECT_CALL(*mock_image_ctx.image_watcher, get_watch_handle())
+ .WillOnce(Return(98765));
EXPECT_CALL(mock_reacquire_request, send())
- .WillOnce(FinishRequest(&mock_reacquire_request, r, &mock_image_ctx));
+ .WillOnce(CompleteRequest(&mock_reacquire_request, r));
}
void expect_notify_request_lock(MockExclusiveLockImageCtx &mock_image_ctx,
void expect_notify_acquired_lock(MockExclusiveLockImageCtx &mock_image_ctx) {
EXPECT_CALL(*mock_image_ctx.image_watcher, notify_acquired_lock())
- .Times(1);
+ .Times(1);
}
void expect_notify_released_lock(MockExclusiveLockImageCtx &mock_image_ctx) {
EXPECT_CALL(*mock_image_ctx.image_watcher, notify_released_lock())
- .Times(1);
+ .Times(1);
}
void expect_is_lock_request_needed(MockExclusiveLockImageCtx &mock_image_ctx, bool ret) {
C_SaferCond ctx;
{
RWLock::WLocker owner_locker(mock_image_ctx.owner_lock);
- exclusive_lock.try_lock(&ctx);
+ exclusive_lock.try_acquire_lock(&ctx);
}
return ctx.wait();
}
C_SaferCond ctx;
{
RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
- exclusive_lock.request_lock(&ctx);
+ exclusive_lock.acquire_lock(&ctx);
}
return ctx.wait();
}
expect_block_writes(mock_image_ctx);
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
- MockAcquireRequest try_lock_acquire;
- expect_acquire_lock(mock_image_ctx, try_lock_acquire, 0);
+ MockPreAcquireRequest try_lock_pre_acquire;
+ MockManagedAcquireRequest try_lock_managed_acquire;
+ MockPostAcquireRequest try_lock_post_acquire;
+ expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire,
+ try_lock_managed_acquire, &try_lock_post_acquire, 0, 0, 0);
ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock));
ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
- MockReleaseRequest request_release;
- expect_release_lock(mock_image_ctx, request_release, 0);
+ MockPreReleaseRequest pre_request_release;
+ MockManagedReleaseRequest managed_request_release;
+ expect_release_lock(mock_image_ctx, pre_request_release,
+ managed_request_release, 0, 0);
ASSERT_EQ(0, when_release_lock(mock_image_ctx, exclusive_lock));
ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
- MockAcquireRequest request_lock_acquire;
- expect_acquire_lock(mock_image_ctx, request_lock_acquire, 0);
+ MockPreAcquireRequest request_lock_pre_acquire;
+ MockManagedAcquireRequest request_lock_managed_acquire;
+ MockPostAcquireRequest request_lock_post_acquire;
+ expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire,
+ request_lock_managed_acquire, &request_lock_post_acquire,
+ 0, 0, 0);
ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock));
ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
- MockReleaseRequest shutdown_release;
- expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
+ MockPreReleaseRequest shutdown_pre_release;
+ MockManagedReleaseRequest shutdown_managed_release;
+ expect_release_lock(mock_image_ctx, shutdown_pre_release,
+ shutdown_managed_release, 0, 0, true);
ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
}
expect_block_writes(mock_image_ctx);
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
- MockAcquireRequest try_lock_acquire;
- expect_acquire_lock(mock_image_ctx, try_lock_acquire, 0);
+ MockPreAcquireRequest try_lock_pre_acquire;
+ MockManagedAcquireRequest try_lock_managed_acquire;
+ MockPostAcquireRequest try_lock_post_acquire;
+ expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire,
+ try_lock_managed_acquire, &try_lock_post_acquire, 0, 0, 0);
ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock));
ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock));
- MockReleaseRequest shutdown_release;
- expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
+ MockPreReleaseRequest shutdown_pre_release;
+ MockManagedReleaseRequest shutdown_managed_release;
+ expect_release_lock(mock_image_ctx, shutdown_pre_release,
+ shutdown_managed_release, 0, 0, true);
ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
}
expect_block_writes(mock_image_ctx);
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
- MockAcquireRequest try_lock_acquire;
- expect_acquire_lock(mock_image_ctx, try_lock_acquire, -EAGAIN);
+ MockPreAcquireRequest try_lock_pre_acquire;
+ MockManagedAcquireRequest try_lock_managed_acquire;
+ expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire,
+ try_lock_managed_acquire, nullptr, 0, -EAGAIN, 0);
ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock));
ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
expect_block_writes(mock_image_ctx);
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
- MockAcquireRequest try_lock_acquire;
- expect_acquire_lock(mock_image_ctx, try_lock_acquire, -EBUSY);
+ MockPreAcquireRequest try_lock_pre_acquire;
+ MockManagedAcquireRequest try_lock_managed_acquire;
+ expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire,
+ try_lock_managed_acquire, nullptr, 0, -EBUSY, 0);
ASSERT_EQ(-EBUSY, when_try_lock(mock_image_ctx, exclusive_lock));
ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
InSequence seq;
expect_block_writes(mock_image_ctx);
-
- MockAcquireRequest try_lock_acquire;
- expect_acquire_lock(mock_image_ctx, try_lock_acquire, -EINVAL);
-
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
+
+ MockPreAcquireRequest try_lock_pre_acquire;
+ MockManagedAcquireRequest try_lock_managed_acquire;
+ expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire,
+ try_lock_managed_acquire, nullptr, 0, -EINVAL, 0);
ASSERT_EQ(-EINVAL, when_try_lock(mock_image_ctx, exclusive_lock));
ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
expect_block_writes(mock_image_ctx);
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
- MockAcquireRequest try_lock_acquire;
- expect_acquire_lock(mock_image_ctx, try_lock_acquire, 0);
+ MockPreAcquireRequest try_lock_pre_acquire;
+ MockManagedAcquireRequest try_lock_managed_acquire;
+ MockPostAcquireRequest try_lock_post_acquire;
+ expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire,
+ try_lock_managed_acquire, &try_lock_post_acquire, 0, 0, 0);
ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock));
-
- MockReleaseRequest shutdown_release;
- expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
+ ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock));
+ MockPreReleaseRequest shutdown_pre_release;
+ MockManagedReleaseRequest shutdown_managed_release;
+ expect_release_lock(mock_image_ctx, shutdown_pre_release,
+ shutdown_managed_release, 0, 0, true);
ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
}
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
// will abort after seeing blacklist error (avoid infinite request loop)
- MockAcquireRequest request_lock_acquire;
- expect_acquire_lock(mock_image_ctx, request_lock_acquire, -EBLACKLISTED);
- expect_notify_request_lock(mock_image_ctx, exclusive_lock);
+ MockPreAcquireRequest request_pre_acquire;
+ MockManagedAcquireRequest request_managed_acquire;
+ expect_acquire_lock(mock_image_ctx, request_pre_acquire,
+ request_managed_acquire, nullptr, 0, -EBLACKLISTED, 0);
ASSERT_EQ(-EBLACKLISTED, when_request_lock(mock_image_ctx, exclusive_lock));
ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
// will repeat until successfully acquires the lock
- MockAcquireRequest request_lock_acquire1;
- expect_acquire_lock(mock_image_ctx, request_lock_acquire1, -EBUSY);
+ MockPreAcquireRequest request_lock_pre_acquire1;
+ MockManagedAcquireRequest request_lock_managed_acquire1;
+ expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire1,
+ request_lock_managed_acquire1, nullptr, 0, -EBUSY, 0);
expect_notify_request_lock(mock_image_ctx, exclusive_lock);
- MockAcquireRequest request_lock_acquire2;
- expect_acquire_lock(mock_image_ctx, request_lock_acquire2, 0);
+ MockPreAcquireRequest request_lock_pre_acquire2;
+ MockManagedAcquireRequest request_lock_managed_acquire2;
+ MockPostAcquireRequest request_lock_post_acquire2;
+ expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire2,
+ request_lock_managed_acquire2,
+ &request_lock_post_acquire2, 0, 0, 0);
ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock));
ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
- MockReleaseRequest shutdown_release;
- expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
+ MockPreReleaseRequest shutdown_pre_release;
+ MockManagedReleaseRequest shutdown_managed_release;
+ expect_release_lock(mock_image_ctx, shutdown_pre_release,
+ shutdown_managed_release, 0, 0, true);
ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
}
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
// will repeat until successfully acquires the lock
- MockAcquireRequest request_lock_acquire1;
- expect_acquire_lock(mock_image_ctx, request_lock_acquire1, -EINVAL);
+ MockPreAcquireRequest request_lock_pre_acquire1;
+ MockManagedAcquireRequest request_lock_managed_acquire1;
+ expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire1,
+ request_lock_managed_acquire1, nullptr, 0, -EINVAL, 0);
expect_notify_request_lock(mock_image_ctx, exclusive_lock);
- MockAcquireRequest request_lock_acquire2;
- expect_acquire_lock(mock_image_ctx, request_lock_acquire2, 0);
+ MockPreAcquireRequest request_lock_pre_acquire2;
+ MockManagedAcquireRequest request_lock_managed_acquire2;
+ MockPostAcquireRequest request_lock_post_acquire2;
+ expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire2,
+ request_lock_managed_acquire2,
+ &request_lock_post_acquire2, 0, 0, 0);
ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock));
ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
- MockReleaseRequest shutdown_release;
- expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
+ MockPreReleaseRequest shutdown_pre_release;
+ MockManagedReleaseRequest shutdown_managed_release;
+ expect_release_lock(mock_image_ctx, shutdown_pre_release,
+ shutdown_managed_release, 0, 0, true);
+ ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
+}
+
+TEST_F(TestMockExclusiveLock, RequestLockJournalEPERM) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockExclusiveLockImageCtx mock_image_ctx(*ictx);
+ MockExclusiveLock exclusive_lock(mock_image_ctx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_block_writes(mock_image_ctx);
+ ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
+
+ // will abort after seeing perm error (avoid infinite request loop)
+ MockPreAcquireRequest request_lock_pre_acquire;
+ MockManagedAcquireRequest request_lock_managed_acquire;
+ MockPostAcquireRequest request_lock_post_acquire;
+ expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire,
+ request_lock_managed_acquire,
+ &request_lock_post_acquire, 0, 0, -EPERM);
+ MockManagedReleaseRequest release_on_error;
+ EXPECT_CALL(release_on_error, send())
+ .WillOnce(CompleteRequest(&release_on_error, 0));
+ ASSERT_EQ(-EPERM, when_request_lock(mock_image_ctx, exclusive_lock));
+ ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
+
+ expect_unblock_writes(mock_image_ctx);
+ expect_flush_notifies(mock_image_ctx);
ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
}
expect_block_writes(mock_image_ctx);
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
- MockAcquireRequest try_lock_acquire;
- expect_acquire_lock(mock_image_ctx, try_lock_acquire, 0);
+ MockPreAcquireRequest try_lock_pre_acquire;
+ MockManagedAcquireRequest try_lock_managed_acquire;
+ MockPostAcquireRequest try_lock_post_acquire;
+ expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire,
+ try_lock_managed_acquire, &try_lock_post_acquire, 0, 0, 0);
ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock));
- MockReleaseRequest release;
- expect_release_lock(mock_image_ctx, release, -EINVAL);
-
+ MockPreReleaseRequest request_pre_release;
+ MockManagedReleaseRequest request_managed_release;
+ expect_release_lock(mock_image_ctx, request_pre_release,
+ request_managed_release, 0, -EINVAL, false);
ASSERT_EQ(-EINVAL, when_release_lock(mock_image_ctx, exclusive_lock));
ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
- MockReleaseRequest shutdown_release;
- expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
+ MockPreReleaseRequest shutdown_pre_release;
+ MockManagedReleaseRequest shutdown_managed_release;
+ expect_release_lock(mock_image_ctx, shutdown_pre_release,
+ shutdown_managed_release, 0, 0, true);
ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
}
expect_block_writes(mock_image_ctx);
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
- MockAcquireRequest try_lock_acquire;
+ MockPreAcquireRequest try_lock_pre_acquire;
+ MockManagedAcquireRequest try_lock_managed_acquire;
+ MockPostAcquireRequest try_lock_post_acquire;
C_SaferCond wait_for_send_ctx1;
expect_get_watch_handle(mock_image_ctx);
- EXPECT_CALL(try_lock_acquire, send())
+ EXPECT_CALL(try_lock_pre_acquire, send())
+ .WillOnce(CompleteRequest(&try_lock_pre_acquire, 0));
+ EXPECT_CALL(try_lock_managed_acquire, send())
+ .WillOnce(CompleteRequest(&try_lock_managed_acquire, 0));
+ EXPECT_CALL(try_lock_post_acquire, send())
.WillOnce(Notify(&wait_for_send_ctx1));
- MockAcquireRequest request_acquire;
- expect_acquire_lock(mock_image_ctx, request_acquire, 0);
+ MockManagedReleaseRequest managed_release_on_error;
+ EXPECT_CALL(managed_release_on_error, send())
+ .WillOnce(CompleteRequest(&managed_release_on_error, 0));
+
+ MockPreAcquireRequest request_pre_acquire;
+ MockManagedAcquireRequest request_managed_acquire;
+ MockPostAcquireRequest request_post_acquire;
+ expect_acquire_lock(mock_image_ctx, request_pre_acquire,
+ request_managed_acquire, &request_post_acquire, 0, 0, 0);
- MockReleaseRequest release;
+ MockPreReleaseRequest pre_release;
+ MockManagedReleaseRequest managed_release;
C_SaferCond wait_for_send_ctx2;
- EXPECT_CALL(release, send())
- .WillOnce(Notify(&wait_for_send_ctx2));
+ EXPECT_CALL(pre_release, send()).WillOnce(Notify(&wait_for_send_ctx2));
+ EXPECT_CALL(managed_release, send())
+ .WillOnce(CompleteRequest(&managed_release, 0));
expect_notify_released_lock(mock_image_ctx);
expect_is_lock_request_needed(mock_image_ctx, false);
C_SaferCond try_request_ctx1;
{
RWLock::WLocker owner_locker(mock_image_ctx.owner_lock);
- exclusive_lock.try_lock(&try_request_ctx1);
+ exclusive_lock.try_acquire_lock(&try_request_ctx1);
}
C_SaferCond request_lock_ctx1;
C_SaferCond request_lock_ctx2;
{
RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
- exclusive_lock.request_lock(&request_lock_ctx1);
- exclusive_lock.request_lock(&request_lock_ctx2);
+ exclusive_lock.acquire_lock(&request_lock_ctx1);
+ exclusive_lock.acquire_lock(&request_lock_ctx2);
}
C_SaferCond release_lock_ctx1;
C_SaferCond request_lock_ctx3;
{
RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
- exclusive_lock.request_lock(&request_lock_ctx3);
+ exclusive_lock.acquire_lock(&request_lock_ctx3);
}
// fail the try_lock
ASSERT_EQ(0, wait_for_send_ctx1.wait());
- try_lock_acquire.on_lock_unlock->complete(0);
- try_lock_acquire.on_finish->complete(-EINVAL);
+ try_lock_post_acquire.on_lock_unlock->complete(0);
+ try_lock_post_acquire.on_finish->complete(-EINVAL);
ASSERT_EQ(-EINVAL, try_request_ctx1.wait());
// all three pending request locks should complete
// proceed with the release
ASSERT_EQ(0, wait_for_send_ctx2.wait());
- release.on_lock_unlock->complete(0);
- release.on_finish->complete(0);
+ pre_release.on_lock_unlock->complete(0);
+ pre_release.on_finish->complete(0);
ASSERT_EQ(0, release_lock_ctx1.wait());
expect_unblock_writes(mock_image_ctx);
expect_block_writes(mock_image_ctx);
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
- MockAcquireRequest try_lock_acquire;
- expect_acquire_lock(mock_image_ctx, try_lock_acquire, 0);
+ MockPreAcquireRequest try_lock_pre_acquire;
+ MockManagedAcquireRequest try_lock_managed_acquire;
+ MockPostAcquireRequest try_lock_post_acquire;
+ expect_acquire_lock(mock_image_ctx, try_lock_pre_acquire,
+ try_lock_managed_acquire, &try_lock_post_acquire, 0, 0, 0);
ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock));
ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
ASSERT_TRUE(exclusive_lock.accept_requests(&ret_val));
ASSERT_EQ(0, ret_val);
- MockReleaseRequest shutdown_release;
- expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
+ MockPreReleaseRequest shutdown_pre_release;
+ MockManagedReleaseRequest shutdown_managed_release;
+ expect_release_lock(mock_image_ctx, shutdown_pre_release,
+ shutdown_managed_release, 0, 0, true);
ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
}
}),
Return(0)));
- MockAcquireRequest request_lock_acquire;
- expect_acquire_lock(mock_image_ctx, request_lock_acquire, 0);
+ MockPreAcquireRequest request_lock_pre_acquire;
+ MockManagedAcquireRequest request_lock_managed_acquire;
+ MockPostAcquireRequest request_lock_post_acquire;
+ expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire,
+ request_lock_managed_acquire,
+ &request_lock_post_acquire, 0, 0, 0);
ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock));
ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
- MockReleaseRequest shutdown_release;
- expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
+ MockPreReleaseRequest shutdown_pre_release;
+ MockManagedReleaseRequest shutdown_managed_release;
+ expect_release_lock(mock_image_ctx, shutdown_pre_release,
+ shutdown_managed_release, 0, 0, true);
ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
}
expect_block_writes(mock_image_ctx);
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
- MockAcquireRequest request_lock_acquire;
- expect_acquire_lock(mock_image_ctx, request_lock_acquire, 0);
+ MockPreAcquireRequest request_lock_pre_acquire;
+ MockManagedAcquireRequest request_lock_managed_acquire;
+ MockPostAcquireRequest request_lock_post_acquire;
+ expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire,
+ request_lock_managed_acquire,
+ &request_lock_post_acquire, 0, 0, 0);
ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock));
ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
- MockReacquireRequest mock_reacquire_request;
+ EXPECT_CALL(*mock_image_ctx.image_watcher, get_watch_handle())
+ .WillOnce(Return(1234567890));
+
C_SaferCond reacquire_ctx;
- expect_reacquire_lock(mock_image_ctx, mock_reacquire_request, 0);
{
RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
exclusive_lock.reacquire_lock(&reacquire_ctx);
}
ASSERT_EQ(0, reacquire_ctx.wait());
- MockReleaseRequest shutdown_release;
- expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
+ MockPreReleaseRequest shutdown_pre_release;
+ MockManagedReleaseRequest shutdown_managed_release;
+ expect_release_lock(mock_image_ctx, shutdown_pre_release,
+ shutdown_managed_release, 0, 0, true);
ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
}
expect_block_writes(mock_image_ctx);
ASSERT_EQ(0, when_init(mock_image_ctx, exclusive_lock));
- MockAcquireRequest request_lock_acquire;
- expect_acquire_lock(mock_image_ctx, request_lock_acquire, 0);
+ MockPreAcquireRequest request_lock_pre_acquire;
+ MockManagedAcquireRequest request_lock_managed_acquire;
+ MockPostAcquireRequest request_lock_post_acquire;
+ expect_acquire_lock(mock_image_ctx, request_lock_pre_acquire,
+ request_lock_managed_acquire,
+ &request_lock_post_acquire, 0, 0, 0);
ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock));
ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
- MockReacquireRequest mock_reacquire_request;
+ MockManagedReacquireRequest mock_reacquire_request;
C_SaferCond reacquire_ctx;
expect_reacquire_lock(mock_image_ctx, mock_reacquire_request, -EOPNOTSUPP);
- MockReleaseRequest reacquire_lock_release;
- expect_release_lock(mock_image_ctx, reacquire_lock_release, 0, false);
+ MockPreReleaseRequest reacquire_lock_pre_release;
+ MockManagedReleaseRequest reacquire_lock_managed_release;
+ expect_release_lock(mock_image_ctx, reacquire_lock_pre_release,
+ reacquire_lock_managed_release, 0, 0, false);
- MockAcquireRequest reacquire_lock_acquire;
- expect_acquire_lock(mock_image_ctx, reacquire_lock_acquire, 0);
+ MockPreAcquireRequest reacquire_lock_pre_acquire;
+ MockManagedAcquireRequest reacquire_lock_managed_acquire;
+ MockPostAcquireRequest reacquire_lock_post_acquire;
+ expect_acquire_lock(mock_image_ctx, reacquire_lock_pre_acquire,
+ reacquire_lock_managed_acquire,
+ &reacquire_lock_post_acquire, 0, 0, 0);
{
RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
}
ASSERT_EQ(-EOPNOTSUPP, reacquire_ctx.wait());
- MockReleaseRequest shutdown_release;
- expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
+ MockPreReleaseRequest shutdown_pre_release;
+ MockManagedReleaseRequest shutdown_managed_release;
+ expect_release_lock(mock_image_ctx, shutdown_pre_release,
+ shutdown_managed_release, 0, 0, true);
ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
}
for (uint64_t i = 0; i < 10; ++i) {
RWLock::RLocker owner_locker(ictx->owner_lock);
C_SaferCond request_lock;
- ictx->exclusive_lock->request_lock(&request_lock);
+ ictx->exclusive_lock->acquire_lock(&request_lock);
ASSERT_EQ(0, request_lock.wait());
C_SaferCond append_ctx;
{
RWLock::RLocker owner_locker(ictx->owner_lock);
C_SaferCond request_lock;
- ictx->exclusive_lock->request_lock(&request_lock);
+ ictx->exclusive_lock->acquire_lock(&request_lock);
ASSERT_EQ(0, request_lock.wait());
C_SaferCond append_ctx;
C_SaferCond ctx;
{
RWLock::RLocker owner_locker((*image_ctx)->owner_lock);
- (*image_ctx)->exclusive_lock->try_lock(&ctx);
+ (*image_ctx)->exclusive_lock->try_acquire_lock(&ctx);
}
ASSERT_EQ(0, ctx.wait());
ASSERT_TRUE((*image_ctx)->exclusive_lock->is_lock_owner());
OpenLocalImageRequest<I>, &OpenLocalImageRequest<I>::handle_lock_image>(
this);
- (*m_local_image_ctx)->exclusive_lock->request_lock(ctx);
+ (*m_local_image_ctx)->exclusive_lock->acquire_lock(ctx);
}
template <typename I>