0007 — Boot-environment rollback model (three rungs, pre-boot)
Status: accepted (2026-06-22) — ratified by maintainer; proposed 2026-06-04
Context
System rollbacks happen pre-boot, inside keyboot — the one place the datasets
are idle (so zfs rollback/clone can’t fail on a busy mount) and a half-running
system can’t fight you or be corrupted. This is why ZFSBootMenu rolls back from
its own environment, not the booted OS.
zfs rollback is per-dataset and in-place, and its -r/-R flags only
destroy newer snapshots/clones of the same dataset — they do not recurse
into children (a common trap; zfs snapshot -r is recursive, rollback is
not). So any whole-system operation must iterate the recursive snapshot set
(ADR 0006 names), and rollback is not a single atomic command.
Decision
keyboot’s BE menu offers an escalating ladder, all operating on the recursive
snapshot set (root + BE-scoped /var + BE-scoped /home at the same name;
persistent rpool/data/* untouched):
- Boot read-only — boot the snapshot RO; zero side effects. Inspect.
- Rollback-clone (default, recommended) — clone the recursive snapshot set
into a new BE and boot it. The original BE + timeline are untouched;
reversible (destroy the clone). Adopt with
keyboot-install be promote. - Rollback-destroy —
zfs rollback -reach dataset in the set; discards all newer snapshots. Irreversible; explicit, unmistakable confirmation.
- Default system-rollback = consistent point-in-time across the BE-scoped set
(ADR 0005). Mixing versions (e.g. old
/var, current/home) is a deliberate recovery-shell, manual action — and is always safe because the only separately-rollbackable datasets are binary-independent (ADR 0005 keeps the package DB inside the BE).
Guards (the “many checks”)
- Rollback-destroy must detect dependent clones and REFUSE.
zfs rollback -rfails if a newer snapshot has a clone; the only force-past is-R -f, which destroys those clones — which may be other boot environments. The script must never auto-escalate to-R -f; it refuses with a clear message (“snapshot X is the origin of BEgentoo-test; promote or destroy it first”). - Clone → promote lifecycle. A clone is tethered to its origin snapshot; you
can’t reclaim the old timeline until
be promoteflips the origin. Keep the clone if good (be promote), destroy it if not (original pristine). - Visual unmistakability. The menu marks rung 3 as irreversible and separates it from the safe rungs.
Alternatives considered
- Only
zfs rollback(destructive): loses the forward timeline and footguns on dependent clones. Kept as rung 3 only, guarded. - Only clone-and-boot: can’t “just undo” or reclaim space immediately. Kept as rung 2 (default).
- In-OS rollback (from the booted system): dataset busy, can corrupt a running system. Rejected — pre-boot only.
- Recurse children automatically via some
rollback -rmagic: does not exist in ZFS. Rejected (script iterates the set).
Consequences
- The rollback engine is a checks-heavy script in keyboot’s recovery/menu stage (stage-8), using the full ZFS toolkit keyboot already ships.
keyboot-install be {clone, promote, destroy}(SPEC §14) are the clone lifecycle primitives this builds on.- Depends on ADR 0006’s recursive, consistently-named snapshot set.
- The BE-scoped-
/homedefault (ADR 0005) is safe because rung 2 is the default — clone-and-boot never destroys current/home; only the explicit rung 3 could, and only with confirmation.