From 0cab32a08a4803d6d0b338e2019cb9f3bb9f8c60 Mon Sep 17 00:00:00 2001 From: Matthew Jackson <1085847+MattJackson@users.noreply.github.com> Date: Tue, 30 Jun 2026 17:08:26 -0700 Subject: [PATCH] disc/patch: fast-capture reads fail-fast (no deep recovery) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A fast_capture pass defers every failed block to a granular pass anyway, so spending the drive's 60s deep-recovery timeout on it here only freezes the breadth-first sweep on a pure-bad cluster (~25s per 32-block, incl. NOT_READY grind). Read with recovery=false in fast_capture so a bad block fails on the short timeout (~10s) and the sweep steps on; the granular passes (fast_capture=false) do the deep recovery on what's left. No recovery lost — the block stays NonTrimmed for the granular retry. --- src/disc/patch.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/disc/patch.rs b/src/disc/patch.rs index 689a12d..7f08a0c 100644 --- a/src/disc/patch.rs +++ b/src/disc/patch.rs @@ -1937,6 +1937,13 @@ impl PatchCtx<'_, '_, R> { // Single-shot read (no inline retry — see the historical note // in handle_read_failure). `recovery_read` widens a mid-unit // AACS window to the aligned unit; otherwise it's a plain read. + // Fast-capture reads FAIL-FAST (no deep-recovery timeout): a block + // it can't read quickly is deferred to a granular pass anyway, so + // there's no point spending the drive's 60s recovery grind on it + // here — that just freezes the breadth-first sweep on a bad cluster + // (~25s/block). The granular passes (fast_capture = false) do the + // deep recovery on what's left. + let recovery = self.state.recovery && !self.opts.fast_capture; let read_start = std::time::Instant::now(); let read_result = recovery_read( self.reader, @@ -1944,7 +1951,7 @@ impl PatchCtx<'_, '_, R> { lba, count, &mut self.buf, - self.state.recovery, + recovery, ); let read_duration_ms = read_start.elapsed().as_millis();