Skip to content

docs(spec): design for flash modes 1, 2, 3 - #24

Open
JanZachmann wants to merge 3 commits into
omnect:mainfrom
JanZachmann:feat/flash-modes-spec
Open

docs(spec): design for flash modes 1, 2, 3#24
JanZachmann wants to merge 3 commits into
omnect:mainfrom
JanZachmann:feat/flash-modes-spec

Conversation

@JanZachmann

@JanZachmann JanZachmann commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Design spec for porting the three flash modes from the legacy scripted initramfs to Rust. Docs only.

Shared layer (env keys, clear-trigger-first, dispatch point, feature gating, build-time constants) plus one section per mode. Implementation order 1 → 3 → 2.

§10 blocks implementation: six decisions where the spec keeps the conservative default but reviewers must confirm or overturn first.

Reason

Flash modes are the last feature block with no Rust equivalent, so they are what keeps the bash init.d scripts alive. Two places where a straight port would be wrong, both worth checking:

Mode 1 images the running rootfs with e2image. Legacy ran the flash modes at init.d/87, before fs-mount at 89, so rootCurrent was not mounted. The Rust flow mounts it at /sysroot before dispatch, and that boot-partition mount is not GRUB-conditional despite the legacy comment. Every mode now unmounts /sysroot fully before writing.

A queued factory reset no longer runs before a flash — legacy ran both (86, then 87), single-mode dispatch runs only the flash. Harmless for modes 2/3, where the reset would be overwritten anyway, but mode 1's source disk survives the clone, so that is a real behaviour change (§10.6).

The spec also fixes two bugs in flash-mode-1 rather than reproducing them: the destination-device wait treats success on its last iteration as failure, and the DOS extended-partition start is read via a relative path that cannot match the sfdisk dump it is compared against.

Signed-off-by: Jan Zachmann <jan.zachmann@conplement.de>
Signed-off-by: Jan Zachmann <jan.zachmann@conplement.de>
Signed-off-by: Jan Zachmann <jan.zachmann@conplement.de>

| Mode | What it does | Network | Gating |
|---|---|---|---|
| 1 | Clones the running disk onto another block device | no | on by default |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is currently this way, but given dehndetect which doesn't have a chance to provide flash-mode 1, this should probably be also gated by a feature in future.

Comment on lines +81 to +83
`init_setup` before a flash mode would resize a data partition that is about to
be cloned over or overwritten, and an extra-bootargs reboot would delay the
flash.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as far as I can see there is neither a "clone over" of a data partition nor any "overwrite":

  • mode 1 creates the data partition, formats it as ext4 and finally writes the flash-mode log to it
  • modes 2 and 3 just write the WIC data partition to the disk and enlarging of it happens on first-boot

Comment on lines +98 to +99
- **deviates** — the extra-bootargs sync step has no legacy counterpart and is
skipped for flash modes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that makes me ask which source base was used for that spec: while bootargs handling didn't exist when omnect-os-init started, it was implemented legacy first.

- `BootMode::Flash(FlashConfig)` — the new dispatch variant;
- `FlashMode::{Mode1, Mode2, Mode3}` — numeric, following the existing
`ResetMode::Mode1` and the operator-facing documentation;
- `ResetMode` stays the factory-reset wipe mode.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe off-topic but still: ResetMode could be misleading given that there a devices out there which can choose between a

  • soft-reset / warm start (incomplete board (re-)initialization), and
  • a hard-reset / cold start (full board initialization as during power-on)

we currently don't support such a device so my remark can be seen as purely academical but I wanted to utter it nevertheless.

| `e2image` | `/usr/sbin/e2image` | `e2fsprogs` | 1 |
| `mkfs.ext4` | `/usr/sbin/mkfs.ext4` | `e2fsprogs-mke2fs` | 1 |
| `tune2fs` | `/usr/sbin/tune2fs` | `e2fsprogs-tune2fs` | 1 |
| `uuidgen` | `/usr/bin/uuidgen` | `util-linux-uuidgen` | 1 |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have uuidgen expected to be a perfect candidate for a rust-native implementation and a short web search yielded crate uuid. I cannot tell whether it is sufficient nor whether it is a good choice, though.

Comment on lines +268 to +270
run both. It follows from single-mode dispatch — `BootMode` selects exactly one
handler — and it is the right outcome for modes 2 and 3, where the reset would be
undone moments later by the whole-disk overwrite.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

although it doesn't change anything on how flash modes should be handled (i.e. prioritized) I think the statement isn't fully correct:

  • factory reset operates on the current boot device, while
  • flash mode 1 operates on a different device

the bottom line is that a combination of factory reset and flash mode was never intended (while not making much sense if any), and the legacy behavior in that theoretic case can be neglected.

ok, should have read on, because that's exactly what is described below, but my comment remains valid.

Comment on lines +353 to +355
- U-Boot: write `/etc/omnect/uboot-env.bin` at both `UBOOT_ENV1_START` and
`UBOOT_ENV2_START`. This deliberately gives the destination a redundant
U-Boot environment even when the source image had only one.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that doesn't make sense: if a u-boot doesn't have a redundant environment defined in its configuration, it won't gain one by copying the default env block to a second location if there was a location defined for at all.

Comment on lines +544 to +549
- **Modes 2 and 3** — the whole disk is overwritten. Before flashing the outcome
is not yet known; after a failure the disk is in an unknown half-written state
and mounting anything on it is unsafe. Persistence is therefore best-effort
onto the freshly written data partition after a **successful** flash only. On
failure these modes leave nothing on disk, the same as legacy, and diagnosis
stays on kmsg and the console.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is correct as stated.
but maybe it would be worth considering to make log data persistent dependent on data partition state: if preparation worked or data partition wasn't touched yet, creation of the log file most likely would succeed, too. and as there are many errors that lead to fatal condition handling, there are several with a rather high probability that the system will come up again (after re-powering) what would allow investigating what happened after the fact.

Comment on lines +624 to +627
The default in §8.3 is a best-effort write after a successful flash, which costs
an extra mount of a just-written partition and yields nothing on the failures
where a log would help most.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

2 participants