Skip to content

Commit 6fb5be5

Browse files
authored
Merge pull request ceph#52057 from nbalacha/tracker-61672
rbd-mirror: fix race preventing local image deletion Reviewed-by: Ilya Dryomov <[email protected]> Reviewed-by: Prasanna Kumar Kalever <[email protected]> Reviewed-by: Mykola Golub <[email protected]>
2 parents 104bec4 + 1df7921 commit 6fb5be5

File tree

3 files changed

+107
-5
lines changed

3 files changed

+107
-5
lines changed

src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,59 @@ TEST_F(TestMockImageReplayerBootstrapRequest, PrepareRemoteImageNotPrimaryLocalL
636636
ASSERT_EQ(0, ctx.wait());
637637
}
638638

639+
TEST_F(TestMockImageReplayerBootstrapRequest, PrepareRemoteImageDNELocalLinked) {
640+
InSequence seq;
641+
642+
// prepare local image
643+
MockPrepareLocalImageRequest mock_prepare_local_image_request;
644+
MockStateBuilder mock_state_builder;
645+
expect_send(mock_prepare_local_image_request, mock_state_builder,
646+
m_local_image_ctx->id, m_local_image_ctx->name, 0);
647+
648+
// prepare remote image
649+
MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
650+
expect_send(mock_prepare_remote_image_request, mock_state_builder,
651+
"remote mirror uuid", m_remote_image_ctx->id, -ENOENT);
652+
expect_is_local_primary(mock_state_builder, false);
653+
expect_is_linked(mock_state_builder, true);
654+
655+
C_SaferCond ctx;
656+
MockThreads mock_threads(m_threads);
657+
MockInstanceWatcher mock_instance_watcher;
658+
MockBootstrapRequest *request = create_request(
659+
&mock_threads, &mock_instance_watcher, "global image id",
660+
"local mirror uuid", &ctx);
661+
request->send();
662+
ASSERT_EQ(-ENOLINK, ctx.wait());
663+
}
664+
665+
TEST_F(TestMockImageReplayerBootstrapRequest, PrepareRemoteImageDNELocalLinkedCanceled) {
666+
InSequence seq;
667+
668+
// prepare local image
669+
MockPrepareLocalImageRequest mock_prepare_local_image_request;
670+
MockStateBuilder mock_state_builder;
671+
expect_send(mock_prepare_local_image_request, mock_state_builder,
672+
m_local_image_ctx->id, m_local_image_ctx->name, 0);
673+
674+
// prepare remote image
675+
MockPrepareRemoteImageRequest mock_prepare_remote_image_request;
676+
expect_send(mock_prepare_remote_image_request, mock_state_builder,
677+
"remote mirror uuid", m_remote_image_ctx->id, -ENOENT);
678+
expect_is_local_primary(mock_state_builder, false);
679+
expect_is_linked(mock_state_builder, true);
680+
681+
C_SaferCond ctx;
682+
MockThreads mock_threads(m_threads);
683+
MockInstanceWatcher mock_instance_watcher;
684+
MockBootstrapRequest *request = create_request(
685+
&mock_threads, &mock_instance_watcher, "global image id",
686+
"local mirror uuid", &ctx);
687+
request->cancel();
688+
request->send();
689+
ASSERT_EQ(-ENOLINK, ctx.wait());
690+
}
691+
639692
TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImageError) {
640693
InSequence seq;
641694

src/test/rbd_mirror/test_mock_ImageReplayer.cc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,45 @@ TEST_F(TestMockImageReplayer, BootstrapCancel) {
620620
ASSERT_EQ(-ECANCELED, start_ctx.wait());
621621
}
622622

623+
TEST_F(TestMockImageReplayer, BootstrapRemoteDeletedCancel) {
624+
create_local_image();
625+
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
626+
627+
MockThreads mock_threads(m_threads);
628+
expect_work_queue_repeatedly(mock_threads);
629+
expect_add_event_after_repeatedly(mock_threads);
630+
631+
MockImageDeleter mock_image_deleter;
632+
633+
expect_set_mirror_image_status_repeatedly();
634+
635+
InSequence seq;
636+
637+
MockBootstrapRequest mock_bootstrap_request;
638+
MockStateBuilder mock_state_builder;
639+
EXPECT_CALL(mock_bootstrap_request, send())
640+
.WillOnce(Invoke([this, &mock_bootstrap_request, &mock_state_builder,
641+
&mock_local_image_ctx]() {
642+
mock_state_builder.local_image_id = mock_local_image_ctx.id;
643+
mock_state_builder.remote_image_id = "";
644+
*mock_bootstrap_request.state_builder = &mock_state_builder;
645+
m_image_replayer->stop(nullptr);
646+
mock_bootstrap_request.on_finish->complete(-ENOLINK);
647+
}));
648+
EXPECT_CALL(mock_bootstrap_request, cancel());
649+
650+
expect_close(mock_state_builder, 0);
651+
652+
expect_trash_move(mock_image_deleter, "global image id", false, 0);
653+
expect_mirror_image_status_exists(false);
654+
655+
create_image_replayer(mock_threads);
656+
657+
C_SaferCond start_ctx;
658+
m_image_replayer->start(&start_ctx);
659+
ASSERT_EQ(-ECANCELED, start_ctx.wait());
660+
}
661+
623662
TEST_F(TestMockImageReplayer, StopError) {
624663
// START
625664

src/tools/rbd_mirror/ImageReplayer.cc

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,6 @@ void ImageReplayer<I>::bootstrap() {
348348
ceph_assert(!m_peers.empty());
349349
m_remote_image_peer = *m_peers.begin();
350350

351-
if (on_start_interrupted(m_lock)) {
352-
return;
353-
}
354-
355351
ceph_assert(m_state_builder == nullptr);
356352
auto ctx = create_context_callback<
357353
ImageReplayer, &ImageReplayer<I>::handle_bootstrap>(this);
@@ -364,6 +360,13 @@ void ImageReplayer<I>::bootstrap() {
364360

365361
request->get();
366362
m_bootstrap_request = request;
363+
364+
// proceed even if stop was requested to allow for m_delete_requested
365+
// to get set; cancel() would prevent BootstrapRequest from going into
366+
// image sync
367+
if (m_stop_requested) {
368+
request->cancel();
369+
}
367370
locker.unlock();
368371

369372
update_mirror_image_status(false, boost::none);
@@ -379,6 +382,14 @@ void ImageReplayer<I>::handle_bootstrap(int r) {
379382
m_bootstrap_request = nullptr;
380383
}
381384

385+
// set m_delete_requested early to ensure that in case remote
386+
// image no longer exists local image gets deleted even if start
387+
// is interrupted
388+
if (r == -ENOLINK) {
389+
dout(5) << "remote image no longer exists" << dendl;
390+
m_delete_requested = true;
391+
}
392+
382393
if (on_start_interrupted()) {
383394
return;
384395
} else if (r == -ENOMSG) {
@@ -393,7 +404,6 @@ void ImageReplayer<I>::handle_bootstrap(int r) {
393404
on_start_fail(r, "split-brain detected");
394405
return;
395406
} else if (r == -ENOLINK) {
396-
m_delete_requested = true;
397407
on_start_fail(0, "remote image no longer exists");
398408
return;
399409
} else if (r == -ERESTART) {

0 commit comments

Comments
 (0)