Btrfs
Quick Reference
# Create filesystem
mkfs.btrfs /dev/sda1
mkfs.btrfs -L mylabel -m raid1 -d raid1 /dev/sda1 /dev/sdb1
# Mount with options
mount -o compress=zstd,noatime /dev/sda1 /mnt
# Subvolume operations
btrfs subvolume create /mnt/@home
btrfs subvolume list /mnt
btrfs subvolume delete /mnt/@old
# Snapshot operations
btrfs subvolume snapshot /mnt/@ /mnt/@snapshots/root-$(date +%Y%m%d)
btrfs subvolume snapshot -r /mnt/@ /mnt/@snapshots/root-readonly
# Check filesystem
btrfs filesystem show
btrfs filesystem df /mnt
btrfs filesystem usage /mnt
# Scrub (verify data integrity)
btrfs scrub start /mnt
btrfs scrub status /mnt
Understanding Btrfs
What is Btrfs?
Btrfs (B-tree filesystem) is a modern copy-on-write (CoW) filesystem for Linux that provides:
-
Snapshots - Instant, space-efficient point-in-time copies
-
Subvolumes - Separate filesystem trees within a single filesystem
-
Built-in RAID - Native support for RAID 0, 1, 5, 6, 10
-
Compression - Transparent compression (zstd, lzo, zlib)
-
Checksums - Data integrity verification
-
Online operations - Resize, balance, scrub without unmounting
Btrfs Architecture
Btrfs organizes storage in layers:
-
Subvolumes - Independent filesystem trees (e.g., @root, @home, @snapshots) that share the same storage pool
-
B-tree Metadata - Manages extent allocation, checksums, and reference counting
-
Block Devices - Physical storage, optionally aggregated as RAID
Creating Btrfs Filesystems
Single Device
# Basic creation
mkfs.btrfs /dev/sda1
# With label
mkfs.btrfs -L "DataDrive" /dev/sda1
# Force overwrite existing filesystem
mkfs.btrfs -f /dev/sda1
# Specify metadata profile
mkfs.btrfs -m dup /dev/sda1 # Duplicate metadata (default for single)
mkfs.btrfs -m single /dev/sda1 # Single copy (not recommended)
# With specific features
mkfs.btrfs -O no-holes /dev/sda1 # Space-efficient sparse files
Multi-Device (RAID)
# RAID 1 (mirror) - data and metadata
mkfs.btrfs -m raid1 -d raid1 /dev/sda1 /dev/sdb1
# RAID 0 (stripe) - performance, no redundancy
mkfs.btrfs -m raid1 -d raid0 /dev/sda1 /dev/sdb1
# RAID 10 (stripe of mirrors)
mkfs.btrfs -m raid10 -d raid10 /dev/sd{a,b,c,d}1
# RAID 5/6 (parity) - still experimental
mkfs.btrfs -m raid5 -d raid5 /dev/sda1 /dev/sdb1 /dev/sdc1
mkfs.btrfs -m raid6 -d raid6 /dev/sda1 /dev/sdb1 /dev/sdc1 /dev/sdd1
# Mixed mode (small devices, same blocks for data/metadata)
mkfs.btrfs -M /dev/sda1
RAID Profiles
| Profile | Min Devices | Description | Use Case |
|---|---|---|---|
single |
1 |
No redundancy |
Testing, non-critical data |
dup |
1 |
Duplicate copies on same device |
Default for metadata |
raid0 |
2+ |
Striped, no redundancy |
Performance, scratch space |
raid1 |
2+ |
Mirrored |
Data protection |
raid1c3 |
3+ |
3 copies |
High redundancy |
raid1c4 |
4+ |
4 copies |
Maximum redundancy |
raid10 |
4+ |
Striped mirrors |
Performance + redundancy |
raid5 |
3+ |
Single parity |
Capacity efficiency (experimental) |
raid6 |
4+ |
Double parity |
Higher redundancy (experimental) |
Mount Options
Common Options
# fstab entry with recommended options
UUID=xxx /mnt btrfs defaults,noatime,compress=zstd,space_cache=v2,subvol=@ 0 0
# Mount specific subvolume by name
mount -o subvol=@home /dev/sda1 /home
# Mount specific subvolume by ID
mount -o subvolid=256 /dev/sda1 /mnt
# Compression options
mount -o compress=zstd /dev/sda1 /mnt # zstd default level
mount -o compress=zstd:3 /dev/sda1 /mnt # zstd level 3
mount -o compress=lzo /dev/sda1 /mnt # Fast compression
mount -o compress-force=zstd /dev/sda1 /mnt # Force compression
# Performance options
mount -o noatime /dev/sda1 /mnt # No access time updates
mount -o ssd /dev/sda1 /mnt # SSD optimizations
mount -o nossd /dev/sda1 /mnt # Disable SSD optimizations
mount -o discard=async /dev/sda1 /mnt # Async TRIM
# Consistency options
mount -o autodefrag /dev/sda1 /mnt # Auto defragmentation
mount -o flushoncommit /dev/sda1 /mnt # Flush on transaction
Mount Option Reference
| Option | Description |
|---|---|
compress=alg |
Enable compression (zstd, lzo, zlib, none) |
compress-force=alg |
Force compression even for incompressible data |
noatime |
Don’t update access times (performance) |
nodatacow |
Disable CoW for new files (use with caution) |
space_cache=v2 |
Free space cache (v2 is faster) |
ssd |
Optimize for SSD (auto-detected) |
discard=async |
Enable asynchronous TRIM |
autodefrag |
Auto defragment small random writes |
subvol=name |
Mount specific subvolume by name |
subvolid=id |
Mount specific subvolume by ID |
Subvolume Management
Create Subvolumes
# Mount the top-level (ID 5)
mount /dev/sda1 /mnt
# Create subvolumes
btrfs subvolume create /mnt/@ # Root filesystem
btrfs subvolume create /mnt/@home # Home directories
btrfs subvolume create /mnt/@var # Variable data
btrfs subvolume create /mnt/@snapshots # Snapshot storage
btrfs subvolume create /mnt/@log # Logs (no CoW)
btrfs subvolume create /mnt/@cache # Cache (no CoW)
# Disable CoW for specific subvolumes
chattr +C /mnt/@log
chattr +C /mnt/@cache
# Verify
btrfs subvolume list /mnt
List and Show Subvolumes
# List all subvolumes
btrfs subvolume list /mnt
# List with additional info
btrfs subvolume list -p /mnt # Parent ID
btrfs subvolume list -u /mnt # UUID
btrfs subvolume list -t /mnt # Table format
btrfs subvolume list -a /mnt # All (including snapshots)
# Show specific subvolume info
btrfs subvolume show /mnt/@home
# Get default subvolume
btrfs subvolume get-default /mnt
# Set default subvolume (boot without subvol= option)
btrfs subvolume set-default 256 /mnt
Delete Subvolumes
# Delete subvolume
btrfs subvolume delete /mnt/@old
# Delete with subvolume ID
btrfs subvolume delete -i 258 /mnt
# Force delete (even if not empty)
btrfs subvolume delete --commit-each /mnt/@old
# Delete snapshot
btrfs subvolume delete /mnt/@snapshots/root-20240101
Recommended Layout for System
A typical production layout uses separate subvolumes for different purposes:
-
@ - Root filesystem (/)
-
@home - User home directories (/home)
-
@var - Variable data (/var) - optional
-
@log - Logs (/var/log) - with nodatacow for database-like writes
-
@cache - Cache (/var/cache) - with nodatacow
-
@tmp - Temporary files (/tmp) - with nodatacow
-
@snapshots - Snapshot storage (/.snapshots)
-
@swap - Swapfile location (/swap) - if using swapfile
fstab Configuration
# /etc/fstab for subvolume layout
UUID=xxx / btrfs defaults,noatime,compress=zstd,subvol=@ 0 0
UUID=xxx /home btrfs defaults,noatime,compress=zstd,subvol=@home 0 0
UUID=xxx /var/log btrfs defaults,noatime,nodatacow,subvol=@log 0 0
UUID=xxx /var/cache btrfs defaults,noatime,nodatacow,subvol=@cache 0 0
UUID=xxx /.snapshots btrfs defaults,noatime,compress=zstd,subvol=@snapshots 0 0
Snapshots
Create Snapshots
# Writable snapshot
btrfs subvolume snapshot /mnt/@ /mnt/@snapshots/root-$(date +%Y%m%d-%H%M%S)
# Read-only snapshot (recommended for backups)
btrfs subvolume snapshot -r /mnt/@ /mnt/@snapshots/root-$(date +%Y%m%d-%H%M%S)
# Snapshot with specific name
btrfs subvolume snapshot -r /mnt/@home /mnt/@snapshots/home-pre-upgrade
# Verify snapshot
btrfs subvolume show /mnt/@snapshots/root-20240101-120000
Restore from Snapshot
# Method 1: Replace subvolume with snapshot
# Boot from live USB or recovery
mount /dev/sda1 /mnt
# Delete current root
btrfs subvolume delete /mnt/@
# Restore from snapshot (create writable copy)
btrfs subvolume snapshot /mnt/@snapshots/root-20240101 /mnt/@
# Method 2: Move/rename subvolumes
# Rename current (keep as backup)
mv /mnt/@ /mnt/@.broken
# Restore snapshot
btrfs subvolume snapshot /mnt/@snapshots/root-20240101 /mnt/@
# After verifying, delete broken
btrfs subvolume delete /mnt/@.broken
Send/Receive (Backup)
# Create read-only snapshot first
btrfs subvolume snapshot -r /data /snapshots/data-latest
# Send to file
btrfs send /snapshots/data-latest > /backup/data-latest.btrfs
# Send to another Btrfs filesystem
btrfs send /snapshots/data-latest | btrfs receive /backup/
# Incremental send (requires parent snapshot)
btrfs subvolume snapshot -r /data /snapshots/data-new
btrfs send -p /snapshots/data-latest /snapshots/data-new | btrfs receive /backup/
# Send over SSH
btrfs send /snapshots/data-latest | ssh user@remote btrfs receive /backup/
# Compressed transfer
btrfs send /snapshots/data-latest | zstd | ssh user@remote 'zstd -d | btrfs receive /backup/'
Automated Snapshots with Snapper
# Install snapper
# Arch
sudo pacman -S snapper
# Debian/Ubuntu
sudo apt install snapper
# Create configuration for root
sudo snapper -c root create-config /
# List configurations
snapper list-configs
# Create manual snapshot
snapper -c root create --description "Pre-upgrade"
# List snapshots
snapper -c root list
# Compare snapshots
snapper -c root diff 1..2
# Rollback (show what would change)
snapper -c root undochange 1..0
# Configure automatic snapshots
# /etc/snapper/configs/root
TIMELINE_CREATE="yes"
TIMELINE_CLEANUP="yes"
TIMELINE_MIN_AGE="1800"
TIMELINE_LIMIT_HOURLY="10"
TIMELINE_LIMIT_DAILY="10"
TIMELINE_LIMIT_WEEKLY="0"
TIMELINE_LIMIT_MONTHLY="10"
TIMELINE_LIMIT_YEARLY="10"
Filesystem Operations
Show Filesystem Information
# Show all Btrfs filesystems
btrfs filesystem show
# Show specific filesystem
btrfs filesystem show /dev/sda1
btrfs filesystem show /mnt
# Disk usage summary
btrfs filesystem df /mnt
# Detailed usage
btrfs filesystem usage /mnt
# Device statistics
btrfs device stats /mnt
# Filesystem label
btrfs filesystem label /mnt
btrfs filesystem label /mnt "NewLabel"
Resize Filesystem
# Grow to fill device
btrfs filesystem resize max /mnt
# Grow by specific amount
btrfs filesystem resize +10G /mnt
# Shrink by specific amount
btrfs filesystem resize -10G /mnt
# Resize to specific size
btrfs filesystem resize 50G /mnt
# Resize specific device in multi-device
btrfs filesystem resize 1:max /mnt
btrfs filesystem resize 2:+10G /mnt
Add/Remove Devices
# Add device to filesystem
btrfs device add /dev/sdc1 /mnt
# Add and rebalance
btrfs device add /dev/sdc1 /mnt
btrfs balance start /mnt
# Remove device
btrfs device remove /dev/sdb1 /mnt
# Replace failed device
btrfs device delete missing /mnt
btrfs device add /dev/sdd1 /mnt
# Replace (online, keeps data)
btrfs replace start /dev/sdb1 /dev/sdd1 /mnt
btrfs replace status /mnt
Balance Operations
# Full balance (redistribute data/metadata)
btrfs balance start /mnt
# Balance in background
btrfs balance start --background /mnt
# Balance with filters
btrfs balance start -dusage=50 /mnt # Data chunks < 50% used
btrfs balance start -musage=50 /mnt # Metadata chunks < 50% used
btrfs balance start -susage=50 /mnt # System chunks < 50% used
# Convert RAID profile
btrfs balance start -dconvert=raid1 -mconvert=raid1 /mnt
# Limit balance operations
btrfs balance start -dlimit=10 /mnt # Process 10 chunks
# Check balance status
btrfs balance status /mnt
# Pause/resume/cancel
btrfs balance pause /mnt
btrfs balance resume /mnt
btrfs balance cancel /mnt
Scrub (Data Integrity Check)
# Start scrub
btrfs scrub start /mnt
# Start in background (default)
btrfs scrub start -B /mnt # Foreground
btrfs scrub start -d /mnt # Background daemon
# Check status
btrfs scrub status /mnt
# Detailed status
btrfs scrub status -d /mnt
# Cancel scrub
btrfs scrub cancel /mnt
# Resume interrupted scrub
btrfs scrub resume /mnt
# Scrub specific device
btrfs scrub start /dev/sda1
# Read-only scrub (verify only, don't repair)
btrfs scrub start -r /mnt
Defragmentation
# Defragment file
btrfs filesystem defragment /path/to/file
# Defragment directory (recursive)
btrfs filesystem defragment -r /path/to/dir
# Defragment with compression
btrfs filesystem defragment -r -czstd /mnt
# Defragment with flush
btrfs filesystem defragment -f /path/to/file
# Note: Defrag breaks reflinks (snapshots use more space)
# Use with caution on snapshotted data
Compression
Enable Compression
# Mount with compression
mount -o compress=zstd /dev/sda1 /mnt
# Set compression on directory (new files)
btrfs property set /mnt/data compression zstd
# Check compression property
btrfs property get /mnt/data
# Compress existing files
btrfs filesystem defragment -r -czstd /mnt/data
# Force compression (even incompressible data)
mount -o compress-force=zstd /dev/sda1 /mnt
Compression Algorithms
| Algorithm | Speed | Ratio | Use Case |
|---|---|---|---|
zstd |
Fast |
Good |
Default, general purpose |
zstd:N (1-15) |
Configurable |
N-dependent |
Tune speed/ratio |
lzo |
Very fast |
Lower |
CPU-constrained systems |
zlib |
Slow |
High |
Maximum compression |
zlib:N (1-9) |
Configurable |
N-dependent |
Tune speed/ratio |
Check Compression
# Check compression ratio with compsize
compsize /mnt/data
# Output example:
# Processed 1234 files, 456 regular extents (789 refs)
# Type Perc Disk Usage Uncompressed
# TOTAL 45% 4.5G 10.0G
# none 100% 2.0G 2.0G
# zstd 25% 2.5G 8.0G
# Install compsize
# Arch
sudo pacman -S compsize
# Debian/Ubuntu
sudo apt install btrfs-compsize
Quota and Space Management
Enable Quotas
# Enable quota tracking
btrfs quota enable /mnt
# Check quota status
btrfs qgroup show /mnt
# Show with sizes
btrfs qgroup show -reF /mnt
# Detailed view
btrfs qgroup show --raw /mnt
Set Limits
# Create quota group for subvolume
# Subvolumes automatically get qgroup 0/subvolid
btrfs qgroup show /mnt
# Set limit on subvolume (qgroup 0/256)
btrfs qgroup limit 10G 0/256 /mnt
# Set limit with no limit (unlimited)
btrfs qgroup limit none 0/256 /mnt
# Set exclusive limit (shared data doesn't count)
btrfs qgroup limit -e 5G 0/256 /mnt
# Clear limit
btrfs qgroup limit none 0/256 /mnt
# Disable quotas
btrfs quota disable /mnt
Reclaim Space
# Trim (SSD)
fstrim /mnt
fstrim -v /mnt
# Or mount with discard
mount -o discard=async /dev/sda1 /mnt
# Force space reclamation after deletes
btrfs filesystem sync /mnt
# Check for balance opportunities
btrfs filesystem usage /mnt
# Reclaim space from deleted subvolumes
btrfs subvolume sync /mnt
Troubleshooting
Check Filesystem
# Check unmounted filesystem
btrfs check /dev/sda1
# Check mounted (read-only mode)
btrfs check --readonly /dev/sda1
# Repair (DANGEROUS - backup first)
btrfs check --repair /dev/sda1
# Clear space cache (fixes some issues)
btrfs check --clear-space-cache v2 /dev/sda1
# Initialize extent tree (extreme recovery)
btrfs check --init-extent-tree /dev/sda1
Recovery Options
# Mount with recovery options
mount -o recovery /dev/sda1 /mnt
mount -o ro,recovery /dev/sda1 /mnt
# Skip balance resume
mount -o skip_balance /dev/sda1 /mnt
# Use backup superblock
mount -o usebackuproot /dev/sda1 /mnt
# Rescue mode options
btrfs rescue super-recover /dev/sda1 # Recover superblock
btrfs rescue chunk-recover /dev/sda1 # Recover chunk tree
btrfs rescue zero-log /dev/sda1 # Clear log tree
btrfs rescue fix-device-size /dev/sda1 # Fix device size
# Restore files from broken filesystem
btrfs restore /dev/sda1 /recovery/
btrfs restore -l /dev/sda1 # List roots
btrfs restore -t 278 /dev/sda1 /recovery/ # Restore specific root
Common Issues
"No space left" with Free Space
# Check metadata space
btrfs filesystem df /mnt
# If metadata is full but data isn't:
# Add temporary device
btrfs device add /dev/sdc1 /mnt
btrfs balance start -m /mnt
btrfs device remove /dev/sdc1 /mnt
# Or balance metadata chunks
btrfs balance start -musage=0 /mnt
btrfs balance start -musage=50 /mnt
# Enable space_cache=v2 (better allocator)
mount -o remount,space_cache=v2 /mnt
Debug Information
# Kernel messages
dmesg | grep -i btrfs
# Filesystem generation
btrfs inspect-internal dump-super /dev/sda1 | grep generation
# Tree dump (advanced)
btrfs inspect-internal dump-tree /dev/sda1
# Root tree
btrfs inspect-internal dump-tree -t root /dev/sda1
# Inode resolution
btrfs inspect-internal inode-resolve 256 /mnt
# Logical address resolution
btrfs inspect-internal logical-resolve -P 12345678 /mnt
Performance Tuning
SSD Optimization
# fstab for SSD
UUID=xxx /mnt btrfs defaults,noatime,compress=zstd,ssd,discard=async,space_cache=v2 0 0
# Check if SSD detected
cat /sys/block/sda/queue/rotational # 0 = SSD
# Manual TRIM schedule
systemctl enable fstrim.timer
Quick Command Reference
# Creation
mkfs.btrfs /dev/sda1 # Single device
mkfs.btrfs -L label -m raid1 -d raid1 /dev/sd{a,b}1 # RAID1
# Mounting
mount -o subvol=@,compress=zstd,noatime /dev/sda1 /mnt
# Subvolumes
btrfs subvolume create /mnt/@name # Create
btrfs subvolume list /mnt # List
btrfs subvolume delete /mnt/@name # Delete
btrfs subvolume snapshot /mnt/@ /mnt/@snap # Writable snap
btrfs subvolume snapshot -r /mnt/@ /mnt/@snap # Read-only snap
# Filesystem
btrfs filesystem show # Show all
btrfs filesystem df /mnt # Space usage
btrfs filesystem usage /mnt # Detailed usage
btrfs filesystem resize max /mnt # Grow
# Devices
btrfs device add /dev/sdc1 /mnt # Add device
btrfs device remove /dev/sdb1 /mnt # Remove device
btrfs device stats /mnt # Error stats
# Maintenance
btrfs balance start /mnt # Rebalance
btrfs scrub start /mnt # Verify data
btrfs check /dev/sda1 # Check (unmounted)
# Send/Receive
btrfs send /snap | btrfs receive /backup/ # Backup
btrfs send -p /old /new | btrfs receive /backup/ # Incremental