lib/deploy: Use `fallocate` for early prune space check
authorJonathan Lebon <jonathan@jlebon.com>
Sat, 27 May 2023 14:37:30 +0000 (10:37 -0400)
committerJonathan Lebon <jonathan@jlebon.com>
Mon, 29 May 2023 16:17:05 +0000 (12:17 -0400)
commit193ef29f3f0886e3d59e6580e394f8817f2f123e
treee6c2cabd569c37883b3534b1e55fecabb2d2a388
parent76649127d1f415abdfd2e8de62ce8a2beef5f412
lib/deploy: Use `fallocate` for early prune space check

The `f_bfree` member of the `statvfs` struct is documented as the
"number of free blocks". However, different filesystems have different
interpretations of this. E.g. on XFS, this is truly the number of blocks
free for allocating data. On ext4 however, it includes blocks that
are actually reserved by the filesystem and cannot be used for file
data. (Note this is separate from the distinction between `f_bfree` and
`f_bavail` which isn't relevant to us here since we're privileged.)

If a kernel and initrd is sized just right so that it's still within the
`f_bfree` limit but above what we can actually allocate, the early prune
code won't kick in since it'll think that there is enough space. So we
end up hitting `ENOSPC` when we actually copy the files in.

Rework the early prune code to instead use `fallocate` which guarantees
us that a file of a certain size can fit on the filesystem. `fallocate`
requires filesystem support, but all the filesystems we care about for
the bootfs support it (including even FAT).

(There's technically a TOCTOU race here that existed also with the
`statvfs` code where free space could change between when we check
and when we copy. Ideally we'd be able to pass down that fd to the
copying bits, but anyway in practice the bootfs is pretty much owned by
libostree and one doesn't expect concurrent writes during a finalization
operation.)
src/libostree/ostree-sysroot-deploy.c
tests/kolainst/destructive/auto-prune.sh