using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::Return;
+using ::testing::ReturnNew;
using ::testing::WithArg;
namespace {
ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx));
}
+ void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) {
+ EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce(
+ ReturnNew<FunctionContext>([](int) {}));
+ }
+
void expect_list_snaps(librbd::MockTestImageCtx &mock_image_ctx,
librados::MockTestMemIoCtxImpl &mock_io_ctx,
const librados::snap_set_t &snap_set) {
librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
+
librbd::MockObjectMap mock_object_map;
mock_local_image_ctx.object_map = &mock_object_map;
-
expect_test_features(mock_local_image_ctx);
C_SaferCond ctx;
librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
+
librbd::MockObjectMap mock_object_map;
mock_local_image_ctx.object_map = &mock_object_map;
expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
+ expect_start_op(mock_exclusive_lock);
expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
+ expect_start_op(mock_exclusive_lock);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[0], OBJECT_EXISTS, 0);
librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
+
librbd::MockObjectMap mock_object_map;
mock_local_image_ctx.object_map = &mock_object_map;
expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]);
expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
+ expect_start_op(mock_exclusive_lock);
expect_write(mock_local_io_ctx, 0, one.range_end(),
{m_local_snap_ids[1], {m_local_snap_ids[1],
m_local_snap_ids[0]}},
0);
+ expect_start_op(mock_exclusive_lock);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[2], OBJECT_EXISTS, 0);
+ expect_start_op(mock_exclusive_lock);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[3], OBJECT_EXISTS_CLEAN, 0);
librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
+
librbd::MockObjectMap mock_object_map;
mock_local_image_ctx.object_map = &mock_object_map;
librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
+
librbd::MockObjectMap mock_object_map;
mock_local_image_ctx.object_map = &mock_object_map;
librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
+
librbd::MockObjectMap mock_object_map;
mock_local_image_ctx.object_map = &mock_object_map;
expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
+ expect_start_op(mock_exclusive_lock);
expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, -EINVAL);
request->send();
librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
+
librbd::MockObjectMap mock_object_map;
mock_local_image_ctx.object_map = &mock_object_map;
expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
+ expect_start_op(mock_exclusive_lock);
expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[2]);
expect_sparse_read(mock_remote_io_ctx, two, 0);
+ expect_start_op(mock_exclusive_lock);
expect_write(mock_local_io_ctx, two,
{m_local_snap_ids[0], {m_local_snap_ids[0]}}, 0);
+ expect_start_op(mock_exclusive_lock);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[0], OBJECT_EXISTS, 0);
+ expect_start_op(mock_exclusive_lock);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[1], OBJECT_EXISTS, 0);
+ expect_start_op(mock_exclusive_lock);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[2], OBJECT_EXISTS_CLEAN, 0);
librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
+
librbd::MockObjectMap mock_object_map;
mock_local_image_ctx.object_map = &mock_object_map;
expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
+ expect_start_op(mock_exclusive_lock);
expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
+ expect_start_op(mock_exclusive_lock);
expect_truncate(mock_local_io_ctx, trim_offset, 0);
+ expect_start_op(mock_exclusive_lock);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[0], OBJECT_EXISTS, 0);
+ expect_start_op(mock_exclusive_lock);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[1], OBJECT_EXISTS, 0);
librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ librbd::MockExclusiveLock mock_exclusive_lock;
+ mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
+
librbd::MockObjectMap mock_object_map;
mock_local_image_ctx.object_map = &mock_object_map;
expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[1]);
expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
+ expect_start_op(mock_exclusive_lock);
expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
+ expect_start_op(mock_exclusive_lock);
expect_remove(mock_local_io_ctx, 0);
+ expect_start_op(mock_exclusive_lock);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[0], OBJECT_EXISTS, 0);
+ expect_start_op(mock_exclusive_lock);
expect_update_object_map(mock_local_image_ctx, mock_object_map,
m_local_snap_ids[1], OBJECT_EXISTS_CLEAN, 0);
#include "ObjectCopyRequest.h"
#include "librados/snap_set_diff.h"
+#include "librbd/ExclusiveLock.h"
#include "librbd/ObjectMap.h"
#include "librbd/Utils.h"
#include "common/errno.h"
}
}
+ Context *finish_op_ctx;
+ {
+ RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
+ finish_op_ctx = start_local_op(m_local_image_ctx->owner_lock);
+ }
+ if (finish_op_ctx == nullptr) {
+ derr << ": lost exclusive lock" << dendl;
+ finish(-EROFS);
+ return;
+ }
+
dout(20) << ": "
<< "local_snap_seq=" << local_snap_seq << ", "
<< "local_snaps=" << local_snap_ids << dendl;
}
}
- librados::AioCompletion *comp = create_rados_callback<
- ObjectCopyRequest<I>, &ObjectCopyRequest<I>::handle_write_object>(this);
+ auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
+ handle_write_object(r);
+ finish_op_ctx->complete(0);
+ });
+ librados::AioCompletion *comp = create_rados_callback(ctx);
int r = m_local_io_ctx.aio_operate(m_local_oid, comp, &op, local_snap_seq,
local_snap_ids);
assert(r == 0);
template <typename I>
void ObjectCopyRequest<I>::send_update_object_map() {
-
+ m_local_image_ctx->owner_lock.get_read();
m_local_image_ctx->snap_lock.get_read();
if (!m_local_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP,
m_local_image_ctx->snap_lock) ||
m_snap_object_states.empty()) {
m_local_image_ctx->snap_lock.put_read();
+ m_local_image_ctx->owner_lock.put_read();
finish(0);
return;
} else if (m_local_image_ctx->object_map == nullptr) {
derr << ": object map is not initialized" << dendl;
m_local_image_ctx->snap_lock.put_read();
+ m_local_image_ctx->owner_lock.put_read();
finish(-EINVAL);
return;
}
<< "object_state=" << static_cast<uint32_t>(snap_object_state.second)
<< dendl;
+ auto finish_op_ctx = start_local_op(m_local_image_ctx->owner_lock);
+ if (finish_op_ctx == nullptr) {
+ derr << ": lost exclusive lock" << dendl;
+ m_local_image_ctx->snap_lock.put_read();
+ m_local_image_ctx->owner_lock.put_read();
+ finish(-EROFS);
+ return;
+ }
+
+ auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
+ handle_update_object_map(r);
+ finish_op_ctx->complete(0);
+ });
+
RWLock::WLocker object_map_locker(m_local_image_ctx->object_map_lock);
bool sent = m_local_image_ctx->object_map->template aio_update<
- ObjectCopyRequest<I>, &ObjectCopyRequest<I>::handle_update_object_map>(
+ Context, &Context::complete>(
snap_object_state.first, m_object_number, snap_object_state.second, {},
- {}, this);
+ {}, ctx);
assert(sent);
m_local_image_ctx->snap_lock.put_read();
+ m_local_image_ctx->owner_lock.put_read();
}
template <typename I>
finish(0);
}
+template <typename I>
+Context *ObjectCopyRequest<I>::start_local_op(RWLock &owner_lock) {
+ assert(m_local_image_ctx->owner_lock.is_locked());
+ if (m_local_image_ctx->exclusive_lock == nullptr) {
+ return nullptr;
+ }
+ return m_local_image_ctx->exclusive_lock->start_op();
+}
+
template <typename I>
void ObjectCopyRequest<I>::compute_diffs() {
CephContext *cct = m_local_image_ctx->cct;