A disk image that grows one write at a time gets fragmented, and fallocate fixes that by reserving space up front without writing a byte. You will also learn to punch holes back out of a file and check exactly what changed on disk. The examples use fallocate from util-linux 2.41.3 installed on this machine; the installed manual page identifies util-linux 2.39.3, so the command's own --help output is the better authority for the newer options.
You need a Linux filesystem that implements the operation you choose, a writable target path, and enough free space for any allocation. Most ordinary files need no elevated privileges. Use sudo only when the target is owned by another account or sits in a protected directory, and check the path carefully before doing so.
Allow about five minutes for the examples. The operations themselves are usually quick, but support and filesystem block alignment can vary. Keep a backup before changing a file that contains data. fallocate has no general undo command.
fallocate --version
fallocate --help
You should see version 2.41.3 here. The normal allocation form needs -l for a length and then a filename. Lengths and offsets are bytes by default. Binary suffixes such as MiB and decimal suffixes such as MB are accepted; K means the same as KiB.
fallocate -l 1MiB /path/to/work/cache.bin
The command creates the file if the default allocation operation can do so, or extends an existing file. It allocates filesystem blocks without first filling the data blocks with a stream of zero bytes, which is normally much faster than using a shell loop or dd for the same reservation.
Check both the apparent length and the allocated blocks:
stat -c 'size=%s bytes, blocks=%b' /path/to/work/cache.bin
du -h /path/to/work/cache.bin
For a one mebibyte file, stat should report size=1048576. The block count depends on the filesystem, so do not treat a particular number as portable. du reports space charged to the file, while stat's size reports its apparent length.
Use --keep-size when you need to allocate beyond the current end of file without making the file appear longer:
fallocate --keep-size --offset 0 --length 1MiB /path/to/work/existing.bin
This can allocate blocks past EOF. The manual page says those blocks can later be removed with truncate. Do not confuse this with writing data: reads beyond EOF still report end of file.
Punching a hole deallocates whole filesystem blocks in a range and makes later reads from that range return zeroes. Partial blocks are zeroed as needed, and the file's apparent length stays the same.
printf 'abcdefghij' > /tmp/fallocate-example.bin
fallocate --punch-hole --offset 2 --length 4 /tmp/fallocate-example.bin
od -An -tx1 -v /tmp/fallocate-example.bin
stat -c 'size=%s bytes, blocks=%b' /tmp/fallocate-example.bin
The bytes shown by od should be 61 62 00 00 00 00 67 68 69 6a. The file remains ten bytes long. On a small file, the filesystem may not reclaim a whole block, so a lower block count is not guaranteed. The operation is still destructive to the original bytes in the selected range. Restore the file from a backup if the range was wrong; there is no inverse fallocate operation that reconstructs the old contents.
The manual lists hole punching support for XFS, ext4, Btrfs, tmpfs and gfs2, with filesystem and kernel version qualifications. Other filesystems can reject it. A failure returns exit status 1; test that status in scripts rather than assuming the request was accepted.
These options change file layout or contents and deserve a backup first:
--zero-range makes a range read as zeroes and ensures it is allocated. Filesystem metadata may represent most of the range as unwritten extents, so it need not physically write every zero.--dig-holes scans for zeroes and replaces suitable ranges with holes. It implies --keep-size and, without an offset and length, analyses the whole file.--collapse-range removes bytes and shifts later data left, making the file shorter. Filesystems commonly require offset and length to match their logical block size.--insert-range inserts a hole and shifts existing data, increasing the file's apparent length. This option is present in the installed 2.41.3 command help even though it is absent from the older local manual page.--collapse-range, --dig-holes, --punch-hole and --zero-range are mutually exclusive. Do not combine them to express a multi-stage plan. Run separate, verified commands and stop after each one if the data matters.
A successful exit status is 0; failure is 1. The most common causes are insufficient free space, a read-only filesystem, a filesystem that does not support the requested operation, invalid ranges, and alignment requirements. Check the target filesystem and free space before changing the command:
df -h /path/to/work/cache.bin
findmnt -T /path/to/work/cache.bin
For a range operation, verify that the offset and length are non-negative, that the range fits the intended file, and that the filesystem's block-size rules are satisfied. --posix uses posix_fallocate(3) instead of the Linux fallocate(2) call. It can take longer, but is useful when the fast filesystem-specific operation is unavailable. It does not make destructive range operations portable.
-l with a deliberately chosen size and target.stat or du.