Create FS

mkfs.btrfs --checksum xxhash -O no-holes -R free-space-tree -m dup ${DEVICE}
xxhash requires Linux 5.5.
free-space-tree (AKA space_cache=v2) is default since 5.15.
no_holes is default since 5.15.


no_holes enables better size-optimized representation for sparse files. Can be enabled after creation also:

btrfstune -n ${DEVICE}


Recommended mount options:


Important BTRFS options:


Issue discard/TRIM to inform underlying storage about freed space.



Issue discard immediately when space is freed.


Merge discard requests and submit them asynchronously for better performance.

discard without a value is equal to discard=sync.

discard=async is default as of Linux v6.2.


Never update access time of a file.


Only update access time when modification time is updated too or when access time has not been updated for 24 hours.

Note that CoW operations are issued when updating atime. On files that have snapshots this impacts performance and uses additional space. noatime should usually be preferred.

See also Atime and btrfs: a bad combination?.


Enable space cache v2 improving performance on large drives, in particular. Corresponds to -R free-space-tree option of mkfs.btrfs.


Enable compression on directory:

btrfs property set ${PATH} compression zstd

Newly created files within directory will be compressed (if content is compressible).

Existing files to be force-compressed using defrag:

btrfs filesystem defrag -r -c zstd ${PATH}

See also:

Disable Copy on Write (NOCOW)

Disable CoW:

setfattr +C ${PATH}

This is only applied to newly created files in directory with the NOCOW flag and empty files.


Enabling NOCOW disables checksumming and compression.

This is required to preserve performance for workloads that modify existing files heavily without rewriting the whole file. Databases and VM images are usually used this way.

See also:

Drive Errors

Error statistics:

$ btrfs device stats ${MOUNT_POINT}
[/dev/mapper/luks-bulk-main].write_io_errs    0
[/dev/mapper/luks-bulk-main].read_io_errs     0
[/dev/mapper/luks-bulk-main].flush_io_errs    0
[/dev/mapper/luks-bulk-main].corruption_errs  1
[/dev/mapper/luks-bulk-main].generation_errs  0


Use --check for the command to return with a non-zero code if any of the counters is non-zero.

Check for BTRFS warnings and BTRFS errors:

$ journalctl -k -g '^BTRFS (error|warning)'
Dec 22 13:23:43 mia kernel: BTRFS warning (device dm-15): csum failed root 19830 ino 2360 off 7357997056 csum 0x61debf728dffc131 expected csum 0xe1e94b36ab30f753 mirror 1
Dec 22 13:23:43 mia kernel: BTRFS error (device dm-15): bdev /dev/mapper/luks-bulk-main errs: wr 0, rd 0, flush 0, corrupt 1, gen 0

Convert ext4 to BTRFS

  1. Check FS:

    e2fsck -fy ${DEVICE}
  2. Convert:

    btrfs-convert --csum xxhash -O no-holes ${DEVICE}
  3. Enable space cache v2 and mount:

    mount ${DEVICE} ${MOUNT_POINT} -o space_cache=v2
  4. Remove snapshot of ext4 filesystem:

    btrfs subvolume delete ${MOUNT_POINT}/ext2_saved
  5. Optimize size of metadata:

    btrfs balance start -m ${MOUNT_POINT}
  6. Duplicate metadata for redundancy:

    btrfs balance start -mconvert=dup ${MOUNT_POINT}
  7. Umount:

    umount ${MOUNT_POINT}

See Mount for mount options to use in production.

See Also