From: Jason Dillaman Date: Tue, 7 Jun 2016 16:42:52 +0000 (-0400) Subject: librbd: stop journal recorder before starting external replay X-Git-Tag: v10.2.2~13^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=f0bf15e9d38e3de63c959bac0ae90b609dafc514;p=ceph.git librbd: stop journal recorder before starting external replay Fixes: http://tracker.ceph.com/issues/16165 Signed-off-by: Jason Dillaman (cherry picked from commit 5aa6eb2782bdb5cde6a050a5f7a4e683800414c0) --- diff --git a/src/librbd/Journal.cc b/src/librbd/Journal.cc index b24e8611e0bb..b874005843ee 100644 --- a/src/librbd/Journal.cc +++ b/src/librbd/Journal.cc @@ -1070,7 +1070,8 @@ typename Journal::Future Journal::wait_event(Mutex &lock, uint64_t tid, } template -int Journal::start_external_replay(journal::Replay **journal_replay) { +void Journal::start_external_replay(journal::Replay **journal_replay, + Context *on_finish) { CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << dendl; @@ -1078,11 +1079,42 @@ int Journal::start_external_replay(journal::Replay **journal_replay) { assert(m_state == STATE_READY); assert(m_journal_replay == nullptr); + on_finish = util::create_async_context_callback(m_image_ctx, on_finish); + on_finish = new FunctionContext( + [this, journal_replay, on_finish](int r) { + handle_start_external_replay(r, journal_replay, on_finish); + }); + + // safely flush all in-flight events before starting external replay + m_journaler->stop_append(util::create_async_context_callback(m_image_ctx, + on_finish)); +} + +template +void Journal::handle_start_external_replay(int r, + journal::Replay **journal_replay, + Context *on_finish) { + CephContext *cct = m_image_ctx.cct; + ldout(cct, 20) << this << " " << __func__ << dendl; + + Mutex::Locker locker(m_lock); + assert(m_state == STATE_READY); + assert(m_journal_replay == nullptr); + + if (r < 0) { + lderr(cct) << "failed to stop recording: " << cpp_strerror(r) << dendl; + *journal_replay = nullptr; + + // get back to a sane-state + start_append(); + on_finish->complete(r); + return; + } + transition_state(STATE_REPLAYING, 0); m_journal_replay = journal::Replay::create(m_image_ctx); - *journal_replay = m_journal_replay; - return 0; + on_finish->complete(0); } template @@ -1093,7 +1125,8 @@ void Journal::stop_external_replay() { delete m_journal_replay; m_journal_replay = nullptr; - transition_state(STATE_READY, 0); + + start_append(); } template @@ -1177,6 +1210,15 @@ void Journal::complete_event(typename Events::iterator it, int r) { } } +template +void Journal::start_append() { + assert(m_lock.is_locked()); + m_journaler->start_append(m_image_ctx.journal_object_flush_interval, + m_image_ctx.journal_object_flush_bytes, + m_image_ctx.journal_object_flush_age); + transition_state(STATE_READY, 0); +} + template void Journal::handle_initialized(int r) { CephContext *cct = m_image_ctx.cct; @@ -1429,10 +1471,7 @@ void Journal::handle_flushing_replay() { m_journal_replay = NULL; m_error_result = 0; - m_journaler->start_append(m_image_ctx.journal_object_flush_interval, - m_image_ctx.journal_object_flush_bytes, - m_image_ctx.journal_object_flush_age); - transition_state(STATE_READY, 0); + start_append(); } template diff --git a/src/librbd/Journal.h b/src/librbd/Journal.h index 3d36b28b4024..d77d50ed2868 100644 --- a/src/librbd/Journal.h +++ b/src/librbd/Journal.h @@ -154,7 +154,8 @@ public: return op_tid; } - int start_external_replay(journal::Replay **journal_replay); + void start_external_replay(journal::Replay **journal_replay, + Context *on_finish); void stop_external_replay(); private: @@ -298,6 +299,8 @@ private: void complete_event(typename Events::iterator it, int r); + void start_append(); + void handle_initialized(int r); void handle_get_tags(int r); @@ -306,6 +309,10 @@ private: void handle_replay_process_ready(int r); void handle_replay_process_safe(ReplayEntry replay_entry, int r); + void handle_start_external_replay(int r, + journal::Replay **journal_replay, + Context *on_finish); + void handle_flushing_restart(int r); void handle_flushing_replay(); diff --git a/src/test/rbd_mirror/test_mock_ImageReplayer.cc b/src/test/rbd_mirror/test_mock_ImageReplayer.cc index b5cfcd9d356e..8ff318afac8f 100644 --- a/src/test/rbd_mirror/test_mock_ImageReplayer.cc +++ b/src/test/rbd_mirror/test_mock_ImageReplayer.cc @@ -21,7 +21,8 @@ struct MockTestImageCtx : public MockImageCtx { }; struct MockTestJournal : public MockJournal { - MOCK_METHOD1(start_external_replay, int(journal::Replay **)); + MOCK_METHOD2(start_external_replay, void(journal::Replay **, + Context *on_finish)); MOCK_METHOD0(stop_external_replay, void()); }; diff --git a/src/tools/rbd_mirror/ImageReplayer.cc b/src/tools/rbd_mirror/ImageReplayer.cc index 8d503516890b..42c90cd44908 100644 --- a/src/tools/rbd_mirror/ImageReplayer.cc +++ b/src/tools/rbd_mirror/ImageReplayer.cc @@ -465,7 +465,15 @@ template void ImageReplayer::start_replay() { dout(20) << dendl; - int r = m_local_image_ctx->journal->start_external_replay(&m_local_replay); + Context *ctx = create_context_callback< + ImageReplayer, &ImageReplayer::handle_start_replay>(this); + m_local_image_ctx->journal->start_external_replay(&m_local_replay, ctx); +} + +template +void ImageReplayer::handle_start_replay(int r) { + dout(20) << "r=" << r << dendl; + if (r < 0) { derr << "error starting external replay on local image " << m_local_image_id << ": " << cpp_strerror(r) << dendl; diff --git a/src/tools/rbd_mirror/ImageReplayer.h b/src/tools/rbd_mirror/ImageReplayer.h index b6bf4a25c443..6b0f993932c3 100644 --- a/src/tools/rbd_mirror/ImageReplayer.h +++ b/src/tools/rbd_mirror/ImageReplayer.h @@ -302,6 +302,7 @@ private: void handle_init_remote_journaler(int r); void start_replay(); + void handle_start_replay(int r); void replay_flush(); void handle_replay_flush(int r);