}
template <typename I>
-bool ExclusiveLock<I>::accept_requests(int *ret_val) const {
+bool ExclusiveLock<I>::accept_request(OperationRequestType request_type,
+ int *ret_val) const {
Mutex::Locker locker(ML<I>::m_lock);
- bool accept_requests = (!ML<I>::is_state_shutdown() &&
- ML<I>::is_state_locked() &&
- m_request_blocked_count == 0);
+ bool accept_request =
+ (!ML<I>::is_state_shutdown() && ML<I>::is_state_locked() &&
+ (m_request_blocked_count == 0 ||
+ m_image_ctx.get_exclusive_lock_policy()->accept_blocked_request(
+ request_type)));
if (ret_val != nullptr) {
- *ret_val = m_request_blocked_ret_val;
+ *ret_val = accept_request ? 0 : m_request_blocked_ret_val;
}
- ldout(m_image_ctx.cct, 20) << "=" << accept_requests << dendl;
- return accept_requests;
+ ldout(m_image_ctx.cct, 20) << "=" << accept_request << " (request_type="
+ << request_type << ")" << dendl;
+ return accept_request;
}
template <typename I>
m_request_blocked_ret_val = r;
}
- ldout(m_image_ctx.cct, 20) << dendl;
+ ldout(m_image_ctx.cct, 20) << "r=" << r << dendl;
}
template <typename I>
#ifndef CEPH_LIBRBD_EXCLUSIVE_LOCK_H
#define CEPH_LIBRBD_EXCLUSIVE_LOCK_H
-#include "librbd/ManagedLock.h"
#include "common/AsyncOpTracker.h"
+#include "librbd/ManagedLock.h"
+#include "librbd/exclusive_lock/Policy.h"
namespace librbd {
ExclusiveLock(ImageCtxT &image_ctx);
- bool accept_requests(int *ret_val = nullptr) const;
+ bool accept_request(exclusive_lock::OperationRequestType request_type,
+ int *ret_val) const;
bool accept_ops() const;
void block_requests(int r);
if (m_image_ctx.exclusive_lock != nullptr &&
m_image_ctx.exclusive_lock->is_lock_owner()) {
int r = 0;
- bool accept_request = m_image_ctx.exclusive_lock->accept_requests(&r);
+ bool accept_request = m_image_ctx.exclusive_lock->accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r);
if (accept_request) {
assert(r == 0);
RWLock::RLocker l(m_image_ctx.owner_lock);
if (m_image_ctx.exclusive_lock != nullptr) {
int r;
- if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+ if (m_image_ctx.exclusive_lock->accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
bool new_request;
Context *ctx;
ProgressContext *prog_ctx;
RWLock::RLocker l(m_image_ctx.owner_lock);
if (m_image_ctx.exclusive_lock != nullptr) {
int r;
- if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+ if (m_image_ctx.exclusive_lock->accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
bool new_request;
Context *ctx;
ProgressContext *prog_ctx;
RWLock::RLocker l(m_image_ctx.owner_lock);
if (m_image_ctx.exclusive_lock != nullptr) {
int r;
- if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+ if (m_image_ctx.exclusive_lock->accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
ldout(m_image_ctx.cct, 10) << this << " remote snap_create request: "
<< payload.snap_name << dendl;
RWLock::RLocker l(m_image_ctx.owner_lock);
if (m_image_ctx.exclusive_lock != nullptr) {
int r;
- if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+ if (m_image_ctx.exclusive_lock->accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
ldout(m_image_ctx.cct, 10) << this << " remote snap_rename request: "
<< payload.snap_id << " to "
<< payload.snap_name << dendl;
C_NotifyAck *ack_ctx) {
RWLock::RLocker l(m_image_ctx.owner_lock);
if (m_image_ctx.exclusive_lock != nullptr) {
+ auto request_type = exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL;
+ if (cls::rbd::get_snap_namespace_type(payload.snap_namespace) ==
+ cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH) {
+ request_type = exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE;
+ }
int r;
- if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+ if (m_image_ctx.exclusive_lock->accept_request(request_type, &r)) {
ldout(m_image_ctx.cct, 10) << this << " remote snap_remove request: "
<< payload.snap_name << dendl;
RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
if (m_image_ctx.exclusive_lock != nullptr) {
int r;
- if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+ if (m_image_ctx.exclusive_lock->accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
ldout(m_image_ctx.cct, 10) << this << " remote snap_protect request: "
<< payload.snap_name << dendl;
RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
if (m_image_ctx.exclusive_lock != nullptr) {
int r;
- if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+ if (m_image_ctx.exclusive_lock->accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
ldout(m_image_ctx.cct, 10) << this << " remote snap_unprotect request: "
<< payload.snap_name << dendl;
RWLock::RLocker l(m_image_ctx.owner_lock);
if (m_image_ctx.exclusive_lock != nullptr) {
int r;
- if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+ if (m_image_ctx.exclusive_lock->accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
bool new_request;
Context *ctx;
ProgressContext *prog_ctx;
RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
if (m_image_ctx.exclusive_lock != nullptr) {
int r;
- if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+ if (m_image_ctx.exclusive_lock->accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
ldout(m_image_ctx.cct, 10) << this << " remote rename request: "
<< payload.image_name << dendl;
RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
if (m_image_ctx.exclusive_lock != nullptr) {
int r;
- if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
+ if (m_image_ctx.exclusive_lock->accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
ldout(m_image_ctx.cct, 10) << this << " remote update_features request: "
<< payload.features << " "
<< (payload.enabled ? "enabled" : "disabled")
RWLock::RLocker l(m_image_ctx.owner_lock);
if (m_image_ctx.exclusive_lock != nullptr) {
int r;
- if (m_image_ctx.exclusive_lock->accept_requests(&r) || r < 0) {
+ if (m_image_ctx.exclusive_lock->accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r) || r < 0) {
encode(ResponseMessage(-EOPNOTSUPP), ack_ctx->out);
}
}
*/
I &image_ctx;
- std::string request_type;
+ std::string name;
+ exclusive_lock::OperationRequestType request_type;
bool permit_snapshot;
boost::function<void(Context*)> local;
boost::function<void(Context*)> remote;
Context *on_finish;
bool request_lock = false;
- C_InvokeAsyncRequest(I &image_ctx, const std::string& request_type,
+ C_InvokeAsyncRequest(I &image_ctx, const std::string& name,
+ exclusive_lock::OperationRequestType request_type,
bool permit_snapshot,
const boost::function<void(Context*)>& local,
const boost::function<void(Context*)>& remote,
const std::set<int> &filter_error_codes,
Context *on_finish)
- : image_ctx(image_ctx), request_type(request_type),
+ : image_ctx(image_ctx), name(name), request_type(request_type),
permit_snapshot(permit_snapshot), local(local), remote(remote),
filter_error_codes(filter_error_codes), on_finish(on_finish) {
}
}
if (image_ctx.exclusive_lock->is_lock_owner() &&
- image_ctx.exclusive_lock->accept_requests()) {
+ image_ctx.exclusive_lock->accept_request(request_type, nullptr)) {
send_local_request();
owner_lock.put_read();
return;
ldout(cct, 20) << __func__ << ": r=" << r << dendl;
if (r == -EOPNOTSUPP) {
- ldout(cct, 5) << request_type << " not supported by current lock owner"
- << dendl;
+ ldout(cct, 5) << name << " not supported by current lock owner" << dendl;
request_lock = true;
send_refresh_image();
return;
return;
}
- ldout(cct, 5) << request_type << " timed out notifying lock owner"
- << dendl;
+ ldout(cct, 5) << name << " timed out notifying lock owner" << dendl;
send_refresh_image();
}
}
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("flatten", false,
+ r = invoke_async_request("flatten",
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ false,
boost::bind(&Operations<I>::execute_flatten, this,
boost::ref(prog_ctx), _1),
boost::bind(&ImageWatcher<I>::notify_flatten,
}
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("rebuild object map", true,
+ r = invoke_async_request("rebuild object map",
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, true,
boost::bind(&Operations<I>::execute_rebuild_object_map,
this, boost::ref(prog_ctx), _1),
boost::bind(&ImageWatcher<I>::notify_rebuild_object_map,
return r;
}
- r = invoke_async_request("check object map", true,
+ r = invoke_async_request("check object map",
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, true,
boost::bind(&Operations<I>::check_object_map, this,
boost::ref(prog_ctx), _1),
[this](Context *c) {
}
if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
- r = invoke_async_request("rename", true,
+ r = invoke_async_request("rename",
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ true,
boost::bind(&Operations<I>::execute_rename, this,
dstname, _1),
boost::bind(&ImageWatcher<I>::notify_rename,
}
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("resize", false,
+ r = invoke_async_request("resize",
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ false,
boost::bind(&Operations<I>::execute_resize, this,
size, allow_shrink, boost::ref(prog_ctx), _1, 0),
boost::bind(&ImageWatcher<I>::notify_resize,
m_image_ctx.snap_lock.put_read();
C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
- m_image_ctx, "snap_create", true,
+ m_image_ctx, "snap_create", exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ true,
boost::bind(&Operations<I>::execute_snap_create, this, snap_namespace, snap_name,
_1, 0, false),
boost::bind(&ImageWatcher<I>::notify_snap_create, m_image_ctx.image_watcher,
}
}
- r = prepare_image_update(false);
+ r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ false);
if (r < 0) {
return r;
}
m_image_ctx.snap_lock.put_read();
if (proxy_op) {
+ auto request_type = exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL;
+ if (cls::rbd::get_snap_namespace_type(snap_namespace) ==
+ cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH) {
+ request_type = exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE;
+ }
C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
- m_image_ctx, "snap_remove", true,
+ m_image_ctx, "snap_remove", request_type, true,
boost::bind(&Operations<I>::execute_snap_remove, this, snap_namespace, snap_name, _1),
boost::bind(&ImageWatcher<I>::notify_snap_remove, m_image_ctx.image_watcher,
snap_namespace, snap_name, _1),
}
if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
- r = invoke_async_request("snap_rename", true,
+ r = invoke_async_request("snap_rename",
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ true,
boost::bind(&Operations<I>::execute_snap_rename,
this, snap_id, dstname, _1),
boost::bind(&ImageWatcher<I>::notify_snap_rename,
}
if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
- r = invoke_async_request("snap_protect", true,
+ r = invoke_async_request("snap_protect",
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ true,
boost::bind(&Operations<I>::execute_snap_protect,
this, snap_namespace, snap_name, _1),
boost::bind(&ImageWatcher<I>::notify_snap_protect,
}
if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
- r = invoke_async_request("snap_unprotect", true,
+ r = invoke_async_request("snap_unprotect",
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ true,
boost::bind(&Operations<I>::execute_snap_unprotect,
this, snap_namespace, snap_name, _1),
boost::bind(&ImageWatcher<I>::notify_snap_unprotect,
C_SaferCond limit_ctx;
{
RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
- r = prepare_image_update(true);
+ r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ true);
if (r < 0) {
return r;
}
C_SaferCond cond_ctx;
{
RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
- r = prepare_image_update(true);
+ r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ true);
if (r < 0) {
return r;
}
r = cond_ctx.wait();
} else {
- r = invoke_async_request("update_features", false,
+ r = invoke_async_request("update_features",
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ false,
boost::bind(&Operations<I>::execute_update_features,
this, features, enabled, _1, 0),
boost::bind(&ImageWatcher<I>::notify_update_features,
C_SaferCond metadata_ctx;
{
RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
- r = prepare_image_update(true);
+ r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ true);
if (r < 0) {
return r;
}
C_SaferCond metadata_ctx;
{
RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
- r = prepare_image_update(true);
+ r = prepare_image_update(exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ true);
if (r < 0) {
return r;
}
}
template <typename I>
-int Operations<I>::prepare_image_update(bool request_lock) {
+int Operations<I>::prepare_image_update(
+ exclusive_lock::OperationRequestType request_type, bool request_lock) {
assert(m_image_ctx.owner_lock.is_locked() &&
!m_image_ctx.owner_lock.is_wlocked());
if (m_image_ctx.image_watcher == nullptr) {
RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
if (m_image_ctx.exclusive_lock != nullptr &&
(!m_image_ctx.exclusive_lock->is_lock_owner() ||
- !m_image_ctx.exclusive_lock->accept_requests())) {
+ !m_image_ctx.exclusive_lock->accept_request(request_type, nullptr))) {
attempting_lock = true;
m_image_ctx.exclusive_lock->block_requests(0);
}
template <typename I>
-int Operations<I>::invoke_async_request(const std::string& request_type,
- bool permit_snapshot,
- const boost::function<void(Context*)>& local_request,
- const boost::function<void(Context*)>& remote_request) {
+int Operations<I>::invoke_async_request(
+ const std::string& name, exclusive_lock::OperationRequestType request_type,
+ bool permit_snapshot, const boost::function<void(Context*)>& local_request,
+ const boost::function<void(Context*)>& remote_request) {
C_SaferCond ctx;
- C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(m_image_ctx,
+ C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(m_image_ctx, name,
request_type,
permit_snapshot,
local_request,
#include "cls/rbd/cls_rbd_types.h"
#include "include/int_types.h"
+#include "librbd/exclusive_lock/Policy.h"
#include "librbd/operation/ObjectMapIterate.h"
#include <atomic>
#include <string>
int metadata_remove(const std::string &key);
void execute_metadata_remove(const std::string &key, Context *on_finish);
- int prepare_image_update(bool request_lock);
+ int prepare_image_update(exclusive_lock::OperationRequestType request_type,
+ bool request_lock);
private:
ImageCtxT &m_image_ctx;
std::atomic<int> m_async_request_seq;
- int invoke_async_request(const std::string& request_type,
+ int invoke_async_request(const std::string& name,
+ exclusive_lock::OperationRequestType request_type,
bool permit_snapshot,
const boost::function<void(Context*)>& local,
const boost::function<void(Context*)>& remote);
namespace librbd {
namespace exclusive_lock {
+enum OperationRequestType {
+ OPERATION_REQUEST_TYPE_GENERAL = 0,
+ OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE = 1,
+};
+
struct Policy {
virtual ~Policy() {
}
virtual bool may_auto_request_lock() = 0;
virtual int lock_requested(bool force) = 0;
+
+ virtual bool accept_blocked_request(OperationRequestType) {
+ return false;
+ }
};
} // namespace exclusive_lock
if (ictx->exclusive_lock != nullptr) {
ictx->exclusive_lock->block_requests(0);
- r = ictx->operations->prepare_image_update(false);
+ r = ictx->operations->prepare_image_update(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, false);
if (r < 0) {
lderr(cct) << "cannot obtain exclusive lock - not removing" << dendl;
ictx->owner_lock.put_read();
#include "include/int_types.h"
#include "include/rados/librados.hpp"
+#include "librbd/exclusive_lock/Policy.h"
#include "gmock/gmock.h"
class Context;
MOCK_METHOD1(acquire_lock, void(Context *));
MOCK_METHOD1(release_lock, void(Context *));
- MOCK_METHOD0(accept_requests, bool());
+ MOCK_METHOD2(accept_request, bool(exclusive_lock::OperationRequestType,
+ int *));
MOCK_METHOD0(accept_ops, bool());
MOCK_METHOD0(get_unlocked_op_error, int());
MOCK_METHOD0(may_auto_request_lock, bool());
MOCK_METHOD1(lock_requested, int(bool));
-
+ MOCK_METHOD1(accept_blocked_request, bool(OperationRequestType));
};
} // namespace exclusive_lock
#include "test/librbd/test_mock_fixture.h"
#include "test/librbd/test_support.h"
#include "test/librbd/mock/MockImageCtx.h"
+#include "test/librbd/mock/exclusive_lock/MockPolicy.h"
#include "librbd/ExclusiveLock.h"
#include "librbd/ManagedLock.h"
#include "librbd/exclusive_lock/PreAcquireRequest.h"
.WillOnce(CompleteContext(0, static_cast<ContextWQ*>(nullptr)));
}
+ void expect_accept_blocked_request(
+ MockExclusiveLockImageCtx &mock_image_ctx,
+ exclusive_lock::MockPolicy &policy,
+ exclusive_lock::OperationRequestType request_type, bool value) {
+ EXPECT_CALL(mock_image_ctx, get_exclusive_lock_policy())
+ .WillOnce(Return(&policy));
+ EXPECT_CALL(policy, accept_blocked_request(request_type))
+ .WillOnce(Return(value));
+ }
+
int when_init(MockExclusiveLockImageCtx &mock_image_ctx,
MockExclusiveLock &exclusive_lock) {
C_SaferCond ctx;
MockExclusiveLockImageCtx mock_image_ctx(*ictx);
MockExclusiveLock exclusive_lock(mock_image_ctx);
+ exclusive_lock::MockPolicy mock_exclusive_lock_policy;
expect_op_work_queue(mock_image_ctx);
int ret_val;
expect_is_state_shutdown(exclusive_lock, false);
expect_is_state_locked(exclusive_lock, true);
- ASSERT_TRUE(exclusive_lock.accept_requests(&ret_val));
+ ASSERT_TRUE(exclusive_lock.accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &ret_val));
ASSERT_EQ(0, ret_val);
exclusive_lock.block_requests(-EROFS);
expect_is_state_shutdown(exclusive_lock, false);
expect_is_state_locked(exclusive_lock, true);
- ASSERT_FALSE(exclusive_lock.accept_requests(&ret_val));
+ expect_accept_blocked_request(mock_image_ctx, mock_exclusive_lock_policy,
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ false);
+ ASSERT_FALSE(exclusive_lock.accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &ret_val));
ASSERT_EQ(-EROFS, ret_val);
+ expect_is_state_shutdown(exclusive_lock, false);
+ expect_is_state_locked(exclusive_lock, true);
+ expect_accept_blocked_request(
+ mock_image_ctx, mock_exclusive_lock_policy,
+ exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE, true);
+ ASSERT_TRUE(exclusive_lock.accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE,
+ &ret_val));
+ ASSERT_EQ(0, ret_val);
+
exclusive_lock.unblock_requests();
expect_is_state_shutdown(exclusive_lock, false);
expect_is_state_locked(exclusive_lock, true);
- ASSERT_TRUE(exclusive_lock.accept_requests(&ret_val));
+ ASSERT_TRUE(exclusive_lock.accept_request(
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &ret_val));
ASSERT_EQ(0, ret_val);
}