FreeBSD, end to end: UFS, growfs, and native ZFS
FreeBSD ships two filesystems worth knowing: UFS, the traditional one, and ZFS, native in the base system. They also illustrate the two mental models better than anything else: UFS is the classic disk → partition → filesystem, and ZFS is disk → pool → dataset.
The videos show the commands; this page explains why they work. Every command
below ran on a disposable 2 GB disk (/dev/da1) in a FreeBSD 14.5 VM, never on
a disk I cared about.
The commands assume root, which is FreeBSD’s normal for disk work; prefix them
with sudo if your setup uses it.
UFS: the classic model
Create it
gpart create -s gpt da1
gpart add -s 1G -t freebsd-ufs da1
newfs -L data /dev/da1p1
mkdir -p /mnt/ufs
mount /dev/da1p1 /mnt/ufs
gpart is FreeBSD’s partition editor: create -s gpt writes a GPT,
add -t freebsd-ufs creates a partition of the right type. newfs is the
mkfs equivalent — it writes UFS2 and takes a label with -L.
The proof is the same as on Linux: write, unmount, mount, read.
echo 'hello from ufs' > /mnt/ufs/hello.txt
umount /mnt/ufs
mount /dev/da1p1 /mnt/ufs
cat /mnt/ufs/hello.txt
gpart show da1
df -h /mnt/ufs
Grow it
UFS grows in two steps, and the order matters:
gpart resize -i 1 da1 # grow the partition first
growfs -y /dev/da1p1 # then the filesystem
growfs extends the filesystem to fill the partition. On a modern FreeBSD it
can grow a mounted filesystem, which is why the series does it without
unmounting — and immediately reads the file back to prove nothing was lost.
Check and tune it
fsck_ufs is the offline checker, the UFS counterpart of e2fsck:
umount /mnt/ufs
fsck_ufs -f -y /dev/da1p1
-y answers yes to everything; -p (preen) only fixes what is safe. On a clean
scratch disk -y is fine; on a real disk, prefer -p.
Then the tunables. UFS reserves 8% of the filesystem by default. Unlike ext4’s
reserve, minfree also keeps the allocator efficient: below 5%, tunefs switches
from time to space optimisation and a full disk gets slow. Useful on /; -m 0
is fine for a scratch or mostly-static disk, less so for a busy one:
tunefs -m 0 /dev/da1p1
tunefs -p /dev/da1p1
mount /dev/da1p1 /mnt/ufs
df -h /mnt/ufs
tunefs -p prints the current settings; after -m 0 the reserve is gone and
df shows the freed space. Do not set this to 0 on a root filesystem you
might need to recover.
ZFS: the same disk, a different model
UFS lives inside a partition. ZFS does not: you hand devices to a pool, and
create datasets inside it. Same 2 GB disk, no newfs:
umount /mnt/ufs
gpart destroy -F da1
zpool create tank da1
zpool status tank
zfs list
zpool status is the pool health report — ONLINE, with read/write/checksum
error counters. zfs list shows the datasets and their mountpoints.
On FreeBSD, zpool create tank da1 uses the raw disk, no GPT: ZFS skips the
partition step entirely (on Linux it creates the partitions for you). For a real
system, set zfs_enable="YES" in /etc/rc.conf so the pool is imported and
mounted at boot.
Snapshots and rollback
A ZFS snapshot is a read-only point in time, created instantly:
zfs create tank/data
echo 'hello from zfs' > /tank/data/hello.txt
zfs snapshot tank/data@snap1
echo 'changed' > /tank/data/hello.txt
cat /tank/data/.zfs/snapshot/snap1/hello.txt # the old content
zfs rollback tank/data@snap1
cat /tank/data/hello.txt # old content again
The .zfs/snapshot/<name> path is how you read a snapshot without mounting
anything. zfs rollback throws away the changes since the snapshot — which is
exactly what you want after a bad edit, and exactly why a snapshot is not a
backup.
Scrub
Every block is checksummed; scrub reads it all back and verifies:
zpool scrub tank
zpool status tank
zpool status -v tank
On a healthy pool: scrub repaired 0B ... with 0 errors, ONLINE, and
No known data errors. FreeBSD’s periodic(8) can scrub for you: set
daily_scrub_zfs_enable="YES" in /etc/periodic.conf (every 35 days by
default), and read the result.
UFS or ZFS on FreeBSD?
- UFS is simple, fast, and predictable. It grows online with
growfs(it cannot shrink), it hasfsck_ufs, and it does not need much memory. UFS has snapshots (mksnap_ffs), but they are limited and mostly used internally bydump -Land background fsck; for everyday snapshots, use ZFS. - ZFS gives you checksums, snapshots, send/receive, compression, scrub and
boot environments (
bectl). It wants memory for the ARC and it does not shrink in place — apart fromzpool removeof a single-disk or mirror vdev, and only in pools without raidz. Plan capacity before you build the pool. - Boot environments are the FreeBSD feature worth learning next:
bectl(in the base system since FreeBSD 12) clones the root dataset via a snapshot, and you can select the clone in the bootloader. (beadmis the older port.)
What to remember
- UFS:
gpart→newfs; grow withgpart resize+growfs; check withfsck_ufs; the minfree reserve istunefs -m. - ZFS:
zpool create→zfs create; snapshots and rollback;zpool scrubto verify. - The models are different: partition → filesystem versus pool → dataset. Once that clicks, the commands follow.
- Snapshots are not backups, on any filesystem.
Part of Filesystems, end to end.