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:

  1. Subvolumes - Independent filesystem trees (e.g., @root, @home, @snapshots) that share the same storage pool

  2. B-tree Metadata - Manages extent allocation, checksums, and reference counting

  3. Block Devices - Physical storage, optionally aggregated as RAID

Copy-on-Write (CoW)

Traditional filesystems overwrite data in-place. If a crash occurs during write, data is corrupted.

Btrfs CoW writes new data to a new location, then atomically updates the metadata pointer. The old data remains intact until the transaction commits, ensuring crash consistency.

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

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

Device Missing

# Mount with degraded (missing device)
mount -o degraded /dev/sda1 /mnt

# Check which device is missing
btrfs filesystem show /mnt

# Remove missing device
btrfs device delete missing /mnt

# Add replacement
btrfs device add /dev/sdc1 /mnt
btrfs balance start /mnt

Scrub Errors

# Check device stats
btrfs device stats /mnt

# Review scrub results
btrfs scrub status -d /mnt

# Reset error counters
btrfs device stats -z /mnt

# If unrecoverable errors on RAID:
# Replace failed device
btrfs replace start /dev/bad /dev/new /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

HDD Optimization

# fstab for HDD
UUID=xxx /mnt btrfs defaults,noatime,compress=zstd,autodefrag,space_cache=v2 0 0

# Consider autodefrag for random write workloads
mount -o autodefrag /dev/sda1 /mnt

Commit Interval

# Increase commit interval (default 30s)
# Higher = better performance, more data at risk
mount -o commit=60 /dev/sda1 /mnt

# Lower for critical data
mount -o commit=5 /dev/sda1 /mnt

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