Skip to content

A commit whose committed-slot record cannot be written is a failed commit: the trial stays, and the next boot commits again - #258

Merged
DevomB merged 4 commits into
mainfrom
commit-record-fails
Oct 9, 2026
Merged

DevomB merged 4 commits into
mainfrom
commit-record-fails

Conversation

@DevomB

@DevomB DevomB commented Oct 9, 2026 •

Copy link
Copy Markdown
Owner

Follows #251 (esp-records-fsync, now on main); this PR's changes are e7ae447 and c346847.

What was wrong (found by 4e's non-author read of #251; it predates #251). commit_slot in boot-success returned 0 once BOOTX64.EFI was the slot's kernel, whatever became of the committed-slot record after it. If that record could not be written, the caller still:

  • cleared the trial,
  • recorded commit b,
  • forgot the firmware entries,
  • raised the clock's floor,

while the ESP still named slot a. On the next boot, boot-success found b running uncommitted and rebooted once for nothing. From then on kryptik-update apply (since #238) refused every apply from b until kryptik-recover --commit-slot b was run from the medium.

And the other way round (4e's second read). When the copy, flush or rename of BOOTX64.EFI failed, commit_slot still rewrote committed-slot to the trial's slot. The next boot took BOOTX64.EFI, which is the old slot, and kryptik-update refused applies from it because the ESP named another slot as committed.

What changed.

  • build/service-scripts/boot-success.sh: the record is part of the commit, and is written only once BOOTX64.EFI boots the slot. Failing to write it sets rc=1, the trial stays and commit-failed b is recorded. kryptik-efiboot appends its entries after the disk's own BOOTX64.EFI in BootOrder, and that file already boots b. So the next boot judges the same trial, finds BOOTX64.EFI already b, and writes only the record. The caller's message no longer claims "the committed slot is unchanged", which a failed record write makes untrue. It says the trial stays. kryptik-recover's put already dies on the same failure.
  • tools/update/kryptik-update: the staged kernel's flush and the version record's write say which failed, instead of exiting through set -e without a message (4e's INFO).
  • tools/tests/boot-success.sh: the sync stand-in can fail for committed-slot.new. One new case checks that the commit then fails, the record still names a, the trial is kept and no entries are forgotten. A second fails the BOOTX64.EFI flush and expects the old boot file, the record still naming a, and the trial kept.

How the run proves it. CI's fixture step runs the new case. Distro run 37877029582 boots through commits and applies in the update, install and integrity suites.

DevomB added 4 commits October 7, 2026 10:56
…are renamed into place, and boot-success writes no record nothing reads

On FAT only the rename is not atomic, so the kernels, BOOTX64.EFI and
kryptik-recover's records are written to a new name, fsynced, then renamed.
boot-success's committed-slot and kryptik-update's version-a/b skipped the
fsync: a power cut after the rename could leave the record with a cluster
that was never written, which the readers show as unknown and an apply then
refuses as naming no committed slot. Both now fsync first.

boot-success also copied version-X to version-committed on every commit.
Nothing reads it, and kryptik-recover --commit-slot never updated it, so it
could name the wrong release; it is no longer written.
…ed copy: the version and committed-slot records are written as the kernels are

It named two renames as the only non-atomic steps, and the version file and
committed-slot were renamed without an fsync before them.
…mmit: the trial stays, and the next boot commits again

boot-success's commit_slot returned 0 once BOOTX64.EFI was the slot's kernel,
whatever became of the committed-slot record. With the record unwritten, the
caller cleared the trial, recorded "commit b", forgot the entries and raised
the clock's floor while the ESP still named a: the next boot found b running
uncommitted and rebooted once for nothing, and kryptik-update refused every
apply from b until kryptik-recover --commit-slot b from the medium. Now the
record is part of the commit. Failing it keeps the trial, and since BOOTX64.EFI
already boots b and kryptik-efiboot's entries come after it in BootOrder, the
next boot finds BOOTX64.EFI already b and writes only the record.
kryptik-recover's put already dies the same way.

kryptik-update says which ESP write failed when the staged kernel's flush or
the version record fails, instead of leaving set -e to exit without a word.
…slot: a boot file that could not be replaced left the ESP naming a slot the firmware does not boot

From a non-author read: when the copy, flush or rename of BOOTX64.EFI failed,
commit_slot still rewrote committed-slot to the trial's slot. The next boot
took BOOTX64.EFI, the old slot, whose applies kryptik-update then refused as
not committed. The fixture fails that step and expects the record unchanged.
@DevomB
DevomB marked this pull request as ready for review October 9, 2026 03:58
@DevomB
DevomB merged commit b8157fb into main Oct 9, 2026
21 checks passed
@DevomB
DevomB deleted the commit-record-fails branch October 9, 2026 04:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant