<< "op_tid=" << event.op_tid << dendl;
bool op_in_progress;
+ bool filter_ret_val;
Context *on_op_complete = nullptr;
Context *on_op_finish_event = nullptr;
{
op_in_progress = op_event.op_in_progress;
std::swap(on_op_complete, op_event.on_op_complete);
std::swap(on_op_finish_event, op_event.on_op_finish_event);
+
+ // special errors which indicate op never started but was recorded
+ // as failed in the journal
+ filter_ret_val = (op_event.op_finish_error_codes.count(event.r) != 0);
}
if (event.r < 0) {
// creating the op event
delete on_op_complete;
delete on_op_finish_event;
- handle_op_complete(event.op_tid, event.r);
+ handle_op_complete(event.op_tid, filter_ret_val ? 0 : event.r);
}
return;
}
event,
on_op_complete));
+ // ignore errors recorded in the journal
+ op_event->op_finish_error_codes = {-EBUSY};
+
// ignore errors caused due to replay
op_event->ignore_error_codes = {-EINVAL};
ASSERT_EQ(0, on_finish_safe.wait());
}
+TEST_F(TestMockJournalReplay, SnapUnprotectOpFinishBusy) {
+ REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockReplayImageCtx mock_image_ctx(*ictx);
+ MockJournalReplay mock_journal_replay(mock_image_ctx);
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ C_SaferCond on_start_ready;
+ C_SaferCond on_start_safe;
+ when_process(mock_journal_replay, EventEntry{SnapUnprotectEvent(123, "snap")},
+ &on_start_ready, &on_start_safe);
+ ASSERT_EQ(0, on_start_ready.wait());
+
+ // aborts the snap unprotect op if image had children
+ C_SaferCond on_finish_ready;
+ C_SaferCond on_finish_safe;
+ when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, -EBUSY)},
+ &on_finish_ready, &on_finish_safe);
+
+ ASSERT_EQ(0, on_start_safe.wait());
+ ASSERT_EQ(0, on_finish_safe.wait());
+ ASSERT_EQ(0, on_finish_ready.wait());
+}
+
TEST_F(TestMockJournalReplay, SnapUnprotectEventInvalid) {
REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);