ZFS
Quick Reference
# Pool operations
zpool create tank /dev/sda # Single disk
zpool create tank mirror /dev/sda /dev/sdb # Mirror
zpool create tank raidz /dev/sda /dev/sdb /dev/sdc # RAIDZ
zpool status
zpool list
# Dataset operations
zfs create tank/data
zfs list
zfs set compression=zstd tank/data
zfs get all tank/data
# Snapshots
zfs snapshot tank/data@backup
zfs list -t snapshot
zfs rollback tank/data@backup
# Send/receive
zfs send tank/data@snap | zfs receive backup/data
Understanding ZFS
Key Concepts
ZFS combines a filesystem and volume manager into a single system:
-
Pool (zpool) - Storage pool aggregating multiple devices
-
Dataset - Filesystem or volume within a pool
-
Snapshot - Read-only point-in-time copy
-
Clone - Writable copy from a snapshot
-
vdev - Virtual device (single disk, mirror, raidz)
Installation
Arch Linux
# Install from AUR (DKMS method)
yay -S zfs-dkms
# Load module
sudo modprobe zfs
# Enable services
sudo systemctl enable zfs-import-cache.service
sudo systemctl enable zfs-mount.service
sudo systemctl enable zfs.target
Pool Management
Create Pools
# Single disk (no redundancy)
zpool create tank /dev/sda
# Mirror (RAID1 equivalent)
zpool create tank mirror /dev/sda /dev/sdb
# Three-way mirror
zpool create tank mirror /dev/sda /dev/sdb /dev/sdc
# RAIDZ (RAID5 equivalent, single parity)
zpool create tank raidz /dev/sda /dev/sdb /dev/sdc
# RAIDZ2 (RAID6 equivalent, double parity)
zpool create tank raidz2 /dev/sda /dev/sdb /dev/sdc /dev/sdd
# RAIDZ3 (triple parity)
zpool create tank raidz3 /dev/sd{a,b,c,d,e}
# Striped mirrors (RAID10 equivalent)
zpool create tank mirror /dev/sda /dev/sdb mirror /dev/sdc /dev/sdd
# With specific mount point
zpool create -m /data tank /dev/sda
# Without mounting
zpool create -m none tank /dev/sda
# Force creation (overwrite existing)
zpool create -f tank /dev/sda
Pool with Special Devices
# Add SSD cache (L2ARC)
zpool add tank cache /dev/nvme0n1
# Add SSD log (ZIL/SLOG)
zpool add tank log /dev/nvme0n1
# Mirrored log (recommended for production)
zpool add tank log mirror /dev/nvme0n1 /dev/nvme1n1
# Add hot spare
zpool add tank spare /dev/sdf
# Remove cache/log/spare
zpool remove tank /dev/nvme0n1
Pool Status and Information
# List pools
zpool list
zpool list -v # Verbose with vdevs
# Pool status
zpool status # All pools
zpool status tank # Specific pool
zpool status -x # Only pools with errors
# Pool history
zpool history tank
# I/O statistics
zpool iostat
zpool iostat tank 5 # Every 5 seconds
zpool iostat -v tank # Per-vdev stats
Pool Maintenance
# Scrub (verify data integrity)
zpool scrub tank
zpool scrub -s tank # Stop scrub
# Check scrub progress
zpool status tank
# Clear errors
zpool clear tank
# Export pool (safe removal)
zpool export tank
# Import pool
zpool import # List available
zpool import tank # Import by name
zpool import -d /dev/disk/by-id tank # Specify device path
zpool import -f tank # Force import
# Upgrade pool version
zpool upgrade tank
zpool upgrade -a # Upgrade all
Replace and Resilver
# Replace failed disk
zpool replace tank /dev/sda /dev/sdd
# Offline disk
zpool offline tank /dev/sda
# Online disk
zpool online tank /dev/sda
# Attach disk (convert single to mirror)
zpool attach tank /dev/sda /dev/sdb
# Detach disk (convert mirror to single)
zpool detach tank /dev/sdb
# Remove vdev (only works for certain configurations)
zpool remove tank /dev/sda
Dataset Management
Create Datasets
# Create dataset
zfs create tank/data
zfs create tank/data/documents
# Create with properties
zfs create -o compression=zstd -o mountpoint=/data tank/data
# Create volume (zvol) for block device
zfs create -V 50G tank/vm-disk
# Create sparse volume
zfs create -s -V 100G tank/thin-disk
List and Properties
# List all datasets
zfs list
# List with specific properties
zfs list -o name,used,avail,refer,mountpoint
# List snapshots
zfs list -t snapshot
# List volumes
zfs list -t volume
# Show all properties
zfs get all tank/data
# Show specific property
zfs get compression tank/data
zfs get compression,compressratio tank/data
# Show inherited properties
zfs get -s inherited all tank/data
Set Properties
# Enable compression
zfs set compression=zstd tank/data
zfs set compression=lz4 tank/data # Faster, lower ratio
zfs set compression=gzip-9 tank/data # Highest ratio
# Quota and reservation
zfs set quota=100G tank/data # Hard limit
zfs set refquota=100G tank/data # Limit excluding snapshots
zfs set reservation=50G tank/data # Guaranteed space
# Mount point
zfs set mountpoint=/data tank/data
zfs set mountpoint=none tank/data # Don't mount
# Access time
zfs set atime=off tank/data
# Deduplication (high memory usage)
zfs set dedup=on tank/data
# Record size (for specific workloads)
zfs set recordsize=1M tank/media # Large files
zfs set recordsize=16K tank/db # Databases
# Sync behavior
zfs set sync=disabled tank/scratch # Dangerous, fast
zfs set sync=standard tank/data # Default
Mount Operations
# Mount dataset
zfs mount tank/data
# Mount all datasets
zfs mount -a
# Unmount
zfs unmount tank/data
zfs unmount -f tank/data # Force
# Show mount points
zfs list -o name,mountpoint,mounted
# Legacy mount (for fstab)
zfs set mountpoint=legacy tank/data
# Then add to /etc/fstab:
# tank/data /data zfs defaults 0 0
Rename and Destroy
# Rename dataset
zfs rename tank/old tank/new
# Rename with mountpoint change
zfs rename -u tank/old tank/new
# Destroy dataset
zfs destroy tank/old
# Destroy recursively
zfs destroy -r tank/old
# Destroy with dependents (clones)
zfs destroy -R tank/old
# Dry run
zfs destroy -nv tank/old
Snapshots
Create Snapshots
# Create snapshot
zfs snapshot tank/data@today
zfs snapshot tank/data@$(date +%Y%m%d-%H%M%S)
# Recursive snapshot
zfs snapshot -r tank/data@backup
# Snapshot with hold (prevent deletion)
zfs snapshot tank/data@important
zfs hold keep tank/data@important
List and Manage Snapshots
# List snapshots
zfs list -t snapshot
zfs list -t snapshot -r tank/data
# Show snapshot space usage
zfs list -t snapshot -o name,used,refer
# Compare snapshots
zfs diff tank/data@snap1 tank/data@snap2
# Show what changed since snapshot
zfs diff tank/data@snap1
# Delete snapshot
zfs destroy tank/data@old
# Delete range of snapshots
zfs destroy tank/data@snap1%snap5
# Release hold
zfs release keep tank/data@important
Rollback
# Rollback to snapshot (destroys changes)
zfs rollback tank/data@snap
# Rollback destroying intermediate snapshots
zfs rollback -r tank/data@snap
# Rollback destroying clones too
zfs rollback -R tank/data@snap
Send/Receive (Backup)
Local Backup
# Send to file
zfs send tank/data@snap > /backup/data.zfs
# Send to another pool
zfs send tank/data@snap | zfs receive backup/data
# Send with properties
zfs send -p tank/data@snap | zfs receive backup/data
# Send recursive
zfs send -R tank/data@snap | zfs receive -d backup
# Resume interrupted receive
zfs send -t <token> | zfs receive backup/data
Incremental Backup
# Send incremental (changes between snapshots)
zfs send -i tank/data@snap1 tank/data@snap2 | zfs receive backup/data
# Incremental from any snapshot (replication stream)
zfs send -I tank/data@snap1 tank/data@snap2 | zfs receive backup/data
# Find common snapshot for incremental
zfs list -t snapshot -o name -s creation tank/data
zfs list -t snapshot -o name -s creation backup/data
Remote Backup
# Send over SSH
zfs send tank/data@snap | ssh user@remote zfs receive tank/data
# With compression
zfs send tank/data@snap | zstd | ssh user@remote 'zstd -d | zfs receive tank/data'
# With mbuffer for network stability
zfs send tank/data@snap | mbuffer -s 128k -m 1G | \
ssh user@remote 'mbuffer -s 128k -m 1G | zfs receive tank/data'
# Incremental remote
zfs send -i tank/data@old tank/data@new | \
ssh user@remote zfs receive -F tank/data
Automated Backup with Sanoid
# Install sanoid
# Arch
yay -S sanoid
# Debian/Ubuntu
sudo apt install sanoid
# Configure /etc/sanoid/sanoid.conf
[tank/data]
use_template = production
recursive = yes
[template_production]
frequently = 0
hourly = 24
daily = 30
monthly = 12
yearly = 2
autosnap = yes
autoprune = yes
# Run sanoid
sanoid --cron
# Replicate with syncoid
syncoid tank/data user@remote:backup/data
Performance Tuning
ARC (Adaptive Replacement Cache)
# View ARC stats
cat /proc/spl/kstat/zfs/arcstats
# Set maximum ARC size (in /etc/modprobe.d/zfs.conf)
options zfs zfs_arc_max=8589934592 # 8GB
# Runtime adjustment
echo 8589934592 > /sys/module/zfs/parameters/zfs_arc_max
# View current ARC size
arc_summary # Or:
cat /proc/spl/kstat/zfs/arcstats | grep "^size"
L2ARC (SSD Cache)
# Add L2ARC cache
zpool add tank cache /dev/nvme0n1
# View L2ARC stats
cat /proc/spl/kstat/zfs/arcstats | grep l2
# Tune L2ARC write speed
echo 524288000 > /sys/module/zfs/parameters/l2arc_write_max
ZIL/SLOG (Sync Write Acceleration)
# Add SLOG (mirrored for safety)
zpool add tank log mirror /dev/nvme0n1 /dev/nvme1n1
# For non-critical data, disable sync
zfs set sync=disabled tank/scratch
Dataset Tuning
# Large sequential files (media, backups)
zfs set recordsize=1M tank/media
# Databases
zfs set recordsize=16K tank/postgresql
zfs set primarycache=metadata tank/postgresql
zfs set logbias=throughput tank/postgresql
# VMs
zfs set recordsize=64K tank/vms
zfs set primarycache=metadata tank/vms
# High-performance
zfs set compression=lz4 tank/data
zfs set atime=off tank/data
zfs set xattr=sa tank/data
Troubleshooting
Check Pool Health
# Status with errors
zpool status -v tank
# Only show problems
zpool status -x
# Clear transient errors
zpool clear tank
# View error log
dmesg | grep -i zfs
Corrupted Data
# Scrub to detect corruption
zpool scrub tank
# If corruption found in RAIDZ:
# Data will be automatically repaired
# If corruption in non-redundant pool:
# Check for backup/snapshot
zfs list -t snapshot
# Restore from snapshot
zfs rollback tank/data@lastgood
Replace Failed Device
# Identify failed device
zpool status tank
# Replace with new device
zpool replace tank /dev/sda-old /dev/sda-new
# Monitor resilver progress
zpool status tank
# If device disappeared
zpool online tank /dev/sda # Try bringing back
# Mark as faulted manually
zpool offline tank /dev/sda
Security
Encryption
# Create encrypted dataset
zfs create -o encryption=aes-256-gcm -o keyformat=passphrase tank/secure
# Create with key file
dd if=/dev/urandom of=/root/zfs.key bs=32 count=1
zfs create -o encryption=aes-256-gcm -o keyformat=raw \
-o keylocation=file:///root/zfs.key tank/secure
# Load key for encrypted dataset
zfs load-key tank/secure
zfs mount tank/secure
# Unload key (unmount first)
zfs unmount tank/secure
zfs unload-key tank/secure
# Change key
zfs change-key tank/secure
# Key status
zfs get keystatus tank/secure
Quick Command Reference
# Pool
zpool create tank mirror /dev/sd{a,b} # Create mirror
zpool status # Pool health
zpool list # Pool usage
zpool scrub tank # Verify integrity
zpool destroy tank # Remove pool
# Dataset
zfs create tank/data # Create dataset
zfs list # List datasets
zfs set compression=zstd tank/data # Set property
zfs get all tank/data # Get properties
zfs destroy tank/data # Remove dataset
# Snapshot
zfs snapshot tank/data@name # Create snapshot
zfs list -t snapshot # List snapshots
zfs rollback tank/data@name # Restore snapshot
zfs destroy tank/data@name # Remove snapshot
# Send/Receive
zfs send tank/data@snap | zfs receive pool/data # Full send
zfs send -i @old @new | zfs receive pool/data # Incremental