#include "librbd/AioImageRequestWQ.h"
#include "librbd/ExclusiveLock.h"
#include "librbd/ImageCtx.h"
+#include "librbd/ImageState.h"
#include "librbd/Journal.h"
#include "librbd/Utils.h"
#include "librbd/image/SetFlagsRequest.h"
namespace librbd {
namespace operation {
+using util::create_async_context_callback;
using util::create_context_callback;
using util::create_rados_ack_callback;
ldout(cct, 20) << this << " " << __func__ << ": features=" << m_features
<< dendl;
- send_block_writes();
+ send_prepare_lock();
}
template <typename I>
return true;
}
+template <typename I>
+void DisableFeaturesRequest<I>::send_prepare_lock() {
+ I &image_ctx = this->m_image_ctx;
+ CephContext *cct = image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << dendl;
+
+ image_ctx.state->prepare_lock(create_async_context_callback(
+ image_ctx, create_context_callback<
+ DisableFeaturesRequest<I>,
+ &DisableFeaturesRequest<I>::handle_prepare_lock>(this)));
+}
+
+template <typename I>
+Context *DisableFeaturesRequest<I>::handle_prepare_lock(int *result) {
+ I &image_ctx = this->m_image_ctx;
+ CephContext *cct = image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
+
+ if (*result < 0) {
+ lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl;
+ return this->create_context_finisher(*result);
+ }
+
+ send_block_writes();
+ return nullptr;
+}
+
template <typename I>
void DisableFeaturesRequest<I>::send_block_writes() {
I &image_ctx = this->m_image_ctx;
CephContext *cct = image_ctx.cct;
ldout(cct, 20) << this << " " << __func__ << dendl;
+ RWLock::WLocker locker(image_ctx.owner_lock);
image_ctx.aio_work_queue->block_writes(create_context_callback<
DisableFeaturesRequest<I>,
&DisableFeaturesRequest<I>::handle_block_writes>(this));
if (*result < 0) {
lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl;
- image_ctx.aio_work_queue->unblock_writes();
- return this->create_context_finisher(*result);
+ return handle_finish(*result);
}
+ m_writes_blocked = true;
{
RWLock::WLocker locker(image_ctx.owner_lock);
image_ctx.aio_work_queue->unblock_writes();
}
+ image_ctx.state->handle_prepare_lock_complete();
return this->create_context_finisher(r);
}
* <start>
* |
* v
+ * STATE_PREPARE_LOCK
+ * |
+ * v
* STATE_BLOCK_WRITES
* |
* v
uint64_t m_features;
bool m_acquired_lock = false;
+ bool m_writes_blocked = false;
bool m_snap_lock_acquired = false;
bool m_requests_blocked = false;
bool m_disabling_journal = false;
cls::rbd::MirrorMode m_mirror_mode = cls::rbd::MIRROR_MODE_DISABLED;
bufferlist m_out_bl;
+ void send_prepare_lock();
+ Context *handle_prepare_lock(int *result);
+
void send_block_writes();
Context *handle_block_writes(int *result);
#include "librbd/AioImageRequestWQ.h"
#include "librbd/ExclusiveLock.h"
#include "librbd/ImageCtx.h"
+#include "librbd/ImageState.h"
#include "librbd/Journal.h"
#include "librbd/Utils.h"
#include "librbd/image/SetFlagsRequest.h"
namespace librbd {
namespace operation {
+using util::create_async_context_callback;
using util::create_context_callback;
using util::create_rados_ack_callback;
ldout(cct, 20) << this << " " << __func__ << ": features=" << m_features
<< dendl;
- send_block_writes();
+ send_prepare_lock();
}
template <typename I>
return true;
}
+template <typename I>
+void EnableFeaturesRequest<I>::send_prepare_lock() {
+ I &image_ctx = this->m_image_ctx;
+ CephContext *cct = image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << dendl;
+
+ image_ctx.state->prepare_lock(create_async_context_callback(
+ image_ctx, create_context_callback<
+ EnableFeaturesRequest<I>,
+ &EnableFeaturesRequest<I>::handle_prepare_lock>(this)));
+}
+
+template <typename I>
+Context *EnableFeaturesRequest<I>::handle_prepare_lock(int *result) {
+ I &image_ctx = this->m_image_ctx;
+ CephContext *cct = image_ctx.cct;
+ ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
+
+ if (*result < 0) {
+ lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl;
+ return this->create_context_finisher(*result);
+ }
+
+ send_block_writes();
+ return nullptr;
+}
+
template <typename I>
void EnableFeaturesRequest<I>::send_block_writes() {
I &image_ctx = this->m_image_ctx;
CephContext *cct = image_ctx.cct;
ldout(cct, 20) << this << " " << __func__ << dendl;
+ RWLock::WLocker locker(image_ctx.owner_lock);
image_ctx.aio_work_queue->block_writes(create_context_callback<
EnableFeaturesRequest<I>,
&EnableFeaturesRequest<I>::handle_block_writes>(this));
if (*result < 0) {
lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl;
- image_ctx.aio_work_queue->unblock_writes();
- return this->create_context_finisher(*result);
+ return handle_finish(*result);
}
+ m_writes_blocked = true;
send_get_mirror_mode();
return nullptr;
if (image_ctx.exclusive_lock != nullptr && m_requests_blocked) {
image_ctx.exclusive_lock->unblock_requests();
}
- image_ctx.aio_work_queue->unblock_writes();
+ if (m_writes_blocked) {
+ image_ctx.aio_work_queue->unblock_writes();
+ }
}
+ image_ctx.state->handle_prepare_lock_complete();
return this->create_context_finisher(r);
}
* <start>
* |
* v
+ * STATE_PREPARE_LOCK
+ * |
+ * v
* STATE_BLOCK_WRITES
* |
* v
bool m_enable_mirroring = false;
bool m_requests_blocked = false;
+ bool m_writes_blocked = false;
uint64_t m_new_features = 0;
uint64_t m_enable_flags = 0;
bufferlist m_out_bl;
+ void send_prepare_lock();
+ Context *handle_prepare_lock(int *result);
+
void send_block_writes();
Context *handle_block_writes(int *result);
librados::IoCtx &m_ioctx;
};
+ void expect_prepare_lock(MockOperationImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.state, prepare_lock(_))
+ .WillOnce(Invoke([](Context *on_ready) {
+ on_ready->complete(0);
+ }));
+ expect_op_work_queue(mock_image_ctx);
+ }
+
+ void expect_handle_prepare_lock_complete(MockOperationImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
+ }
+
void expect_block_writes(MockOperationImageCtx &mock_image_ctx) {
EXPECT_CALL(*mock_image_ctx.aio_work_queue, block_writes(_))
.WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
MockRemoveObjectMapRequest mock_remove_object_map_request;
::testing::InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
expect_block_writes(mock_image_ctx);
if (mock_image_ctx.journal != nullptr) {
expect_is_journal_replaying(*mock_image_ctx.journal);
}
expect_unblock_requests(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
C_SaferCond cond_ctx;
MockDisableFeaturesRequest *req = new MockDisableFeaturesRequest(
MockRemoveObjectMapRequest mock_remove_object_map_request;
::testing::InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
expect_block_writes(mock_image_ctx);
if (mock_image_ctx.journal != nullptr) {
expect_is_journal_replaying(*mock_image_ctx.journal);
expect_notify_update(mock_image_ctx);
expect_unblock_requests(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
expect_commit_op_event(mock_image_ctx, 0);
C_SaferCond cond_ctx;
MockRemoveObjectMapRequest mock_remove_object_map_request;
::testing::InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
expect_block_writes(mock_image_ctx);
if (mock_image_ctx.journal != nullptr) {
expect_is_journal_replaying(*mock_image_ctx.journal);
mock_remove_object_map_request, -EINVAL);
expect_unblock_requests(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
expect_commit_op_event(mock_image_ctx, -EINVAL);
C_SaferCond cond_ctx;
MockDisableMirrorRequest mock_disable_mirror_request;
::testing::InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
expect_block_writes(mock_image_ctx);
expect_is_journal_replaying(*mock_image_ctx.journal);
expect_block_requests(mock_image_ctx);
expect_set_journal_policy(mock_image_ctx);
expect_unblock_requests(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
C_SaferCond cond_ctx;
MockDisableFeaturesRequest *req = new MockDisableFeaturesRequest(
MockDisableMirrorRequest mock_disable_mirror_request;
::testing::InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
expect_block_writes(mock_image_ctx);
expect_is_journal_replaying(*mock_image_ctx.journal);
expect_block_requests(mock_image_ctx);
expect_set_journal_policy(mock_image_ctx);
expect_unblock_requests(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
C_SaferCond cond_ctx;
MockDisableFeaturesRequest *req = new MockDisableFeaturesRequest(
ASSERT_EQ(0U, features & features_to_disable);
}
+ void expect_prepare_lock(MockOperationImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.state, prepare_lock(_))
+ .WillOnce(Invoke([](Context *on_ready) {
+ on_ready->complete(0);
+ }));
+ expect_op_work_queue(mock_image_ctx);
+ }
+
+ void expect_handle_prepare_lock_complete(MockOperationImageCtx &mock_image_ctx) {
+ EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
+ }
+
void expect_block_writes(MockOperationImageCtx &mock_image_ctx) {
EXPECT_CALL(*mock_image_ctx.aio_work_queue, block_writes(_))
.WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
MockCreateObjectMapRequest mock_create_object_map_request;
::testing::InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
expect_block_writes(mock_image_ctx);
expect_block_requests(mock_image_ctx);
if (features_to_enable & RBD_FEATURE_JOURNALING) {
expect_notify_update(mock_image_ctx);
expect_unblock_requests(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
C_SaferCond cond_ctx;
MockEnableFeaturesRequest *req = new MockEnableFeaturesRequest(
MockCreateObjectMapRequest mock_create_object_map_request;
::testing::InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
expect_block_writes(mock_image_ctx);
if (mock_image_ctx.journal != nullptr) {
expect_is_journal_replaying(*mock_image_ctx.journal);
expect_notify_update(mock_image_ctx);
expect_unblock_requests(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
expect_commit_op_event(mock_image_ctx, 0);
C_SaferCond cond_ctx;
MockCreateObjectMapRequest mock_create_object_map_request;
::testing::InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
expect_block_writes(mock_image_ctx);
if (mock_image_ctx.journal != nullptr) {
expect_is_journal_replaying(*mock_image_ctx.journal);
mock_image_ctx, mock_create_object_map_request, -EINVAL);
expect_unblock_requests(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
expect_commit_op_event(mock_image_ctx, -EINVAL);
C_SaferCond cond_ctx;
MockCreateObjectMapRequest mock_create_object_map_request;
::testing::InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
expect_block_writes(mock_image_ctx);
if (mock_image_ctx.journal != nullptr) {
expect_is_journal_replaying(*mock_image_ctx.journal);
mock_set_flags_request, -EINVAL);
expect_unblock_requests(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
expect_commit_op_event(mock_image_ctx, -EINVAL);
C_SaferCond cond_ctx;
MockEnableMirrorRequest mock_enable_mirror_request;
::testing::InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
expect_block_writes(mock_image_ctx);
expect_block_requests(mock_image_ctx);
expect_create_journal_request_send(mock_image_ctx,
expect_notify_update(mock_image_ctx);
expect_unblock_requests(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
C_SaferCond cond_ctx;
MockEnableFeaturesRequest *req = new MockEnableFeaturesRequest(
MockEnableMirrorRequest mock_enable_mirror_request;
::testing::InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
expect_block_writes(mock_image_ctx);
expect_block_requests(mock_image_ctx);
expect_create_journal_request_send(mock_image_ctx,
mock_create_journal_request, -EINVAL);
expect_unblock_requests(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
C_SaferCond cond_ctx;
MockEnableFeaturesRequest *req = new MockEnableFeaturesRequest(
MockEnableMirrorRequest mock_enable_mirror_request;
::testing::InSequence seq;
+ expect_prepare_lock(mock_image_ctx);
expect_block_writes(mock_image_ctx);
expect_block_requests(mock_image_ctx);
expect_create_journal_request_send(mock_image_ctx,
expect_notify_update(mock_image_ctx);
expect_unblock_requests(mock_image_ctx);
expect_unblock_writes(mock_image_ctx);
+ expect_handle_prepare_lock_complete(mock_image_ctx);
C_SaferCond cond_ctx;
MockEnableFeaturesRequest *req = new MockEnableFeaturesRequest(