Skip to content

ZFS for Homelabbers: Pools, Datasets, and Snapshots

· 4 min read · 743 words
Contents

What Makes ZFS Different?

ZFS is not just a filesystem — it’s a combined volume manager and filesystem. Everything from disk management to RAID to snapshots to checksumming is handled in one stack. This matters because:

  • Every block is checksummed. Silent data corruption (bit rot) is detected and, with redundancy, automatically corrected.
  • Snapshots are instant and cheap. A snapshot is just a pointer — it consumes no space until you delete data that the snapshot still references.
  • Copy-on-write semantics. Writes never overwrite existing data. Torn writes (partial writes during power failure) cannot corrupt the filesystem.
  • Compression is transparent. Enable it on a dataset and the CPU handles compression/decompression invisibly.

ZFS does not protect against drive failure any better than hardware RAID — it has the same RAIDZ fault tolerance. What it protects against is silent corruption, which hardware RAID controllers can silently propagate.

Terminology

TermMeaning
PoolThe top-level storage container. Spans one or more vdevs.
vdevA virtual device — a group of drives in a RAID configuration
DatasetA filesystem within a pool. Inherits pool settings, can override them.
ZvolA block device within a pool. Used for iSCSI, swap, VMs.
ARCAdaptive Replacement Cache — ZFS uses RAM for read caching
L2ARCSecond-level read cache on a fast SSD
SLOGZFS Intent Log — SSD for synchronous write acceleration

Pool Layouts

Mirror

Two drives, exact copy. Can lose one drive and keep running.

zpool create tank mirror sda sdb

Can add more mirror vdevs to expand (striped mirrors = RAID 10):

zpool add tank mirror sdc sdd

RAIDZ1 / RAIDZ2 / RAIDZ3

Variable stripe width with 1, 2, or 3 parity drives. RAIDZ cannot be expanded by adding drives later (without full replacement).

zpool create tank raidz2 sda sdb sdc sdd sde sdf  # 6 drives, 2 parity

Usable space: N - parity drives. With 6 drives RAIDZ2: 4 drives usable.

Recommendation for Homelabs

  • 2 drives: mirror
  • 4 drives: 2x mirrors (striped), not RAIDZ1 (better performance and expandable)
  • 6+ drives: RAIDZ2 or 3x mirrors

Working with Datasets

Create a dataset:

zfs create tank/media
zfs create tank/backups
zfs create tank/documents

Properties

Set compression on a dataset:

zfs set compression=lz4 tank/media        # fast, good ratio
zfs set compression=zstd tank/documents   # better compression, more CPU

Disable access time updates (reduces writes on busy datasets):

zfs set atime=off tank/media

Set a quota:

zfs set quota=500G tank/media

List dataset properties:

zfs get compression,atime,quota tank/media

Inheritance

Child datasets inherit parent settings. Set compression on the pool root and all new datasets inherit it:

zfs set compression=lz4 tank

Snapshots

Create a snapshot:

zfs snapshot tank/documents@2026-03-01

List snapshots:

zfs list -t snapshot

Roll back a dataset to a snapshot (destroys all changes since):

zfs rollback tank/documents@2026-03-01

Access snapshot contents without rolling back — ZFS exposes snapshots in a .zfs/snapshot/ directory:

ls /tank/documents/.zfs/snapshot/2026-03-01/

Delete a snapshot:

zfs destroy tank/documents@2026-03-01

Automated Snapshots

Use zfs-auto-snapshot or sanoid for policy-based automated snapshots.

Install sanoid on Debian:

apt install sanoid

Edit /etc/sanoid/sanoid.conf:

[tank/documents]
  use_template = production

[tank/media]
  use_template = media
  recursive = yes

[template_production]
  frequently = 0
  hourly = 24
  daily = 30
  weekly = 8
  monthly = 12
  autosnap = yes
  autoprune = yes

[template_media]
  daily = 7
  weekly = 4
  autosnap = yes
  autoprune = yes

Enable the systemd timer:

systemctl enable --now sanoid.timer

Replication

Send a dataset to another pool (local or remote):

# Initial send
zfs send -R tank/documents@2026-03-01 | zfs receive backup/documents

# Incremental send (only changes since last snapshot)
zfs send -i @2026-03-01 tank/documents@2026-03-09 | zfs receive backup/documents

For automated incremental replication, use syncoid (part of the sanoid project):

syncoid tank/documents backup-server:backup/documents

This is how you build proper offsite backups — replicate to a machine at a different physical location.

Scrubs

A scrub reads all data, verifies checksums, and repairs any corrupted blocks that can be corrected using redundancy:

zpool scrub tank
zpool status tank  # check progress and results

Schedule monthly scrubs via cron:

0 2 1 * * zpool scrub tank

A clean scrub output looks like:

errors: No known data errors

Any errors reported mean you have hardware issues to investigate. Replace failing drives promptly — resilver (rebuild) time on large drives with degraded performance can take days.

Checking Pool Health

zpool status -v  # verbose, shows any errors per drive
zpool iostat -v  # per-vdev I/O statistics

A healthy pool shows ONLINE for all components. DEGRADED means a drive has failed but the pool is still running. FAULTED means the pool is down.