disc/patch: fast-capture reads fail-fast (no deep recovery)

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.
This commit is contained in:
Matthew Jackson
2026-06-30 17:08:26 -07:00
parent 22f0f5eb6f
commit 0cab32a08a
+8 -1
View File
@@ -1937,6 +1937,13 @@ impl<R: SectorSource + ?Sized> PatchCtx<'_, '_, R> {
// Single-shot read (no inline retry — see the historical note // Single-shot read (no inline retry — see the historical note
// in handle_read_failure). `recovery_read` widens a mid-unit // in handle_read_failure). `recovery_read` widens a mid-unit
// AACS window to the aligned unit; otherwise it's a plain read. // 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_start = std::time::Instant::now();
let read_result = recovery_read( let read_result = recovery_read(
self.reader, self.reader,
@@ -1944,7 +1951,7 @@ impl<R: SectorSource + ?Sized> PatchCtx<'_, '_, R> {
lba, lba,
count, count,
&mut self.buf, &mut self.buf,
self.state.recovery, recovery,
); );
let read_duration_ms = read_start.elapsed().as_millis(); let read_duration_ms = read_start.elapsed().as_millis();