From 551bb50c32805fefde550068751dfad2c113d650 Mon Sep 17 00:00:00 2001 From: Bill Scales Date: Mon, 23 Jun 2025 10:12:10 +0100 Subject: [PATCH] osd: rewind_divergent_log needs to dirty log if crt changes or ... rollback_info_trimmed_to changes PGLog::rewind_divergent_log was only causing the log to be marked dirty and checkpointed if there were divergent entries. However after a PG split it is possible that the log can be rewound modifying crt and/or rollback_info_trimmed_to without creating divergent entries because the entries being rolled back were all split into the other PG. Failing to checkpoint the log generates a window where if the OSD is reset you can end up with crt (and rollback_info_trimmed_to) > head. One consequence of this is asserts like ceph_assert(rollback_info_trimmed_to == head); firing. Fixes: https://tracker.ceph.com/issues/55141 Signed-off-by: Bill Scales (cherry picked from commit d8f78adf85f8cb11deeae3683a28db92046779b5) --- src/osd/PGLog.cc | 10 +++++++++- src/osd/PGLog.h | 4 ++-- src/osd/osd_types.h | 14 +++++++++++--- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/osd/PGLog.cc b/src/osd/PGLog.cc index 07e3f30b6c820..20d9300902e15 100644 --- a/src/osd/PGLog.cc +++ b/src/osd/PGLog.cc @@ -349,10 +349,18 @@ void PGLog::rewind_divergent_log(eversion_t newhead, if (info.last_complete > newhead) info.last_complete = newhead; - auto divergent = log.rewind_from_head(newhead); + bool need_dirty_log; + auto divergent = log.rewind_from_head(newhead, &need_dirty_log); if (!divergent.empty()) { mark_dirty_from(divergent.front().version); + } else if (need_dirty_log) { + // can_rollback_to and/or rollback_info_trimmed_to have been modified + // and need checkpointing + dout(10) << "rewind_divergent_log crt = " + << log.get_can_rollback_to() << dendl; + dirty_log = true; } + for (auto &&entry: divergent) { dout(10) << "rewind_divergent_log future divergent " << entry << dendl; } diff --git a/src/osd/PGLog.h b/src/osd/PGLog.h index 07390eebe1dec..f7d0386d9cf81 100644 --- a/src/osd/PGLog.h +++ b/src/osd/PGLog.h @@ -296,8 +296,8 @@ public: eversion_t previous_version) {}); } - mempool::osd_pglog::list rewind_from_head(eversion_t newhead) { - auto divergent = pg_log_t::rewind_from_head(newhead); + mempool::osd_pglog::list rewind_from_head(eversion_t newhead, bool *dirty_log = nullptr) { + auto divergent = pg_log_t::rewind_from_head(newhead, dirty_log); index(); reset_rollback_info_trimmed_to_riter(); return divergent; diff --git a/src/osd/osd_types.h b/src/osd/osd_types.h index 5a58dddaf80e3..607b030da7d1d 100644 --- a/src/osd/osd_types.h +++ b/src/osd/osd_types.h @@ -4738,7 +4738,7 @@ public: std::move(childdups)); } - mempool::osd_pglog::list rewind_from_head(eversion_t newhead) { + mempool::osd_pglog::list rewind_from_head(eversion_t newhead, bool *dirty_log = nullptr) { ceph_assert(newhead >= tail); mempool::osd_pglog::list::iterator p = log.end(); @@ -4768,11 +4768,19 @@ public: } head = newhead; - if (can_rollback_to > newhead) + if (can_rollback_to > newhead) { can_rollback_to = newhead; + if (dirty_log) { + *dirty_log = true; + } + } - if (rollback_info_trimmed_to > newhead) + if (rollback_info_trimmed_to > newhead) { rollback_info_trimmed_to = newhead; + if (dirty_log) { + *dirty_log = true; + } + } return divergent; } -- 2.39.5