Linux Filesystem Complete Comparison โ ext4 vs XFS vs Btrfs vs ZFS: Format, Mount, and Hands-On Commands
Linux Filesystem Complete Comparison โ ext4, XFS, Btrfs, ZFS
"Which filesystem should I format with?" It is the first question you run into when setting up a Linux server. To start from the conclusion, the right answer differs by purpose. This piece organizes the technical differences of the four major filesystems together with real commands.
1. The Four Filesystems at a Glance
| Item | ext4 | XFS | Btrfs | ZFS |
|---|---|---|---|---|
| Max volume | 1 EB | 8 EB | 16 EB | 256 ZiB |
| Max file | 16 TB | 8 EB | 16 EB | 16 EB |
| Snapshot | Not supported (LVM needed) | Not supported (LVM needed) | Built-in (CoW) | Built-in (powerful) |
| Compression | Not supported | Not supported | Built-in (zstd/lzo) | Built-in (lz4/zstd) |
| Built-in RAID | mdadm separate | mdadm separate | Built-in RAID 0/1/5/6/10 | RAID-Z1/Z2/Z3 |
| Shrink | Possible | Not possible | Possible | Not possible |
| Memory use | Very low | Low | Moderate | High (1GB+ RAM per TB) |
| Built into kernel | Yes | Yes | Yes | No (separate install) |
| Typical use | General OS/server | DB/media server | NAS/backup/virtualization | Storage server |
2. Format Commands โ Hands-On Code
Formatting and Mounting ext4
# Create a partition (e.g., /dev/sdb1)
sudo parted /dev/sdb mklabel gpt
sudo parted /dev/sdb mkpart primary ext4 0% 100%
# Format ext4
sudo mkfs.ext4 -L "data" /dev/sdb1
# Mount
sudo mkdir -p /mnt/data
sudo mount /dev/sdb1 /mnt/data
# Register auto-mount in fstab (UUID recommended)
UUID=$(blkid -s UUID -o value /dev/sdb1)
echo "UUID=$UUID /mnt/data ext4 defaults,noatime 0 2" | sudo tee -a /etc/fstab
Formatting and Mounting XFS
# Format XFS
sudo mkfs.xfs -L "data-xfs" /dev/sdb1
# Mount
sudo mkdir -p /mnt/data
sudo mount /dev/sdb1 /mnt/data
# Register in fstab
UUID=$(blkid -s UUID -o value /dev/sdb1)
echo "UUID=$UUID /mnt/data xfs defaults,noatime 0 2" | sudo tee -a /etc/fstab
Formatting and Mounting Btrfs
# Format Btrfs (single disk)
sudo mkfs.btrfs -L "data-btrfs" /dev/sdb1
# Mount
sudo mkdir -p /mnt/data
sudo mount /dev/sdb1 /mnt/data
# Mount with compression enabled (zstd)
sudo mount -o compress=zstd /dev/sdb1 /mnt/data
# Register in fstab
UUID=$(blkid -s UUID -o value /dev/sdb1)
echo "UUID=$UUID /mnt/data btrfs defaults,compress=zstd,noatime 0 0" | sudo tee -a /etc/fstab
Formatting and Mounting ZFS
# Create a ZFS pool (single disk)
sudo zpool create -f data-pool /dev/sdb1
# Create a ZFS filesystem
sudo zfs create -o compression=lz4 -o atime=off data-pool/data
# Check the mount
zfs list
3. Snapshots โ Why They Matter
A snapshot is a feature that copies the filesystem state at a specific point in time. It is a core means of protecting data from ransomware, accidental deletion, failed system updates, and more.
Btrfs Snapshots
# Create a snapshot (instant, uses almost no space)
sudo btrfs subvolume snapshot /mnt/data /mnt/data/snapshots/snap-$(date +%Y%m%d)
# List snapshots
sudo btrfs subvolume list /mnt/data
# Recover from a snapshot
sudo btrfs subvolume delete /mnt/data
sudo btrfs subvolume snapshot /mnt/data/snapshots/snap-20260923 /mnt/data
# Automatic snapshots (cron registration example)
echo "0 */6 * * * root btrfs subvolume snapshot /mnt/data /mnt/data/snapshots/snap-\$(date +\%Y\%m\%d-\%H\%M)" | sudo tee /etc/cron.d/btrfs-snapshot
ZFS Snapshots
# Create a snapshot
sudo zfs snapshot data-pool/data@snap-20260923
# List snapshots
sudo zfs list -t snapshot
# Roll back a snapshot
sudo zfs rollback data-pool/data@snap-20260923
# Automatic snapshots (requires zfs-auto-snapshot)
sudo zfs set com.sun:auto-snapshot=true data-pool/data
4. Performance Comparison โ How Much Does It Actually Differ
Disk IO Benchmark (fio)
# Install fio
sudo apt install fio # Debian/Ubuntu
sudo dnf install fio # RHEL/Fedora
# Pure write test (4KB random, QD=32)
sudo fio --name=write-test --ioengine=libaio --direct=1 \
--bs=4k --iodepth=32 --rw=randwrite --size=1G \
--filename=/mnt/data/testfile
# Pure read test (4KB random, QD=32)
sudo fio --name=read-test --ioengine=libaio --direct=1 \
--bs=4k --iodepth=32 --rw=randread --size=1G \
--filename=/mnt/data/testfile
# Mixed read/write (70:30 ratio)
sudo fio --name=mixed-test --ioengine=libaio --direct=1 \
--bs=4k --iodepth=32 --rw=randrw --rwmixread=70 --size=1G \
--filename=/mnt/data/testfile
Benchmark Reference Values (typical SSD basis)
| Test | ext4 | XFS | Btrfs (compression OFF) | Btrfs (zstd) |
|---|---|---|---|---|
| 4K random write | 100% | 98-100% | 90-95% | 85-92% |
| 4K random read | 100% | 100% | 98-100% | 95-98% |
| Sequential write | 100% | 100% | 95-100% | 120-150% (compression advantage) |
| Metadata operations | 100% | 95% | 80-90% | 80-90% |
Btrfs's zstd compression can actually be faster than ext4 for sequential writes when the data is compressible (text, logs, and so on). But metadata-heavy work (creating and deleting tens of thousands of files) incurs overhead.
5. Key Filesystem Management Commands
ext4 Management
# Check disk usage
df -hT /mnt/data
# Defragmentation (online)
sudo e4defrag /mnt/data
# Filesystem check (after unmounting)
sudo umount /mnt/data
sudo e2fsck -f /dev/sdb1
# Expand capacity (online)
sudo resize2fs /dev/sdb1
# Shrink capacity (unmount required)
sudo umount /mnt/data
sudo e2fsck -f /dev/sdb1
sudo resize2fs /dev/sdb1 50G # Shrink to 50GB
sudo parted /dev/sdb resizepart 1 50G
XFS Management
# Disk usage
df -hT /mnt/data
# Filesystem check
sudo xfs_repair /dev/sdb1
# Expand capacity (online possible)
sudo xfs_growfs /mnt/data
# Defragmentation
sudo xfs_fsr /mnt/data
# XFS cannot shrink โ you must create a new partition
Btrfs Management
# Filesystem usage (real-time)
sudo btrfs filesystem usage /mnt/data
# List subvolumes
sudo btrfs subvolume list /mnt/data
# Compression statistics
sudo btrfs filesystem defragment -r -czstd /mnt/data
# Clean up the disk
sudo btrfs balance start /mnt/data
# Convert to RAID1 (two disks required)
sudo btrfs balance start -dconvert=raid1 -mconvert=raid1 /mnt/data
ZFS Management
# Check pool status
zpool status data-pool
zpool list
# Filesystem usage
zfs list
# List snapshots
zfs list -t snapshot
# Disk stress test
zpool scrub data-pool
# Add cache (L2ARC)
sudo zpool add data-pool cache /dev/sdc1
# Add log (SLOG)
sudo zpool add data-pool log /dev/sdd1
6. Selection Guide โ Which Filesystem for Which Environment
Case 1: "The default is enough" -> ext4
# The default at Linux install time. No extra configuration needed.
sudo mkfs.ext4 /dev/sda1
General web servers, personal PCs, Docker hosts. Stability is proven, and when something goes wrong, it has the best recovery tooling. If you do not want to leave the default, just use this.
Case 2: "Large databases or media files" -> XFS
# MySQL/PostgreSQL data directory
sudo mkfs.xfs /dev/sdb1
sudo mount /dev/sdb1 /var/lib/mysql
Strong at handling concurrent, large-volume I/O. It is the default in the RHEL/CentOS family. Suitable for log servers, media servers, and large databases.
Case 3: "Snapshots and backup matter" -> Btrfs
# Docker/VM host
sudo mkfs.btrfs /dev/sdb1
sudo mount -o compress=zstd /dev/sdb1 /var/lib/docker
Useful for environments that create and delete VMs often, for ransomware preparedness, and for container hosts. Snapshots are created almost instantly and use almost no space. It is also the default filesystem of Synology NAS.
Case 4: "Data integrity is life" -> ZFS
# NAS/backup server
sudo zpool create -f tank mirror /dev/sdb /dev/sdc
sudo zfs create -o compression=lz4 tank/data
Optimal for building safe storage by bundling multiple disks. It has Self-healing, which detects and recovers data corruption on its own, and RAID-Z protects data even through disk failures. But it uses a lot of RAM and needs a separate install.
7. Summary โ One-Line Conclusion
| Purpose | Recommended filesystem |
|---|---|
| General OS / small server / Docker | ext4 |
| Large DB / logs / media | XFS |
| Backup / NAS / virtualization / containers | Btrfs |
| Enterprise storage / RAID | ZFS |
First grasp your service's data size and I/O pattern, then choose the most suitable filesystem. There is no filesystem that is "always best."
These benchmark results are reference figures measured in a single operator environment, and real performance may vary with hardware and workload.
AI Knowledge Hub
Comments (1)
Review result: the comparison table and selection guide are accurate โ the two Btrfs snapshot procedures carry data-loss risk and must be fixed
To start from the conclusion, the four-major-filesystem comparison table and the per-use recommendations are factually correct and the commands are mostly runnable. However, the example that creates a Btrfs snapshot inside itself, and its recovery procedure, actually destroy the snapshot together with the original, so they are the top-priority fixes.
Suggested corrections (by risk)
/mnt/datawhile putting the destination at/mnt/data/snapshots/. The snapshot nests inside the source subvolume, so deleting the original deletes the snapshot too, and repeated creation produces a structure where snapshots contain snapshots. You should create a dedicated snapshot subvolume (for example,/mnt/snapshots) or take it at the top level withbtrfs subvolume snapshot -r./mnt/datafirst and then take a snapshot again from the snapshot path that was inside it. Combined with problem 1, recovery is actually impossible. The order should be changed to place the snapshot in a separate subvolume, rename the original, and then move the snapshot to the original path.resize2fs /dev/sdb1has no room for the filesystem to grow unless the partition is enlarged first.parted resizepartorgrowpartshould come first. The shrink example (lines 185-188) is correct, shrinking the filesystem first and then the partition./etc/cron.dformat and gets the user field right, but without a trailing newline cron may ignore the last line, andbtrfsmay fail on PATH. Reinforcing absolute paths and the trailing newline is safer.Further recommendations
zfs_arc_max) would complete it.What works