From: Shai Fultheim Date: Sun, 17 May 2026 04:43:19 +0000 (+0300) Subject: crimson/os/seastore: fix IO-block deadlock when cleaner is sleeping X-Git-Tag: v21.0.1~157^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=c53bacdbcc2988efb027350d0f35c71c98749167;p=ceph.git crimson/os/seastore: fix IO-block deadlock when cleaner is sleeping Two coordinated changes that together close a stall observed at high alive_ratio in the qa/standalone/crimson randwrite bench (one OSD frozen for 70+ minutes, alive_ratio ~0.79, projected_avail_ratio ~0.10, slow_ops accumulating indefinitely). 1. SegmentCleaner::should_clean_space() used segments.get_available_ratio() (actual ratio) while should_block_io_on_clean() used get_projected_available_ratio() (actual minus in-flight reservations). When the actual ratio sat just above available_ratio_hard_limit but the projected ratio dipped below it, IO would block while the cleaner slept. Make should_clean_space() also trip on the projected ratio. 2. BackgroundProcess::reserve_projected_usage() did not wake the background process when an IO blocked. With the cleaner asleep and all IO blocked, nothing called maybe_wake_blocked_io() (no release_projected_usage runs without completing IO; no segment release runs without the cleaner). Kick do_wake_background() at the point of blocking, so the cleaner re-evaluates and runs. Signed-off-by: Shai Fultheim --- diff --git a/src/crimson/os/seastore/async_cleaner.h b/src/crimson/os/seastore/async_cleaner.h index a0ca2d1a056..cd3ee9e1a3a 100644 --- a/src/crimson/os/seastore/async_cleaner.h +++ b/src/crimson/os/seastore/async_cleaner.h @@ -1433,9 +1433,12 @@ public: return false; } auto aratio = segments.get_available_ratio(); + auto projected_aratio = get_projected_available_ratio(); auto rratio = get_reclaim_ratio(); + // should_block_io_on_clean() uses projected ratio; mirror that here so the + // cleaner wakes whenever IO would block, not only when actual space is low. return ( - (aratio < config.available_ratio_hard_limit) || + (projected_aratio < config.available_ratio_hard_limit) || ((aratio < config.available_ratio_gc_max) && (rratio > config.reclaim_ratio_gc_threshold)) ); diff --git a/src/crimson/os/seastore/extent_placement_manager.cc b/src/crimson/os/seastore/extent_placement_manager.cc index bfb0a3232a2..c579b5fd14f 100644 --- a/src/crimson/os/seastore/extent_placement_manager.cc +++ b/src/crimson/os/seastore/extent_placement_manager.cc @@ -755,8 +755,14 @@ ExtentPlacementManager::BackgroundProcess::reserve_projected_usage( ++stats.io_blocked_count; stats.io_blocked_sum += stats.io_blocking_num; - blocking_io = seastar::promise<>(); auto begin_time = seastar::lowres_system_clock::now(); + // IO blocked -> needs cleaner -> cleaner sleeping -> nothing runs -> deadlock. + // Kick the background so it can free space and call maybe_wake_blocked_io(). + auto arm_blocking_io_and_wake = [this] { + blocking_io = seastar::promise<>(); + do_wake_background(); + }; + arm_blocking_io_and_wake(); // we just blocked this IO, now wait until // maybe_wake_blocked_io will set value to blocking_io do { @@ -784,7 +790,7 @@ ExtentPlacementManager::BackgroundProcess::reserve_projected_usage( if (!res.cleaner_result.is_successful()) { ++stats.io_retried_blocked_count_clean; } - blocking_io = seastar::promise<>(); + arm_blocking_io_and_wake(); } } while (blocking_io); }