2 min readbfcfs-linux

One format, two kernels: mounting BFC on Linux and FreeBSD

The same read-only container format implemented as a Linux VFS module and a FreeBSD vnode filesystem, compared side by side.

A BFC container is a single file holding a directory tree. FUSE could mount one, but every read would cross from the kernel to userspace and back. For random reads over many small files, that round trip is most of the cost.

So there are two native kernel drivers: bfcfs-linux and bfcfs-freebsd. They read the same format, and the two kernels shape them differently.

Mounting

Linux FreeBSD
Registration register_filesystem, mount_nodev VFS_SET(…, VFCF_READONLY)
Backing file filp_open(source, O_RDONLY) resolved with namei
Options source=, verify=none|shallow|deep, noreadahead ro, noverify
# Linux
sudo mount -t bfcfs -o source=/tmp/app.bfc,verify=deep /mnt/app
# FreeBSD
doas mount -t bfcfs -o ro,noverify /home/user/mysite.bfc /mnt/bfc

Both read the footer and index at mount time, check the index CRC with the kernel’s own CRC32C, and keep the index in memory.

Lookup

  • Linux: a string table and a directory hierarchy are built at mount time. Inodes come from iget_locked, and directories implement lookup and iterate_shared.
  • FreeBSD: a vop_vector with lookup, open, read, readdir and getattr. Vnodes come from getnewvnode. Create and rename are refused at lookup.

Reading data

On Linux, file data goes through read_iter and the page cache through read_folio. Each object’s content offset is computed from the format (object header, then path, then padding to 16 bytes), and bytes come from the backing file with kernel_read.

On FreeBSD, reads go through VOP_READ on the backing vnode.

Where they stand

Both drivers handle uncompressed, unencrypted containers today, and both return “not supported” for anything else. The format’s ZSTD and ChaCha20-Poly1305 support exists in the userspace library but not in the kernels yet. On Linux, ZSTD and AEAD (keys via the kernel keyring) are the next two phases.

The FreeBSD driver is slightly ahead on symlinks, and it has an ATF/Kyua test suite that runs against a fixture container in CI. The Linux driver ships with DKMS configuration and the steps for signing the module with a Machine Owner Key, so it loads on Secure Boot systems.

The format did the heavy lifting

The format-specific code is the small part of each driver: read the footer, load the index, compute an offset. Most of the code is about each kernel’s object model, with inodes and folios on one side and vnodes and uio on the other. A simple format (index at the end, sorted paths, aligned content) is what made two drivers affordable.

← all writing