#11 posix_fallocate on FreeBSD + ZFS

Closed on October 13, 2024
ryanavella on January 4, 2023

As noted on this fs2 issue, posix_fallocate has some issues on FreeBSD + ZFS.

After a closer look, the implementation of fs2::allocate is not just broken on FreeBSD, it is also buggy on Linux. posix_fallocate either returns 0 or an error code, and it does not set errno. But on non-zero return fs2::allocate attempts to reconstruct the error by calling std::io::Error::last_os_error, which could either be 0 or some unrelated error from a previous libc call.

The following crates have the same problem:

These crates have correct implementations:

  • rustix (unix-like only)
  • fs4 (fork of fs2 that delegates to rustix for unix-like)

I think the quickest fix is to replace the fs2 dependency with fs4. Another option is to introduce a libc dependency and handcode it ourselves. Any and all ideas are appreciated.

ryanavella on January 4, 2023

If we decide to replace fs2 with fs4, I think supporting FreeBSD + ZFS could be as simple as this:

// sanakirja/src/environment/mod.rs
// ...

#[cfg(feature = "mmap")]
use fs4::FileExt;

// ...

#[cfg(feature = "mmap")]
fn fallocate(file: &std::fs::File, length: u64) -> Result<(), Error> {
    let ret = file.allocate(length);

    // Workaround for FreeBSD + ZFS
    #[cfg(target_os = "freebsd")]
    if let Err(ref err) = ret {
        // libc::EINVAL on FreeBSD
        const EINVAL: i32 = 22;

        if err.raw_os_error().unwrap_or(0) == EINVAL {
            // todo: decide if a fallback (e.g. `libc::ftruncate`) makes sense here
            return Ok(());
        }
    }

    Ok(ret?)
}
ryanavella on January 5, 2023

I take back what I said about fs4, it discards the error returned from rustix and then returns errno. This should be fine on Linux because rustix uses fallocate instead of posix_fallocate, but fs4 will still be broken on FreeBSD.

tl;dr: We can switch fs2 to fs4 to fix Linux, but it will still have the same issue on FreeBSD

ryanavella on January 19, 2023

I’ve started writing a crate that allows detecting the filesystem that a particular file resides on. This might help for the edge case of posix_fallocate on FreeBSD+ZFS

ryanavella added a change on February 2, 2023
Support FreeBSD + ZFS where posix_fallocate reliably returns EINVAL by CfKUdBH1SowFB6y7uNUACeEhoxtSXcN8N24RiMMLmSM1,
RUM725HY2MWXXR7M3NHTTXD7M2HM2XCSI77PXODAXAHHLVNX6Z7QC
main
ryanavella on February 2, 2023

Here is a much simpler patch. I submitted a fix to fs4 upstream to return the correct error code for posix_fallocate, and the maintainer bumped the version to 0.6.3.

This has the added benefit that fs4 is actively maintained, while fs2 hasn’t seen activity for more than 5 years despite a number of serious bugs and pull requests.

pmeunier on October 13, 2024

Thanks!

pmeunier closed this discussion on October 13, 2024