LinkedIn Sourceforge

Vincent's Blog

Pleasure in the job puts perfection in the work (Aristote)

A proposition of Boot Environment for VoidLinux running on ZFS

Posted on 2026-09-24 21:22:00 from Vincent in VoidLinux

Give a shoutout to Irham Setyaki on unsplash.com If you run FreeBSD on ZFS, you probably can't imagine upgrading without bectl anymore. Take a boot environment, run freebsd-update or pkg upgrade, and if something goes wrong, reboot into the previous state. No backup to restore, no rescue USB stick.


vbe: bectl-style boot environments on Void Linux

As you saw in one of my previous post, I also run a Void Linux laptop with root on ZFS, and I missed that workflow
there. So I wrote vbe, a small POSIX sh script that brings the core
bectl concepts to Void Linux, using
ZFSBootMenu as the boot loader.

How it works

The idea is the same as on FreeBSD. A boot environment (BE) is a ZFS dataset
directly under a parent dataset, typically <pool>/ROOT:

vpool/ROOT/void          <- the system currently running
vpool/ROOT/pre-upgrade   <- a boot environment created before an upgrade

Creating a BE means taking a snapshot of the running root and cloning it.
Thanks to copy-on-write, this is instant and costs almost no space at first.

On the boot side, ZFSBootMenu plays the role of the FreeBSD loader. It finds
every dataset with mountpoint=/ in the pool, lets you pick one at boot, and
uses the pool's bootfs property as the default, just like FreeBSD.

Usage

The commands mirror bectl:

vbe list [-H]            # list boot environments
vbe create <name>        # snapshot + clone the running BE
vbe activate <name>      # make <name> the default BE (pool bootfs)
vbe destroy [-y] <name>  # destroy a BE and the snapshot created for it

Example output of vbe list:

BE          Active Mountpoint Space Created
pre-upgrade -      -          8.2M  2026-09-20 18:42
void        NR     /          6.1G  2025-11-03 10:15

The Active column has the same meaning as with bectl: N = active now,
R = active on reboot.

A typical upgrade

doas vbe create pre-upgrade
doas xbps-install -Su

If everything works, remove the safety copy later:

doas vbe destroy pre-upgrade

If the upgrade broke something, reboot, choose pre-upgrade in ZFSBootMenu,
then make it permanent:

doas vbe activate pre-upgrade
doas zfs promote vpool/ROOT/pre-upgrade   # reverse the clone dependency
doas vbe destroy void                     # remove the broken BE

The zfs promote step is needed because pre-upgrade is a clone of a
snapshot of void. Promoting it makes void the dependent one, so it can be
destroyed.

Assumptions

vbe deliberately keeps the same simple layout that bectl expects:

  • root on ZFS, booted through ZFSBootMenu;
  • /boot lives inside the BE, so kernel and initramfs roll back together
    with the system;
  • a BE has no child datasets: keep /home, logs and other data outside of
    ROOT, so that a rollback never touches your personal files;
  • kernel arguments are stored in the org.zfsbootmenu:commandline property
    on <pool>/ROOT, so every BE inherits them. vbe checks this before
    creating a BE and suggests the right command if it is missing.

Should I mention that, despite I'm on voidlinus, I'm using ksh, doas, openntpd, got, ... ?
After using OpenBSD since 2009 and FreeBSD since 2024, I have some bias and habits ;)

Differences from bectl

vbe is intentionally small. Compared to bectl:

  • there is no mount, rename or jail command;
  • there is no one-shot activation (bectl activate -t); to boot a BE once,
    simply pick it in ZFSBootMenu;
  • properties set locally on the running BE are not copied to the new one;
    set shared properties (compression, acltype, xattr...) on the parent
    dataset or the pool instead;
  • a BE is always created from the running system (no -e option).

It also refuses the dangerous cases: destroying the running BE, the default
BE (bootfs), or a BE that is currently mounted.

Installation

vbe is a single shell script with no dependencies beyond the ZFS tools and a
standard Void base system

You can get it from my repository: repo.vincentdelft.be/vbd

got clone ssh://anon@repo.vincentdelft.be/vbe
got checkout vbe.git
cd vbe
doas install -m 755 vbe /usr/local/bin/vbe

License: is BSD-2 clauses

Feedback

This is a small personal tool, but I'd be glad to hear from anyone who tries
it.
For sure, patches are welcome ;)

!!! Be careful that this is a early beta code !!!



👍 0, 👎 0
displayed: 52



What is the first vowel of the word Moon?