-
Notifications
You must be signed in to change notification settings - Fork 305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lib/deploy: Use fallocate
for early prune space check
#2866
Conversation
Classic case of analysis getting confused by variables initialized by a function.
Noticed this diagnostic in my editor with clangd hooked up.
For easier diagnostics.
`size_to_remove` looks cryptic in contrast to `new_new_bootcsum_dirs_total_size`. Rename it in the style of the latter for easier reading.
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.)
/* This is a roundabout but more trustworthy way of doing a space check than | ||
* relying on statvfs's f_bfree when you know the size of the objects. */ | ||
static gboolean | ||
dfd_fallocate_check (int dfd, __off_t len, gboolean *out_passed, GError **error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what would be more efficient and cleaner here is to allocate a temporary fd per file we're going to copy, and then actually use the them to do the writes.
But that's also a lot more code changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. I mentioned passing down the fd in the commit message, but yeah... churn.
Backport to Fedora RPMs: https://src.fedoraproject.org/rpms/ostree/pull-request/33# |
It has a fix for an autopruning corner case. ostreedev/ostree#2866
It has a fix for an autopruning corner case. ostreedev/ostree#2866
It has a fix for an autopruning corner case. ostreedev/ostree#2866
It has a fix for an autopruning corner case. ostreedev/ostree#2866
The
f_bfree
member of thestatvfs
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
andf_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 prunecode 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 guaranteesus 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 checkand 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.)