Repository navigation
fix: a backup is not a baseline, and a re-run must not overwrite it - #21
Merged
Merged
Conversation
write used ONE 32 MB read for two jobs that are opposites the moment a
block is programmed. A BACKUP must hold the chip as it was ORIGINALLY. A
BASELINE must describe the chip as it is RIGHT NOW. They agree only until
the first write lands.
The dangerous half: stable_backup_path hands every run the same filename,
so run 2 re-read a half-written chip and wrote it over run 1's good backup.
The only copy of the old BIOS was destroyed silently, since the result is
still exactly chip-sized and looks like a valid dump. That is the failure
this module exists to prevent, reintroduced by the fix for the resume
cliff. The timestamped path it replaced could not clobber anything; it just
orphaned the sidecar.
A complete backup on disk now wins: it is never re-read and never
overwritten. Complete means right size and no resume sidecar, since a
sidecar exists only while a read is unfinished.
The other half: those bytes are then STALE as a baseline, so they are not
used as one. Handing them to the skip check would fail to skip exactly the
blocks an earlier run wrote, which is the resume itself. With no fresh
baseline the loop asks the chip per block instead. A backup read THIS run
is still used as the baseline, because it is fresh and it is free: it cost
a read that had to happen. Pre-reading every block instead would pay for a
read the block's own verify read-back already covers.
This also makes --skip-backup resumable, which it never was.
Fixes test isolation while here. write_chip_skips_blocks_that_already_hold
_the_target_image read and wrote the REAL ~/.local/share/ratchet/backups,
and was caught resuming a half-finished 16 MB dump another test left there
("resuming read of ef4018: 41.4% already captured"). A test must never
touch a user's only copy of their old BIOS. Two mock queues get deeper
because skip_backup now reads each block before writing it, which is a real
protocol change, not a brittle mock.
Both properties pinned by mutation. Always re-reading destroys the backup.
Feeding the stale backup in as a baseline re-erases blocks [0, 10000] that
already held the image.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
writeused ONE 32 MB read for two jobs that are opposites the moment a block is programmed.They agree only until the first write lands. After that, no single read can be both.
The dangerous half
stable_backup_path(from #19) hands every run the same filename. So on a failed write:ratchet-backup-<id>-<size>.bin. Correct.The only copy of the old BIOS is destroyed. Silently, because the result is still exactly chip-sized and looks like a valid dump. That is precisely the failure this module exists to prevent, reintroduced by the fix for the resume cliff. The timestamped path it replaced could not clobber anything; it merely orphaned the sidecar.
A complete backup on disk now wins: never re-read, never overwritten. "Complete" is right size and no resume sidecar, since a sidecar exists only while a read is unfinished.
The other half
Those same bytes are then STALE as a baseline, so they are not used as one. Handing them to the skip check would fail to skip exactly the blocks an earlier run wrote, which IS the resume. With no fresh baseline the loop asks the chip per block instead.
A backup read THIS run is still the baseline, because it is fresh (nothing is programmed yet) and free (it cost a read that had to happen anyway). Pre-reading every block instead would pay for a read that the block's own verify read-back already covers, and would make a first-run rewrite slower, not faster.
Side effect worth having:
--skip-backupis now resumable, which it never was. It used to forfeit the skip entirely and write every block blind.Test isolation
write_chip_skips_blocks_that_already_hold_the_target_imageread and wrote the REAL~/.local/share/ratchet/backups, and was caught resuming a half-finished 16 MB dump another test had left there:A test must never touch a user's only copy of their old BIOS. Sandboxed now.
Two mock queues get deeper because
skip_backupreads each block before writing it. That is a real protocol change, not a brittle mock.Tests
Both properties pinned by mutation:
[0, 10000]that already held the image.Results:
cargo test --workspace: exit 0, 518 + 16 + 10 + 5 passed, 0 failedcargo clippy --workspace --all-targets -- -D warnings: exit 0