Getting BTRFS Boot Rollback Actually Working

I’ve been running BTRFS as my root filesystem for a while now, mostly for the snapshot support. Snapshots are one of those features that sound nice in theory and then quietly save your evening the first time a package update goes sideways. What I hadn’t gotten around to, until recently, was making those snapshots actually bootable from the bootloader itself, rather than something I could only inspect after the fact from a rescue environment.

The Goal

The idea is simple enough to describe. Before any package update touches my system, a snapshot of the root subvolume gets taken automatically. If that update breaks something, I want to be able to reboot, pick the pre-update snapshot from the bootloader menu, and boot straight into a working system, no manual mounting or chrooting required.

Getting there took three pieces working together: a pacman hook that takes the snapshot, a systemd-boot entry that can actually boot into it, and a small helper script to manage the whole thing.

The Pacman Hook

Pacman supports pre-transaction hooks, which run before any packages are installed or upgraded. Mine is about as simple as a hook gets:

[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *

[Action]
Description = Snapshotting root before package transaction
When = PreTransaction
Exec = /usr/local/bin/btrfs-pre-snapshot

The script it calls creates a read only snapshot of the root subvolume into a dedicated @rollback subvolume, tagged with a timestamp. I keep a single-parent policy here, meaning each new pre-transaction snapshot replaces the previous one rather than piling up indefinitely. I don’t need a full history of every single update, just a safety net for the most recent one.

Making the Snapshot Bootable

This is the part that took longer than I expected. A snapshot sitting on disk doesn’t do you any good if the bootloader has no way to point at it. systemd-boot reads boot entries as plain text files, so the fix is to generate a matching entry that boots the same kernel and initramfs, but with the root mount pointed at the rollback subvolume instead of the live one:

title   Arch Linux (rollback)
linux   /vmlinuz-linux
initrd  /initramfs-linux.img
options root=/dev/mapper/cryptroot rootflags=subvol=@rollback rw

The pre-transaction hook keeps this entry’s kernel and initramfs in sync with whatever is currently installed, since booting last week’s snapshot with this week’s kernel is a great way to turn a simple rollback into a much more interesting afternoon.

The Gotcha That Cost Me an Evening

For a while, booting into the rollback entry just silently dropped me back into the live root instead of the snapshot. Nothing crashed, it just wasn’t actually rolling back to anything. The cause turned out to be a subvolume ID pinned in /etc/fstab. I’d set up my root mount using a specific subvolid a long time ago for reasons I can no longer fully reconstruct, and that pin meant the kernel ignored the rootflags=subvol=@rollback option entirely and mounted whatever subvolume that ID pointed to instead.

Once I switched the fstab entry to mount by subvolume path rather than a hardcoded ID, the rollback option in the boot entry started actually being respected. It’s a small line in a config file, but it undid the entire point of the exercise until I noticed it.

The Helper Script

With the mechanics sorted, I wrapped the whole thing in a small helper script that can list available rollback snapshots, show which one the current rollback boot entry points at, and manually trigger a fresh snapshot outside of a package transaction if I want one before doing something riskier by hand, like a manual partition change.

Why Bother

I’ve actually used this rollback path since setting it up, and both times it turned what would have been a stressful troubleshooting session into a two minute reboot. That’s really the whole pitch for snapshots in general. They’re invisible right up until the moment something breaks, and then they’re the difference between a mild inconvenience and losing an evening to a broken bootloader.

· btrfs, snapshots, systemd-boot, arch-linux, backups