Blog/Btrfs defrag with progress output

From Forza's ramblings

Btrfs Filesystem Defrag[edit | edit source]

Space photograph with thousands of galaxies in view
Galaxies, Galaxies, Galaxies, by Hubble Space Telescope. Credit: ESA/Hubble

The Copy-on-Write nature of Btrfs can lead to high amounts of fragmentation in files that are written or update in small bits. This is because for each new write, Btrfs have to write the data to a new location. Especially on spinning HDD's, this can lead to extra seeks and slowness.

btrfs filesystem defragment can be used to defragment files to make the more continuous, thus improving read speeds. Defrag can also be used to apply compression to files, reducing their space usage and increase read/write speeds.

Read more about defragmentation on Btrfs on Btrfs/Defrag

# btrfs filesystem defragment --help
usage: btrfs filesystem defragment [options] <file>|<dir> [<file>|<dir>...]

    Defragment a file or a directory
    -r                        defragment files recursively
    -c[zlib,lzo,zstd]         compress the file while defragmenting, optional parameter (no space in between)
    -f                        flush data to disk immediately after defragmenting
    -s start                  defragment only from byte onward
    -l len                    defragment only up to len bytes
    -t size                   target extent size hint (default: 32M)
    --step SIZE               process the range in given steps, flush after each one
    -v                        deprecated, alias for global -v option
    Global options:
    -v

Defrag in steps, with progress output[edit | edit source]

Btrfs-progs v6.6 came with a new feature, --step, which helps when defragmentig very large files.

Lets consider the following VM image file:

# compsize haikur1beta3-2.img
Processed 1 file, 7905 regular extents (7905 refs), 0 inline.
Type       Perc     Disk Usage   Uncompressed Referenced
TOTAL       98%      3.6G         3.6G         3.6G
none       100%      3.5G         3.5G         3.5G
zstd        40%       25M          63M          63M

Combining -vv (verbose) with --step, we get a nice progress report while defragmenting the file.

The step size can be between 256KiB and 4GiB.

# btrfs -vv fi defrag --step 1G haikur1beta3-2.img
haikur1beta3-2.img
defrag range step: start=0 len=1073741824 step=1073741824
defrag range step: start=1073741824 len=1073741824 step=1073741824
defrag range step: start=2147483648 len=1073741824 step=1073741824
defrag range step: start=3221225472 len=1073741824 step=1073741824

Compsize shows we have reduced the amount of fragmentation quite a bit.

# compsize haikur1beta3-2.img
Processed 1 file, 641 regular extents (641 refs), 0 inline.
Type       Perc     Disk Usage   Uncompressed Referenced
TOTAL       98%      3.6G         3.6G         3.6G
none       100%      3.5G         3.5G         3.5G
zstd        40%       25M          63M          63M