Skip to content
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

posix_fallocate fails on ZFS+FreeBSD #25

Open
P-E-Meunier opened this issue Jun 3, 2018 · 6 comments
Open

posix_fallocate fails on ZFS+FreeBSD #25

P-E-Meunier opened this issue Jun 3, 2018 · 6 comments

Comments

@P-E-Meunier
Copy link

This error never shows up on Linux because glibc tries to emulate fallocate. However, it seems this call could be emulated with truncate on FreeBSD.

@ryanavella
Copy link

@P-E-Meunier by "emulate," do you mean a call that avoids unnecessary truncating? i.e. something like this?

#[cfg(target_os = "freebsd")]
pub fn allocate(file: &File, len: u64) -> Result<()> {
    let fd = file.as_raw_fd();
    let len = len.try_into().unwrap();

    let ret = unsafe {
        let mut stat: libc::stat = mem::zeroed();
        let len_new = if libc::fstat(fd, std::ptr::addr_of_mut!(stat)) == 0 {
            stat.st_size.max(len)
        } else {
            len
        };
        libc::ftruncate(file.as_raw_fd(), len_new)
    };

    if ret == 0 { Ok(()) } else { Err(Error::last_os_error()) }
}

@P-E-Meunier
Copy link
Author

I believe so, but it was quite some time ago, I don't remember exactly what the issue was. It was also reported to me indirectly.
My use of fs2 , when running on ZFS, is also hard to understand, since I'm doing copy-on-write (in the sanakirja crate) on top of a copy-on-write filesystem.

@rtyler
Copy link

rtyler commented Mar 16, 2023

I have a current version of FreeBSD and ZFS running with this crate. posix_fallocate will fail with EINVAL.

diff --git a/src/unix.rs b/src/unix.rs
index 5c2f4f2..79f7595 100644
--- a/src/unix.rs
+++ b/src/unix.rs
@@ -96,7 +96,6 @@ pub fn allocated_size(file: &File) -> Result<u64> {
 }

 #[cfg(any(target_os = "linux",
-          target_os = "freebsd",
           target_os = "android",
           target_os = "emscripten",
           target_os = "nacl"))]
@@ -138,6 +137,7 @@ pub fn allocate(file: &File, len: u64) -> Result<()> {

 #[cfg(any(target_os = "openbsd",
           target_os = "netbsd",
+          target_os = "freebsd",
           target_os = "dragonfly",
           target_os = "solaris",
           target_os = "haiku"))]

A suitable workaround seems to be to make FreeBSD use the same allocate implementation as the other BSDs, but I'm not yet sure if this is a Good Idea ™️

I tested another approach which would use ftruncate(2) on FreeBSD. Either really works for the higher level application I am using here which relies on this functionality.

I am not sure whether @danburkert has any preference to the approach taken here.

@ryanavella
Copy link

@rtyler I'm not sure if fs2 is maintained any more, the last commit was >5 years ago and several important PR's have been left open for nearly as long.

You may consider fs4 as an alternative. It is a fork of fs2 that is now actively maintained, and they accepted my PR to fix the FreeBSD+ZFS issue you are describing.

@rtyler
Copy link

rtyler commented Mar 17, 2023

@ryanavella fs4 does bubble up the EINVAL but still does not provider a suitable allocate implementaiton, but I will take that up with that maintainer instead 😄

@ryanavella
Copy link

I think the reason FreeBSD returns EINVAL with posix_fallocate is that fallocate doesn't really make much sense on a copy-on-write filesystem.

My workaround is to match on fs4::allocate and ignore the returned error if it is EINVAL, instead of blindly bubbling it up with the ? operator. In a lot of cases fs4::allocate will be paired with a ftruncate anyways, so there isn't much to do if EINVAL is returned other than continue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants