The Unix Way ■ Episode 3
You are about to upgrade your operating system. The packages have been fetched, the changelogs reviewed, the maintenance window booked. There is one question that separates a professional deployment from a prayer: what happens if it breaks?
On FreeBSD, the answer is two commands and thirty seconds:
bectl create pre-upgrade && pkg upgrade
Done. If the upgrade breaks something (a kernel module fails to load, a service refuses to start, something in the dependency tree has developed strong opinions), you reboot, select the old boot environment from the bootloader menu, and carry on as though nothing happened. Because, from ZFS’s perspective, nothing did.
On Linux, the same safety net requires assembling the net yourself, from parts, in the dark, hoping none of them are load-bearing.
The Integration
The difference is not ZFS itself. The code is identical: the OpenZFS project maintains a single codebase for both platforms. The difference is where ZFS lives in the system architecture.
On FreeBSD, ZFS has been
in the kernel since 7.0
(2008). Root-on-ZFS became the default installer option in 10.0 (2014).
bectl, the boot environment manager, shipped
in base with
FreeBSD 12.0
(2018). No package to install. No configuration to discover. The
bootloader understands boot environments natively. And
freebsd-update creates a boot environment automatically
before applying patches. The safety net is not optional. It is the
default.
On Linux, ZFS occupies a rather more precarious position. The CDDL licence under which ZFS was released is considered incompatible with the GPL by most legal interpretations. Linus Torvalds, in January 2020, was characteristically succinct: “Don’t use ZFS.” This is not a technical objection. It is a legal one. And it has architectural consequences.
Because ZFS cannot live in the Linux kernel tree, it is distributed as an out-of-tree module compiled via DKMS (Dynamic Kernel Module Support). Every kernel update triggers a recompilation. If the module fails to build against the new kernel headers, ZFS disappears. If your root filesystem is on ZFS, so does your ability to boot.
The DKMS Lottery
This is not theoretical. The failures are documented, timestamped, and recurring.
Kernel 6.2.8 (March 2023): DKMS build failure. Kernel 6.4 (July 2023): DKMS build failure. Kernel 6.12 (January 2025): DKMS build failure. The pattern is not a coincidence. It is structural. An out-of-tree module must track kernel API changes it has no influence over, released on a schedule it does not control, by a project whose maintainer has publicly advised against its use.
On FreeBSD, there is no DKMS. There is no out-of-tree compilation. There is no kernel update that can remove ZFS from the system, because ZFS is the system. The module ships with the kernel. They are tested together, released together, and upgraded together. The failure mode that Linux users experience every few kernel releases simply does not exist.
The Boot Environment
A boot environment is a complete, bootable snapshot of your operating system. Not a backup. Not an image. A zero-cost clone of the live filesystem that the bootloader can select at startup. If the upgrade succeeds, you carry on. If it fails, you reboot into the previous environment. The failed state remains available for forensic examination or simply deletion.
On FreeBSD, bectl manages the lifecycle:
bectl create pre-upgrade: creates the safety net.
bectl list: shows all environments.
bectl activate pre-upgrade: rolls back on next boot.
bectl destroy failed-upgrade: removes the wreckage.
All in base. No package manager involved. The bootloader renders the
list of environments automatically. freebsd-update creates
a boot environment before applying patches, without being asked. The
safety net deploys itself.
On Linux, bectl does not exist. Ubuntu attempted to solve
this with
zsys,
a ZFS-based system state manager. Development ceased in 2021. The project’s
own GitHub issue tracker contains an entry whose title rather speaks for
itself:
“Don’t use ZSYS”.
No replacement was announced. The boot environment story on Linux is,
at the time of writing, a collection of third-party scripts, distribution-specific
workarounds, and hope.
How Snapshots Work
The mechanism is worth understanding, because it explains why boot environments are free and why the safety net has no performance cost.
ZFS is a copy-on-write filesystem. It never overwrites existing data. When a file changes, the new data is written to a different location on disc, and the metadata pointer is updated. The old blocks remain untouched until explicitly freed.
A snapshot simply freezes the metadata pointers at a given moment. No data is copied. The snapshot is instantaneous, sub-second regardless of dataset size. It consumes zero additional bytes at creation, because it references the same blocks as the live filesystem. Only as the live system diverges (as new writes land on new blocks) does the snapshot begin to consume space, and only for the blocks that have changed.
There is no performance penalty. There is no I/O storm. There is no “please wait while the snapshot completes” dialogue. You type the command, and it is done. The safety net costs nothing until you need it.
The Btrfs Question
“But what about Btrfs?” The reflexive counterpoint, and a fair one. openSUSE with snapper is the closest Linux gets to a native boot environment workflow, and it is genuinely useful. Credit where due: the openSUSE team has done serious work to make filesystem snapshots a first-class citizen.
The caveats, however, are non-trivial. Btrfs has no equivalent of
zfs send / zfs receive, the ability
to send an incremental snapshot stream to a remote machine, which is how
ZFS handles off-site replication without third-party tools. Btrfs’s
RAID5 and RAID6 implementation carries a
data loss warning
in its own documentation. And Btrfs reached production readiness around
2015, a decade after ZFS was deployed in production at Sun
Microsystems in 2005.
None of which makes Btrfs bad. It makes it younger, with a narrower feature set, operating in an ecosystem where filesystem-level safety nets are a distribution choice rather than a platform guarantee. openSUSE chose well. Most other distributions did not choose at all.
The Contract
The difference between FreeBSD and Linux here is not a difference of
technology. It is a difference of commitment. FreeBSD ships ZFS in the
kernel, bectl in base, boot environment support in the
bootloader, and automatic snapshots in the update tool. The safety net
is a system contract: if you upgrade, you can always go back.
Linux ships none of this. ZFS is legally complicated. Boot environments are a third-party concern. The update tools do not create snapshots. The bootloader does not know about them. The safety net is your responsibility, assembled from components that may or may not survive the next kernel release.
Same filesystem. Same copy-on-write semantics. Same sub-second snapshots. Same zero-byte initial cost. On one platform, it is infrastructure. On the other, it is an afterthought.
A safety net that requires assembly is not a safety net. It is a kit. FreeBSD ships the net. Linux ships the parts. The thirty seconds it takes to recover from a failed upgrade on FreeBSD is not a benchmark. It is a design decision, and it was made in 2008.