v0.13.15 — pos in on_progress, PatchOptions::reverse, wedged_threshold

Breaking: CopyOptions::on_progress + PatchOptions::on_progress now take
Fn(bytes_good, pos, total). Consumers display `pos` for "% swept" — the
true Pass 1 progress that advances through skip-forward bad zones, where
bytes_good (Finished sectors only) freezes. v0.13.14 live trace proved
the existing UI was lying for ~14 minutes about Dune 2 being "stuck at
30%" while Pass 1 was actually 83% through the disc via skip-forward.

PatchOptions::reverse: walk bad ranges from highest LBA to lowest. For
drives that wedge after a forward read of a bad sector, approaching the
post-bad-zone NonTrimmed range from end-of-disc reads good sectors before
the drive sees a bad one. Hypothesis informed by the BU40N + Initio
bridge live data — Pass 2 forward saw zero successful reads in 7 min
while Pass 1's pos walked all the way to end-of-disc.

PatchOptions::wedged_threshold: > 0 → exit early after that many
consecutive failures with zero successes in the same pass. Saves the
wallclock budget for productive grinding when the drive has wedged on
the bad zone for THIS pass; a different direction or block size in the
next pass may still recover. New PatchResult::wedged_exit reports it.

Trace: patch_start (block_sectors, recovery, reverse, wedged_threshold,
num_ranges) and patch_done (blocks_attempted, blocks_read_ok,
blocks_read_failed, wedged_exit, halted, bytes_recovered) at the
freemkv::disc target.
This commit is contained in:
MattJackson
2026-04-25 20:06:03 -07:00
parent 7bc54be8d3
commit e85e20f436
4 changed files with 151 additions and 11 deletions
+1 -1
View File
@@ -178,7 +178,7 @@ fn test_disc_copy_progress_callback_fires() {
let calls_cb = calls.clone();
let last_bytes_cb = last_bytes.clone();
let progress = move |bytes: u64, _total: u64| {
let progress = move |bytes: u64, _pos: u64, _total: u64| {
calls_cb.fetch_add(1, Ordering::Relaxed);
last_bytes_cb.store(bytes, Ordering::Relaxed);
};