case STATE_LOCKED:
case STATE_POST_ACQUIRING:
case STATE_PRE_RELEASING:
+ case STATE_PRE_SHUTTING_DOWN:
lock_owner = true;
break;
default:
case STATE_POST_ACQUIRING:
case STATE_PRE_RELEASING:
case STATE_RELEASING:
+ case STATE_PRE_SHUTTING_DOWN:
case STATE_SHUTTING_DOWN:
return true;
case STATE_UNINITIALIZED:
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_unlocked_shutdown>(this), 0);
+ 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_SHUTTING_DOWN;
+ m_state = STATE_PRE_SHUTTING_DOWN;
m_lock.Unlock();
m_image_ctx.op_work_queue->queue(new C_ShutDownRelease(this), 0);
using el = ExclusiveLock<I>;
ReleaseRequest<I>* req = ReleaseRequest<I>::create(
- m_image_ctx, cookie, nullptr,
- util::create_context_callback<el, &el::handle_locked_shutdown>(this));
+ m_image_ctx, cookie,
+ util::create_context_callback<el, &el::handle_shutdown_releasing>(this),
+ util::create_context_callback<el, &el::handle_shutdown_released>(this));
req->send();
}
template <typename I>
-void ExclusiveLock<I>::handle_locked_shutdown(int r) {
+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;
}
template <typename I>
-void ExclusiveLock<I>::handle_unlocked_shutdown(int r) {
+void ExclusiveLock<I>::handle_shutdown(int r) {
CephContext *cct = m_image_ctx.cct;
ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
* |
* |
* v
- * SHUTTING_DOWN ---> SHUTDOWN ---> <finish>
+ * PRE_SHUTTING_DOWN ---> SHUTTING_DOWN ---> SHUTDOWN ---> <finish>
*/
enum State {
STATE_UNINITIALIZED,
STATE_WAITING_FOR_PEER,
STATE_PRE_RELEASING,
STATE_RELEASING,
+ STATE_PRE_SHUTTING_DOWN,
STATE_SHUTTING_DOWN,
STATE_SHUTDOWN,
};
void send_shutdown();
void send_shutdown_release();
- void handle_locked_shutdown(int r);
- void handle_unlocked_shutdown(int r);
+ void handle_shutdown_releasing(int r);
+ void handle_shutdown_released(int r);
+ void handle_shutdown(int r);
void complete_shutdown(int r);
};
template <typename I>
void ReleaseRequest<I>::send() {
- send_block_writes();
+ send_cancel_op_requests();
}
template <typename I>
-void ReleaseRequest<I>::send_block_writes() {
+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_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);
- }
+ klass, &klass::handle_cancel_op_requests>(this);
+ m_image_ctx.cancel_async_requests(ctx);
}
template <typename I>
-Context *ReleaseRequest<I>::handle_block_writes(int *ret_val) {
+Context *ReleaseRequest<I>::handle_cancel_op_requests(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;
- }
+ assert(*ret_val == 0);
- send_cancel_op_requests();
+ send_block_writes();
return nullptr;
}
template <typename I>
-void ReleaseRequest<I>::send_cancel_op_requests() {
+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_cancel_op_requests>(this);
- m_image_ctx.cancel_async_requests(ctx);
+ 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_cancel_op_requests(int *ret_val) {
+Context *ReleaseRequest<I>::handle_block_writes(int *ret_val) {
CephContext *cct = m_image_ctx.cct;
ldout(cct, 10) << __func__ << ": r=" << *ret_val << dendl;
- assert(*ret_val == 0);
+ if (*ret_val < 0) {
+ m_image_ctx.aio_work_queue->unblock_writes();
+ return m_on_finish;
+ }
if (m_on_releasing != nullptr) {
// alert caller that we no longer own the exclusive lock
* <start>
* |
* v
- * BLOCK_WRITES
+ * CANCEL_OP_REQUESTS
* |
* v
- * CANCEL_OP_REQUESTS
+ * BLOCK_WRITES
* |
* v
* FLUSH_NOTIFIES . . . . . . . . . . . . . .
decltype(m_image_ctx.object_map) m_object_map;
decltype(m_image_ctx.journal) m_journal;
- void send_block_writes();
- Context *handle_block_writes(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);
expect_op_work_queue(mock_image_ctx);
InSequence seq;
- expect_block_writes(mock_image_ctx, 0);
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();
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);
expect_op_work_queue(mock_image_ctx);
InSequence seq;
- expect_block_writes(mock_image_ctx, 0);
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);