Btrfs/Checksum Algorithms

From Forza's ramblings
Underside of a CPU with its pins showing.

Btrfs computes checksums for all pieces of data and metadata that is stored on disk. This allows Btrfs to detect any corruptions that may happen. If DUP or RAID profiles are used then Btrfs will automatically repair the error.

The default is crc32c which is very fast. One problem with small checksums (digest size) is that the likelihood of a collision is high. A collision means that the two different sets of data computes to the same checksum. Btrfs offers several more modern checksums that provide stronger protection against collisions or malintent alterations.

Algorithm Digest size Description
CRC32C 32bit fast, weak, default, CPU support, backward compatible
XXHASH (xxhash64) 64bit fast, medium, good on modern CPUs.
SHA256 256bit very slow, strong, fast with CPU support
BLAKE2B 256bit slow, strong, good on 64bit architectures
Only crc32c is supported before Linux kernel 5.5


You have to decide what checksum to use when you create the filesystem.

mkfs.btrfs --csum xxhash

See the mkfs.btrfs man-page for detailed usage.

How to check what csum a filesystem uses

The btrfs inspect-internal tool can be used to check what current checksum algorithm a filesystem is using.

Use the dump-super <device> sub command to display information about the super blocks, which includes the checksum type.

# btrfs inspect-internal dump-super /dev/sde1 | grep csum_type
csum_type               1 (xxhash64)

The full output looks like this.

# btrfs inspect-internal dump-super /dev/sde1
superblock: bytenr=65536, device=/dev/sde1

csum_type 1 (xxhash64) csum_size 8 csum 0x1bf4251883f9ae73 [match] bytenr 65536 flags 0x1 ( WRITTEN ) magic _BHRfS_M [match] fsid df68a30d-d26e-4b9c-9606-a130e66ce63d metadata_uuid df68a30d-d26e-4b9c-9606-a130e66ce63d label usb-backup generation 105315 root 1173875441664 sys_array_size 129 chunk_root_generation 105304 root_level 1 chunk_root 23674880 chunk_root_level 1 log_root 0 log_root_transid 0 log_root_level 0 total_bytes 995908124672 bytes_used 795570204672 sectorsize 4096 nodesize 16384 leafsize (deprecated) 16384 stripesize 4096 root_dir 6 num_devices 1 compat_flags 0x0 compat_ro_flags 0x3 ( FREE_SPACE_TREE | FREE_SPACE_TREE_VALID ) incompat_flags 0x371 ( MIXED_BACKREF | COMPRESS_ZSTD | BIG_METADATA | EXTENDED_IREF | SKINNY_METADATA | NO_HOLES ) cache_generation 0 uuid_tree_generation 105315 block_group_root 0 block_group_root_generation 0 block_group_root_level 0 dev_item.uuid 254fe753-d4d6-4ad1-9cc3-cd9f4c1bfa67 dev_item.fsid df68a30d-d26e-4b9c-9606-a130e66ce63d [match] dev_item.type 0 dev_item.total_bytes 995908124672 dev_item.bytes_used 837535399936 dev_item.io_align 4096 dev_item.io_width 4096 dev_item.sector_size 4096 dev_item.devid 1 dev_item.dev_group 0 dev_item.seek_speed 0 dev_item.bandwidth 0 dev_item.generation 0

SMHasher benchmark

Generally, stronger algorithms are slower than weak ones. You can use SMHasher to benchmark your computer. For example on AMD Ryzens, xxhash64 is often faster than crc32c, even if is a much stronger checksum.

Example on an AMD Athlon 3000G (2 cores, 4 threads, 3GHz)

# ./SMHasher --test=Speed <hash>
crc32_hw:      5695 MiB/sec (crc32c-intel using SSE4.2)
xxhash64:     11397 MiB/sec
blake2b-256:    551 MiB/sec
sha2-256:       210 MiB/sec
sha2ni-256:    1419 MiB/sec (AES-Ni CPU support)

Note that the difference is generally smaller due to how checksums integrates with the filesystem. You should benchmark your specific workload to determine the impact. Some CPUs and systems have hardware acceleration support.