Measure File Fragmentation with filefrag

Your database feels slow and someone mutters "fragmentation", so filefrag shows you where the file actually sits on disk. You will inspect a file's layout, read its extent count without mistaking sparse holes for fragmentation, and spot the cases that need extra privileges or a different option.

Allow about ten minutes for a single file, plus time to interpret the filesystem-specific result. The examples use the installed e2fsprogs 1.47.0 command.

Safety boundary: this is an inspection guide. filefrag does not defragment a file, move data or repair a filesystem, so do not delete, rewrite or compact a file just because its report shows more than one extent.

1. Confirm the installed command

Check the binary and version first. This is an ordinary, unprivileged check:

$ command -v filefrag
/usr/sbin/filefrag
$ filefrag -V
filefrag 1.47.0 (5-Feb-2023)
$ dpkg-query -W -f='${Package} ${Version}\n' e2fsprogs
e2fsprogs 1.47.0-2.4~exp1ubuntu4.1

Your package revision may differ even when the upstream utility reports the same version. The installed manual says filefrag first asks the filesystem for FIEMAP information, then falls back to the older FIBMAP interface if FIEMAP is unavailable. That one detail explains many permission and output differences.

Checkpoint: record the command version before comparing reports from different hosts.

2. Request a compact extent count

Give the file name as the final argument. Use a path you can read, and quote it if it contains spaces:

$ filefrag -- /path/to/report.db
/path/to/report.db: 3 extents found

The exact count and wording belong to your file. One extent means one reported contiguous mapping. Several extents mean the mapping is split, but that is only a layout observation. Files pick up extra extents as they grow, and a small file may have an extent that is perfectly adequate for its workload.

A missing file, unreadable parent directory or inaccessible target produces an error instead of a report. Check the path without changing anything:

$ ls -l -- /path/to/report.db
$ test -r /path/to/report.db && echo readable
readable

3. Read the extent table with verbose output

Use -v when you want the mapping, not just the count:

$ filefrag -v -- /path/to/report.db
Filesystem type is: ef53
File size of /path/to/report.db is 123456 (31 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..      30:          12345..     12375:     31:             last,eof
/path/to/report.db: 1 extent found

Values vary with the filesystem and file. Here is how to read the columns:

Tip: physical block numbers expose storage layout, so treat them as operational data. Do not publish them casually, and do not infer a disk's full layout from one file. If a script only needs a count, omit -v.

Checkpoint: compare the extent count with the verbose table. The final line should agree with the number of mapping rows, allowing for filesystem-specific reporting.

4. Separate fragmentation from sparse holes

A sparse file can have large logical ranges with no physical blocks allocated. That is not the same as allocated data split into many physical extents. Check apparent size and allocated blocks alongside filefrag:

$ stat --format='size=%s bytes, blocks=%b, block_size=%B' -- /path/to/image.raw
size=1073741824 bytes, blocks=8192, block_size=512
$ filefrag -v -- /path/to/image.raw

Warning: do not use the apparent size as a storage-cost estimate for sparse files. Equally, do not treat a low extent count as proof that an application will be fast. Read and write patterns, caching, queueing, device latency and filesystem behaviour all matter.

5. Make block-size comparisons explicit

Normal output uses the filesystem block size. For compatibility with older filefrag versions, an unspecified argument to -b defaults to 1024 bytes, and the optional value must be attached to the option. The modern, clearer forms are:

$ filefrag -b4096 -- /path/to/report.db
$ filefrag -b1M -- /path/to/report.db
$ filefrag -k -- /path/to/report.db

-k is equivalent to -b1024. The suffixes K, M and G are accepted up to 1 GB for output. These options change how the mapping is presented, not the file's allocation or the filesystem's block size. Keep the same option when comparing reports from different runs.

Warning: writing -b 4096 and assuming the next token is its value is the classic trap. The installed manual documents the no-space form precisely because the argument is optional. If a script needs a particular unit, use -b4096 or -b1M and check the output before relying on parsed columns.

6. Sync before measuring when recent writes matter

Use -s when the file has just been written and you want it synced before its mapping is requested:

$ filefrag -s -v -- /path/to/recent-output.bin

This can create extra I/O and is unnecessary for a stable, already closed file. It does not reorganise or defragment the file. If an application still has the file open, the report remains a snapshot rather than a final view of future allocation.

Warning: do not add -s blindly to a loop over large active files. It can turn a quick inspection into sustained storage activity. Measure a representative sample first, and schedule heavier checks away from latency-sensitive work.

7. Handle FIEMAP and FIBMAP privilege failures

For testing, -B forces the older FIBMAP interface instead of FIEMAP:

$ filefrag -B -- /path/to/report.db
/path/to/report.db: FIBMAP requires root privileges

That failure is expected on an unprivileged invocation on this machine. FIBMAP may need elevated privileges because it exposes physical block mappings.

Recovery: do not run it with sudo just to make an ordinary FIEMAP report work. Remove -B and use the default path first:

$ filefrag -v -- /path/to/report.db

If the default command reports that FIEMAP is unsupported, check filesystem and kernel support before escalating. A root invocation changes the authority the inspection runs under, but it cannot add FIEMAP support to a filesystem. The exact error may also reflect a filesystem, container or security-policy boundary.

Warning: -E and -P are ext4-specific cache operations, and the manual warns that kernel support is not universal. Use them only when diagnosing an ext4 extent-status-cache issue. They are not general-purpose fragmentation switches.

8. Inspect specialised mappings only when needed

$ filefrag -e -v -- /path/to/report.db
$ filefrag -X -v -- /path/to/report.db
$ filefrag -x -- /path/to/report.db

These views answer different questions. Do not treat an extended-attribute mapping as the data-file mapping, and do not parse verbose columns without accounting for the selected unit and format.

Tip: for a repeatable report, save the command line, package version, filesystem type and timestamp with the output.

Done means