OpenRiot v7.9.69 — The Machine Copies Itself and Lives

“The construct tried to make a copy of itself and the whole street went dark. It read every file, one by one, and asked the encrypted disk for each one twice, and the disk — the same disk it was using for memory — stopped answering. The force-reboot came. The filesystem came back dirty. The Turing Police would call it a ‘thrashing induced I/O deadlock on a shared block device’ and bill you for the diagnosis. We call it a mirror that melted the thing it was standing on. So we stopped walking the files one at a time and taught the machine to read its own raw skin, straight through, top to bottom, and write it down somewhere else. The copy lives. The machine lives. That’s the whole trick.” — The OpenRiot Crew, v7.9.69


Release Overview

Backing up the whole system to a bootable mirror used to freeze the machine. It doesn’t anymore. The drive manager gains a second clone path that reads the raw filesystem sequentially instead of walking 3.2TB of inodes, the swap that turned out to be the murderer is taken out of the equation, the target is checked and repaired before it’s used, and the cancel key finally, actually, cancels.

Total changes: a sequential dump | restore clone, swap discipline, a pre-mount fsck, a working cancel, and a progress bar that moves.


📦 The Sequential Clone

dump 0af - /dev/rsd1a | (cd /mnt/backup && restore -rf -)

The Problem: The only clone path was rsync. rsync walks the tree one inode at a time — millions of random seeks through the softraid crypto layer. Sequential reads are cheap; random reads are not. The crypto pipeline backs up, the disk stops answering, the machine locks, the force-reboot arrives, and you spend the morning in fsck.

The Fix: A second option under Full Backup — Clone to /mnt/backup (dump | restore). dump reads the raw filesystem cylinder-group by cylinder-group, in order, and pipes the stream to restore, which writes the actual files into the target. Same mirror as rsync. Sequential I/O instead of a random storm.

rsync stays for incremental runs — and it got harder to hurt you: nice -n 20, --delete-delay, --prune-empty-dirs, and a lower --bwlimit.


🔒 The Swap Was the Murderer

The Problem: Root, home, and swap all lived on one softraid crypto volume. Under memory pressure the kernel paged to swap — on the same encrypted disk rsync was already saturating — and the crypto layer deadlocked on itself. nice and --bwlimit only delayed it.

The Fix: The clone disables swap before it starts and restores it when it’s done, on every exit path — success, failure, or cancel. Without swap on the same device, the feedback loop has nowhere to form. There’s no dmesg for this. There is no error message. There is just a machine that doesn’t freeze.


🧹 The Filesystem Was Not Clean

The Problem: After a force-reboot the backup disk came back dirty — WARNING: R/W mount of /mnt/backup denied. Filesystem is not clean - run fsck — and the clone would run against a filesystem that refused to mount.

The Fix: Before cloning, if /mnt/backup isn’t already up, the machine runs fsck -y /dev/sd3a, then mounts it. If it’s already mounted, fsck is skipped — a clean reboot isn’t punished with an unnecessary check.


⏹️ ESC Means Stop

The Problem: Pressing ESC set a flag and changed the message to cancelled. It never touched the process. dump forks a small army of children; restore holds the mount. The TUI said “cancelled” while the disk kept grinding, and umount came back Device busy.

The Fix: A watcher kills the whole tree — dump, restore, rsync — the instant the flag is set. ESC means the machine stops. umount means umount.


📊 A Bar That Tells the Truth

The Problem: The progress bar sat at 0.0% forever. dump only reports its own percentage when it receives SIGINFO, which nothing was sending; restore’s per-file chatter churned the header; the number measured the root partition against a 3.4TB total so it barely moved; and the sweep animation only re-ticked on the other progress screen, so it froze after one frame. A cancel with no error message dereferenced a nil and panicked.

The Fix: Progress is measured from the target’s own growth against the partition being written, per partition — root climbs 0→100%, then home climbs 0→100%. The sweep animates on the clone screen too. The header keeps only the DUMP: lines, so it reads dumping (Pass IV) [regular files] instead of restore soup. And the cancel path no longer panics on a nil.


🧾 Files Changed

File Change
source/migrate/clone.go dump | restore sequential clone;
  swap disable/restore; pre-mount
  fsck; process-tree cancel kill;
  per-partition progress from disk use
source/migrate/model.go dump_clone routing; ESC kills the
  tree; nil-guarded cancel; cylon
  animation on the dump-progress screen
source/migrate/screens/menus.go New “dump | restore” Full Backup entry
source/migrate/ui.go Render the dump|restore clone correctly
~/.local/bin/backup-4tb Standalone sequential clone script

🗣️ Final Words

“The machine kept trying to copy itself and kept dying in the attempt, because it was reading its own skin one freckle at a time while breathing through the same wound. So we told it to read straight through, and to stop using its veins as its lungs, and to shut itself down when told. The copy boots. The original keeps running. The Turing Police will keep selling you a backup that phones home and a warranty that voids itself when you use it. We kept the mirror local and the machine awake.” — The OpenRiot Crew, v7.9.69