ldout(m_cct, 20) << dendl;
Context *finish_op_ctx = nullptr;
+ int r;
if (m_dst_image_ctx->exclusive_lock != nullptr) {
- finish_op_ctx = m_dst_image_ctx->exclusive_lock->start_op();
+ finish_op_ctx = m_dst_image_ctx->exclusive_lock->start_op(&r);
}
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
m_dst_image_ctx->snap_lock.put_read();
m_dst_image_ctx->owner_lock.put_read();
- finish(-EROFS);
+ finish(r);
return;
}
template <typename I>
void DeepCopyRequest<I>::send_refresh_object_map() {
+ int r;
Context *finish_op_ctx = nullptr;
{
RWLock::RLocker owner_locker(m_dst_image_ctx->owner_lock);
if (m_dst_image_ctx->exclusive_lock != nullptr) {
- finish_op_ctx = m_dst_image_ctx->exclusive_lock->start_op();
+ finish_op_ctx = m_dst_image_ctx->exclusive_lock->start_op(&r);
}
}
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
- finish(-EROFS);
+ finish(r);
return;
}
}
template <typename I>
-Context *ExclusiveLock<I>::start_op() {
+Context *ExclusiveLock<I>::start_op(int* ret_val) {
ceph_assert(m_image_ctx.owner_lock.is_locked());
Mutex::Locker locker(ML<I>::m_lock);
if (!accept_ops(ML<I>::m_lock)) {
+ *ret_val = get_unlocked_op_error();
return nullptr;
}
void block_requests(int r);
void unblock_requests();
- int get_unlocked_op_error() const;
-
void init(uint64_t features, Context *on_init);
void shut_down(Context *on_shutdown);
void handle_peer_notification(int r);
- Context *start_op();
+ int get_unlocked_op_error() const;
+ Context *start_op(int* ret_val);
protected:
void shutdown_handler(int r, Context *on_finish) override;
ldout(cct, 20) << __func__ << ": r=" << r << dendl;
if (r < 0) {
- complete(-EROFS);
+ complete(r == -EBLACKLISTED ? -EBLACKLISTED : -EROFS);
return;
}
// context can complete before owner_lock is unlocked
RWLock &owner_lock(image_ctx.owner_lock);
owner_lock.get_read();
- if (image_ctx.exclusive_lock->is_lock_owner()) {
+ if (image_ctx.exclusive_lock == nullptr ||
+ image_ctx.exclusive_lock->is_lock_owner()) {
send_local_request();
owner_lock.put_read();
return;
r = prepare_image_update(false);
if (r < 0) {
- return -EROFS;
+ return r;
}
execute_snap_rollback(snap_namespace, snap_name, prog_ctx, &cond_ctx);
RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
r = prepare_image_update(true);
if (r < 0) {
- return -EROFS;
+ return r;
}
execute_update_features(features, enabled, &cond_ctx, 0);
CephContext *cct = m_image_ctx.cct;
ldout(cct, 5) << this << " " << __func__ << ": key=" << key << dendl;
- if (m_image_ctx.read_only) {
- return -EROFS;
- }
-
int r = m_image_ctx.state->refresh_if_required();
if (r < 0) {
return r;
m_image_ctx.exclusive_lock->unblock_requests();
}
+ if (r == -EAGAIN || r == -EBUSY) {
+ r = 0;
+ }
if (r < 0) {
return r;
} else if (m_image_ctx.exclusive_lock != nullptr &&
!m_image_ctx.exclusive_lock->is_lock_owner()) {
- return -EROFS;
+ return m_image_ctx.exclusive_lock->get_unlocked_op_error();
}
return 0;
return;
}
+ int r;
Context *finish_op_ctx;
{
RWLock::RLocker owner_locker(m_dst_image_ctx->owner_lock);
- finish_op_ctx = start_lock_op(m_dst_image_ctx->owner_lock);
+ finish_op_ctx = start_lock_op(m_dst_image_ctx->owner_lock, &r);
}
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
- finish(-EROFS);
+ finish(r);
return;
}
finish_op_ctx->complete(0);
});
librados::AioCompletion *comp = create_rados_callback(ctx);
- int r = m_dst_io_ctx.aio_operate(m_dst_oid, comp, &op, dst_snap_seq,
- dst_snap_ids, nullptr);
+ r = m_dst_io_ctx.aio_operate(m_dst_oid, comp, &op, dst_snap_seq, dst_snap_ids,
+ nullptr);
ceph_assert(r == 0);
comp->release();
}
ldout(m_cct, 20) << "dst_snap_id=" << dst_snap_id << ", object_state="
<< static_cast<uint32_t>(object_state) << dendl;
- auto finish_op_ctx = start_lock_op(m_dst_image_ctx->owner_lock);
+ int r;
+ auto finish_op_ctx = start_lock_op(m_dst_image_ctx->owner_lock, &r);
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
m_dst_image_ctx->snap_lock.put_read();
m_dst_image_ctx->owner_lock.put_read();
- finish(-EROFS);
+ finish(r);
return;
}
}
template <typename I>
-Context *ObjectCopyRequest<I>::start_lock_op(RWLock &owner_lock) {
+Context *ObjectCopyRequest<I>::start_lock_op(RWLock &owner_lock, int* r) {
ceph_assert(m_dst_image_ctx->owner_lock.is_locked());
if (m_dst_image_ctx->exclusive_lock == nullptr) {
return new FunctionContext([](int r) {});
}
- return m_dst_image_ctx->exclusive_lock->start_op();
+ return m_dst_image_ctx->exclusive_lock->start_op(r);
}
template <typename I>
void send_update_object_map();
void handle_update_object_map(int r);
- Context *start_lock_op(RWLock &owner_lock);
+ Context *start_lock_op(RWLock &owner_lock, int* r);
uint64_t src_to_dst_object_offset(uint64_t objectno, uint64_t offset);
librados::ObjectWriteOperation op;
librbd::cls_client::set_size(&op, m_size);
- auto finish_op_ctx = start_lock_op();
+ int r;
+ auto finish_op_ctx = start_lock_op(&r);
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
- finish(-EROFS);
+ finish(r);
return;
}
finish_op_ctx->complete(0);
});
librados::AioCompletion *comp = create_rados_callback(ctx);
- int r = m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op);
+ r = m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op);
ceph_assert(r == 0);
comp->release();
}
m_image_ctx->parent_lock.put_read();
ldout(m_cct, 20) << dendl;
- auto finish_op_ctx = start_lock_op();
+
+ int r;
+ auto finish_op_ctx = start_lock_op(&r);
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
- finish(-EROFS);
+ finish(r);
return;
}
m_image_ctx->parent_lock.put_read();
ldout(m_cct, 20) << dendl;
- auto finish_op_ctx = start_lock_op();
+
+ int r;
+ auto finish_op_ctx = start_lock_op(&r);
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
- finish(-EROFS);
+ finish(r);
return;
}
}
template <typename I>
-Context *SetHeadRequest<I>::start_lock_op() {
+Context *SetHeadRequest<I>::start_lock_op(int* r) {
RWLock::RLocker owner_locker(m_image_ctx->owner_lock);
if (m_image_ctx->exclusive_lock == nullptr) {
return new FunctionContext([](int r) {});
}
- return m_image_ctx->exclusive_lock->start_op();
+ return m_image_ctx->exclusive_lock->start_op(r);
}
template <typename I>
void send_attach_parent();
void handle_attach_parent(int r);
- Context *start_lock_op();
+ Context *start_lock_op(int* r);
void finish(int r);
};
ldout(m_cct, 20) << "snap_name=" << m_snap_name << ", "
<< "snap_id=" << m_prev_snap_id << dendl;
- auto finish_op_ctx = start_lock_op();
+ int r;
+ auto finish_op_ctx = start_lock_op(&r);
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
- finish(-EROFS);
+ finish(r);
return;
}
<< "snap_name=" << m_snap_name << ", "
<< "snap_id=" << m_prev_snap_id << dendl;
- auto finish_op_ctx = start_lock_op();
+ int r;
+ auto finish_op_ctx = start_lock_op(&r);
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
- finish(-EROFS);
+ finish(r);
return;
}
<< "snap_id=" << parent_spec.snap_id << ", "
<< "overlap=" << parent_overlap << "]" << dendl;
- Context *finish_op_ctx = start_lock_op();
+ int r;
+ Context *finish_op_ctx = start_lock_op(&r);
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
- finish(-EROFS);
+ finish(r);
return;
}
ldout(m_cct, 20) << "snap_name=" << m_snap_name << ", "
<< "snap_id=" << m_prev_snap_id << dendl;
- auto finish_op_ctx = start_lock_op();
+ int r;
+ auto finish_op_ctx = start_lock_op(&r);
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
- finish(-EROFS);
+ finish(r);
return;
}
ldout(m_cct, 20) << dendl;
- auto finish_op_ctx = start_lock_op(m_dst_image_ctx->owner_lock);
+ auto finish_op_ctx = start_lock_op(m_dst_image_ctx->owner_lock, &r);
if (finish_op_ctx != nullptr) {
auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
handle_resize_object_map(r);
}
lderr(m_cct) << "lost exclusive lock" << dendl;
- r = -EROFS;
}
}
}
template <typename I>
-Context *SnapshotCopyRequest<I>::start_lock_op() {
+Context *SnapshotCopyRequest<I>::start_lock_op(int* r) {
RWLock::RLocker owner_locker(m_dst_image_ctx->owner_lock);
- return start_lock_op(m_dst_image_ctx->owner_lock);
+ return start_lock_op(m_dst_image_ctx->owner_lock, r);
}
template <typename I>
-Context *SnapshotCopyRequest<I>::start_lock_op(RWLock &owner_lock) {
+Context *SnapshotCopyRequest<I>::start_lock_op(RWLock &owner_lock, int* r) {
ceph_assert(m_dst_image_ctx->owner_lock.is_locked());
if (m_dst_image_ctx->exclusive_lock == nullptr) {
return new FunctionContext([](int r) {});
}
- return m_dst_image_ctx->exclusive_lock->start_op();
+ return m_dst_image_ctx->exclusive_lock->start_op(r);
}
template <typename I>
int validate_parent(ImageCtxT *image_ctx, cls::rbd::ParentImageSpec *spec);
- Context *start_lock_op();
- Context *start_lock_op(RWLock &owner_lock);
+ Context *start_lock_op(int* r);
+ Context *start_lock_op(RWLock &owner_locki, int* r);
void finish(int r);
};
void SnapshotCreateRequest<I>::send_create_snap() {
ldout(m_cct, 20) << "snap_name=" << m_snap_name << dendl;
- auto finish_op_ctx = start_lock_op();
+ int r;
+ auto finish_op_ctx = start_lock_op(&r);
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
- finish(-EROFS);
+ finish(r);
return;
}
librados::ObjectWriteOperation op;
librbd::cls_client::object_map_resize(&op, object_count, OBJECT_NONEXISTENT);
- auto finish_op_ctx = start_lock_op();
+ int r;
+ auto finish_op_ctx = start_lock_op(&r);
if (finish_op_ctx == nullptr) {
lderr(m_cct) << "lost exclusive lock" << dendl;
- finish(-EROFS);
+ finish(r);
return;
}
finish_op_ctx->complete(0);
});
librados::AioCompletion *comp = create_rados_callback(ctx);
- int r = m_dst_image_ctx->md_ctx.aio_operate(object_map_oid, comp, &op);
+ r = m_dst_image_ctx->md_ctx.aio_operate(object_map_oid, comp, &op);
ceph_assert(r == 0);
comp->release();
}
}
template <typename I>
-Context *SnapshotCreateRequest<I>::start_lock_op() {
+Context *SnapshotCreateRequest<I>::start_lock_op(int* r) {
RWLock::RLocker owner_locker(m_dst_image_ctx->owner_lock);
if (m_dst_image_ctx->exclusive_lock == nullptr) {
return new FunctionContext([](int r) {});
}
- return m_dst_image_ctx->exclusive_lock->start_op();
+ return m_dst_image_ctx->exclusive_lock->start_op(r);
}
template <typename I>
void send_create_object_map();
void handle_create_object_map(int r);
- Context *start_lock_op();
+ Context *start_lock_op(int* r);
void finish(int r);
};
template<typename I>
void RemoveRequest<I>::check_exclusive_lock() {
if (m_image_ctx->operations_disabled) {
- lderr(m_cct) << "image operations disabled due to unsupported op features" << dendl;
+ lderr(m_cct) << "image operations disabled due to unsupported op features"
+ << dendl;
send_close_image(-EROFS);
return;
}
int is_exclusive_lock_owner(ImageCtx *ictx, bool *is_owner)
{
+ CephContext *cct = ictx->cct;
+ ldout(cct, 20) << __func__ << ": ictx=" << ictx << dendl;
*is_owner = false;
RWLock::RLocker owner_locker(ictx->owner_lock);
- if (ictx->exclusive_lock == nullptr ||
- !ictx->exclusive_lock->is_lock_owner()) {
+ if (ictx->exclusive_lock == nullptr) {
return 0;
}
}
RWLock::RLocker l(ictx->owner_lock);
-
- if (ictx->exclusive_lock == nullptr ||
- !ictx->exclusive_lock->is_lock_owner()) {
+ if (ictx->exclusive_lock == nullptr) {
+ return -EINVAL;
+ } else if (!ictx->exclusive_lock->is_lock_owner()) {
lderr(cct) << "failed to acquire exclusive lock" << dendl;
- return -EROFS;
+ return ictx->exclusive_lock->get_unlocked_op_error();
}
return 0;
#include "librbd/ExclusiveLock.h"
#include "librbd/ImageCtx.h"
#include "librbd/ImageState.h"
+#include "librbd/ImageWatcher.h"
#include "librbd/internal.h"
#include "librbd/Utils.h"
#include "librbd/exclusive_lock/Policy.h"
ldout(cct, 5) << "exclusive lock required: delaying IO " << item << dendl;
if (!m_image_ctx.get_exclusive_lock_policy()->may_auto_request_lock()) {
lderr(cct) << "op requires exclusive lock" << dendl;
- fail_in_flight_io(-EROFS, item);
+ fail_in_flight_io(m_image_ctx.exclusive_lock->get_unlocked_op_error(),
+ item);
// wake up the IO since we won't be returning a request to process
this->signal();
}
m_image_ctx.owner_lock.get_read();
- if (m_image_ctx.exclusive_lock == nullptr ||
+ if (m_image_ctx.exclusive_lock != nullptr &&
!m_image_ctx.exclusive_lock->is_lock_owner()) {
+ r = m_image_ctx.exclusive_lock->get_unlocked_op_error();
m_image_ctx.owner_lock.put_read();
lderr(cct) << "failed to acquire exclusive lock" << dendl;
- finish(-EROFS);
+ finish(r);
return;
}
m_image_ctx.owner_lock.put_read();
CephContext *cct = image_ctx.cct;
ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
+ image_ctx.owner_lock.get_read();
if (*result < 0) {
lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl;
+ image_ctx.owner_lock.put_read();
return handle_finish(*result);
- } else if (m_acquired_lock && (image_ctx.exclusive_lock == nullptr ||
- !image_ctx.exclusive_lock->is_lock_owner())) {
+ } else if (image_ctx.exclusive_lock != nullptr &&
+ !image_ctx.exclusive_lock->is_lock_owner()) {
lderr(cct) << "failed to acquire exclusive lock" << dendl;
- *result = -EROFS;
+ *result = image_ctx.exclusive_lock->get_unlocked_op_error();
+ image_ctx.owner_lock.put_read();
return handle_finish(*result);
}
do {
- RWLock::WLocker locker(image_ctx.owner_lock);
-
m_features &= image_ctx.features;
m_new_features = image_ctx.features & ~m_features;
m_features_mask = m_features;
m_disable_flags |= RBD_FLAG_OBJECT_MAP_INVALID;
}
} while (false);
+ image_ctx.owner_lock.put_read();
if (*result < 0) {
return handle_finish(*result);
if ((m_src_image_ctx->features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
return;
}
- EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce(
+ EXPECT_CALL(mock_exclusive_lock, start_op(_)).WillOnce(
ReturnNew<FunctionContext>([](int) {}));
}
}
void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) {
- EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce(
+ EXPECT_CALL(mock_exclusive_lock, start_op(_)).WillOnce(
ReturnNew<FunctionContext>([](int) {}));
}
if ((m_src_image_ctx->features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
return;
}
- EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce(
+ EXPECT_CALL(mock_exclusive_lock, start_op(_)).WillOnce(
ReturnNew<FunctionContext>([](int) {}));
}
}
void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) {
- EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce(
+ EXPECT_CALL(mock_exclusive_lock, start_op(_)).WillOnce(
ReturnNew<FunctionContext>([](int) {}));
}
aio_comp->release();
}
+TEST_F(TestMockIoImageRequestWQ, AcquireLockBlacklisted) {
+ REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ MockExclusiveLock mock_exclusive_lock;
+ mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+
+ auto mock_queued_image_request = new MockImageDispatchSpec();
+ expect_was_throttled(*mock_queued_image_request, false);
+ expect_set_throttled(*mock_queued_image_request);
+
+ InSequence seq;
+ MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
+ expect_signal(mock_image_request_wq);
+ mock_image_request_wq.set_require_lock(DIRECTION_WRITE, true);
+
+ expect_is_write_op(*mock_queued_image_request, true);
+ expect_queue(mock_image_request_wq);
+ auto *aio_comp = new librbd::io::AioCompletion();
+ mock_image_request_wq.aio_write(aio_comp, 0, 0, {}, 0);
+
+ librbd::exclusive_lock::MockPolicy mock_exclusive_lock_policy;
+ expect_front(mock_image_request_wq, mock_queued_image_request);
+ expect_is_refresh_request(mock_image_ctx, false);
+ expect_is_write_op(*mock_queued_image_request, true);
+ expect_dequeue(mock_image_request_wq, mock_queued_image_request);
+ expect_get_exclusive_lock_policy(mock_image_ctx, mock_exclusive_lock_policy);
+ expect_may_auto_request_lock(mock_exclusive_lock_policy, false);
+ EXPECT_CALL(*mock_image_ctx.exclusive_lock, get_unlocked_op_error())
+ .WillOnce(Return(-EBLACKLISTED));
+ expect_process_finish(mock_image_request_wq);
+ expect_fail(*mock_queued_image_request, -EBLACKLISTED);
+ expect_is_write_op(*mock_queued_image_request, true);
+ expect_signal(mock_image_request_wq);
+ ASSERT_TRUE(mock_image_request_wq.invoke_dequeue() == nullptr);
+
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ ASSERT_EQ(-EBLACKLISTED, aio_comp->get_return_value());
+ aio_comp->release();
+}
+
TEST_F(TestMockIoImageRequestWQ, RefreshError) {
librbd::ImageCtx *ictx;
ASSERT_EQ(0, open_image(m_image_name, &ictx));
MOCK_METHOD0(accept_ops, bool());
MOCK_METHOD0(get_unlocked_op_error, int());
- MOCK_METHOD0(start_op, Context*());
+ MOCK_METHOD1(start_op, Context*(int*));
};
} // namespace librbd
}
void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) {
- EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce(
+ EXPECT_CALL(mock_exclusive_lock, start_op(_)).WillOnce(
ReturnNew<FunctionContext>([](int) {}));
}
}
void expect_start_op(librbd::MockTestImageCtx &mock_image_ctx, bool success) {
- EXPECT_CALL(*mock_image_ctx.exclusive_lock, start_op())
- .WillOnce(Invoke([success]() {
+ EXPECT_CALL(*mock_image_ctx.exclusive_lock, start_op(_))
+ .WillOnce(Invoke([success](int* r) {
if (!success) {
+ *r = -EROFS;
return static_cast<FunctionContext*>(nullptr);
}
return new FunctionContext([](int r) {});
<< "snap_namespace=" << m_snap_namespace << ", "
<< "snap_name=" << m_snap_name << dendl;
- auto finish_op_ctx = start_lock_op();
+ auto finish_op_ctx = start_lock_op(&r);
if (finish_op_ctx == nullptr) {
derr << "lost exclusive lock" << dendl;
- m_ret_val = -EROFS;
+ m_ret_val = r;
close_image();
return;
}
<< "snap_namespace=" << m_snap_namespace << ", "
<< "snap_name=" << m_snap_name << dendl;
- auto finish_op_ctx = start_lock_op();
+ int r;
+ auto finish_op_ctx = start_lock_op(&r);
if (finish_op_ctx == nullptr) {
derr << "lost exclusive lock" << dendl;
- m_ret_val = -EROFS;
+ m_ret_val = r;
close_image();
return;
}
}
template <typename I>
-Context *SnapshotPurgeRequest<I>::start_lock_op() {
+Context *SnapshotPurgeRequest<I>::start_lock_op(int* r) {
RWLock::RLocker owner_locker(m_image_ctx->owner_lock);
- return m_image_ctx->exclusive_lock->start_op();
+ return m_image_ctx->exclusive_lock->start_op(r);
}
} // namespace image_deleter
void finish(int r);
- Context *start_lock_op();
+ Context *start_lock_op(int* r);
};