ZFS on Linux: Pools, Datasets, Snapshots, and the Licensing Problem
ZFS combines the filesystem, the volume manager, and RAID into one system that knows about all three. That integration is what lets it detect silent corruption and repair it, snapshot instantly, and replicate a filesystem to another machine efficiently.
It also cannot be merged into the Linux kernel, and that single fact shapes the whole experience of running it.
The licensing problem
ZFS is licensed under the CDDL. The Linux kernel is GPLv2. The two are widely held to be incompatible for distribution as a combined work, so ZFS cannot be merged upstream.
Instead it ships as an out-of-tree kernel module, built against your running kernel by DKMS. Every kernel update triggers a rebuild, and if kernel internals changed in a way OpenZFS has not yet handled, the build fails.
The consequence is a habit you must form:
# After any kernel update, before rebooting
modinfo zfs | grep ^version
zpool status
On a system with ZFS root, rebooting into a kernel the module does not support means the pool does not import and the machine does not boot. OpenZFS 2.4.4 supports kernels up to 7.2, and checking the supported range before a kernel upgrade is not optional.
Pools and vdevs
The layout has two levels and getting it right at the start matters.
A vdev is a group of disks with a redundancy arrangement: a mirror, a RAIDZ group, or a single disk. A pool is one or more vdevs, striped together.
The critical implication: losing any vdev loses the entire pool. A pool made of two mirrors survives one failure per mirror; a pool with one mirror and one single disk dies when that single disk dies.
# Mirror of two
sudo zpool create tank mirror /dev/sdb /dev/sdc
# RAIDZ1, one parity, three disks
sudo zpool create tank raidz1 /dev/sdb /dev/sdc /dev/sdd
# RAIDZ2, two parity, six disks
sudo zpool create tank raidz2 /dev/sd{b,c,d,e,f,g}
# Two mirrors striped, the ZFS equivalent of RAID 10
sudo zpool create tank mirror /dev/sdb /dev/sdc mirror /dev/sdd /dev/sde
Use stable device names rather than /dev/sdb, which can change:
sudo zpool create tank mirror /dev/disk/by-id/ata-WDC_... /dev/disk/by-id/ata-WDC_...
Datasets
A dataset looks like a directory and behaves like a filesystem with its own properties. This is where ZFS becomes pleasant to use.
sudo zfs create tank/media
sudo zfs create tank/backups
sudo zfs create tank/vms
# Per-dataset properties
sudo zfs set compression=zstd tank/media
sudo zfs set recordsize=1M tank/media # large sequential files
sudo zfs set recordsize=16K tank/vms # database and VM images
sudo zfs set quota=500G tank/backups
sudo zfs set atime=off tank
Turn compression on. zstd is fast enough that it is usually a net performance gain, because less data read from disk beats a small amount of CPU.
Snapshots
sudo zfs snapshot tank/media@before-reorg
sudo zfs list -t snapshot
sudo zfs rollback tank/media@before-reorg
sudo zfs destroy tank/media@before-reorg
Snapshots are instant and initially free, consuming space only as blocks change afterwards. Browse one without rolling back:
ls /tank/media/.zfs/snapshot/before-reorg/
That hidden .zfs directory means recovering a single accidentally deleted file is a cp, not a restore.
Send and receive
# Full replication to another machine
sudo zfs send tank/media@snap1 | ssh backup-host sudo zfs recv backup/media
# Incremental, sending only what changed between snapshots
sudo zfs send -i tank/media@snap1 tank/media@snap2 | ssh backup-host sudo zfs recv backup/media
Incremental send transmits only changed blocks, identified by the filesystem itself rather than by scanning. For large datasets this is dramatically faster than rsync, which must walk the tree to find differences.
Scrubbing
sudo zpool scrub tank
zpool status tank
A scrub reads every block and verifies its checksum, repairing from redundancy where it finds corruption. This is ZFS’s distinguishing feature: silent corruption that ext4 would return to you as valid data gets detected and fixed.
Schedule it monthly. Most packages ship a timer.
Deduplication, briefly
Do not enable it.
It requires a large in-memory table proportional to pool size, the decision is effectively permanent for a dataset, and the space saved is almost always less than expected. Compression gives most of the benefit at a fraction of the cost.
The one-gigabyte-per-terabyte RAM guidance that follows ZFS around came from dedup. Without it, ZFS runs comfortably on ordinary amounts of memory.
Where ZFS fits
Good fit: a NAS or storage server where data integrity matters, anything you want to replicate to another machine, workloads that benefit from snapshots before risky changes.
Poor fit: a root filesystem on a machine you update aggressively, unless you are comfortable with the module dance. A laptop where Btrfs gives you snapshots without the out-of-tree module.
Our ext4, Btrfs, and XFS comparison covers the in-tree alternatives, and mdadm covers block-level RAID under any of them.
Frequently Asked Questions
Why is ZFS not in the Linux kernel?
Licensing. ZFS is under the CDDL and the kernel is GPLv2, and the two are widely considered incompatible for distribution as a combined work. So ZFS ships as an out-of-tree module that has to be rebuilt whenever kernel internals change.
What is the practical risk of an out-of-tree module?
A kernel update can arrive before ZFS supports it, and the module then fails to build. On a system with ZFS root that means it will not boot. Always confirm the module built before rebooting into a new kernel.
How much RAM does ZFS need?
Less than the folklore suggests. The old rule of one gigabyte per terabyte came from deduplication, which most people should not enable. Without dedup, ZFS runs fine on modest memory, though more RAM means a larger cache and better read performance.
Should I enable deduplication?
Almost certainly not. It requires a large in-memory table, it is effectively permanent for a dataset once enabled, and the space saved is rarely worth it. Compression gives most of the benefit at a fraction of the cost.
What does ZFS do that ext4 and XFS do not?
Checksums every block and repairs corruption automatically when redundancy exists, takes instant snapshots that cost only changed blocks, replicates efficiently to another machine with send and receive, and manages volumes and RAID itself rather than layering on mdadm and LVM.
Can I add a disk to an existing pool?
You can add another vdev, which widens the pool, and recent OpenZFS versions support expanding a RAIDZ vdev. What you historically could not do is grow a RAIDZ vdev in place, which is why pool layout planning matters more than with mdadm.