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 support #1105

Merged
merged 5 commits into from Sep 28, 2019
Merged

Conversation

dingxiangfei2009
Copy link
Contributor

This PR add posix_fallocate, which is available on

  • Linux
  • FreeBSD
  • Android
  • Emscripten
  • Fuchsia
  • WASI

Here is a question: for some reason, posix_fallocate returns EBADF instead of EPIPE if a FIFO file descriptor is passed in on Linux 4.19.64. In the test EBADF is used for now, but I would like to know if such behaviour is expected.

@asomers
Copy link
Member

asomers commented Aug 11, 2019

It's not nix's job to fix kernel bugs; we have to live with them. You should adjust the test so that it accepts all error codes that the kernel might return in that situation.

@dingxiangfei2009 dingxiangfei2009 force-pushed the posix_fallocate branch 2 times, most recently from 50417ff to 0617c24 Compare August 12, 2019 16:39
@dingxiangfei2009
Copy link
Contributor Author

Sorry, forgot to cross reference here: CraneStation/wasi-common#16

Copy link
Member

@asomers asomers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to add a CHANGELOG entry, too.

const LEN: usize = 100;
let mut tmp = NamedTempFile::new().unwrap();
let fd = tmp.as_raw_fd();
let res = posix_fallocate(fd, 0, LEN as libc::off_t).unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test will fail if /tmp resides on a file system that doesn't support posix_fallocate, like ZFS. The test must be adjusted to handle that error. Unfortunately, POSIX stipulates that the errno in that case shall be EINVAL, which can also indicate several other problems.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I wasn't aware of this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added in some explanation in the test, in case the test fails possibly due to filesystem not supporting this operation.

let (rd, _wr) = pipe().unwrap();
let errno = posix_fallocate(rd as RawFd, 0, 100).unwrap();
match Errno::from_i32(errno) {
Errno::EBADF
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't you narrow this list down? I don't think there are very many different error codes that could be returned in this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure!

Copy link
Member

@asomers asomers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to add a CHANGELOG entry. And please don't squash until the end; it makes incremental review more difficult.

@@ -504,3 +504,16 @@ mod posix_fadvise {
Errno::result(res)
}
}

#[cfg(any(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add dragonfly, too. You can also add NetBSD, if you make a PR to libc first.

match Errno::from_i32(res) {
Errno::EINVAL => {
eprintln!(r#"
`posix_fallocate` returned EINVAL.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to print this info out; a comment is sufficient. And please keep it to 80 characters.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. It is in comment now.

use nix::unistd::pipe;

#[test]
fn test_success() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Putting "test" in the function name is redundant with the "test" in the module name. You can shorten it to "success".

src/fcntl.rs Outdated
any(target_os = "wasi", target_env = "wasi"),
target_env = "freebsd"
))]
pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<libc::c_int> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A better return type would be Result<()>, because the only non-error value ever returned is 0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spec says that posix_fallocate returns the error number and it does not set errno.
fallocate returns -1 on error and set errno. The two functions are behaving quite differently regarding to the returned value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have converted to return type to Result<()>. However, I have concerns on whether we should follow POSIX and return Errno directly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

posix_fallocate does what? That's bonkers. But sure enough; you're correct. However, we shouldn't expose that inconsistency to userspace. Better for Nix's posix_fallocate to have the same interface as other Nix functions. We should turn its return value into a Result<()>.

#[test]
fn test_errno() {
let (rd, _wr) = pipe().unwrap();
let errno = posix_fallocate(rd as RawFd, 0, 100).unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be unwrap_err?

target_os = "emscripten",
target_os = "fuchsia",
any(target_os = "wasi", target_env = "wasi"),
target_env = "freebsd"))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/target_env/target_os/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

src/fcntl.rs Outdated
target_os = "emscripten",
target_os = "fuchsia",
any(target_os = "wasi", target_env = "wasi"),
target_env = "freebsd"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/target_env/target_os/

@dingxiangfei2009 dingxiangfei2009 force-pushed the posix_fallocate branch 4 times, most recently from 39818d2 to cf1f4ae Compare August 25, 2019 05:36
@dingxiangfei2009
Copy link
Contributor Author

dingxiangfei2009 commented Aug 25, 2019

@asomers Sorry for squashing again!

I will not do this for later commits.

Also, I am going to add an entry to the CHANGELOG, once my question about the function signature of posix_fallocate is resolved.

// According to POSIX.1-2008, its implementation shall
// return `EINVAL` if `len` is 0, `offset` is negative or
// the filesystem does not support this operation.
// According to POSIX.1-2001, its implementation shall
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is duped.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✂️ ed

| Sys(Errno::EBADF) => (),
errno =>
panic!(
"errno does not match posix_fallocate spec, errno={}",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would simply say "unexpected errno, {}, errno

assert_eq!(&data as &[u8], &[0u8; LEN] as &[u8]);
}
Err(nix::Error::Sys(Errno::EINVAL)) => {
// `posix_fallocate` returned EINVAL.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me suggest some wording that would sound more natural to a native english speaker:

POSIX requires posix_fallocate to return EINVAL both for invalid arguments (i.e. len < 0) and if the operation is not supported by the file system. There's no way to tell for sure whether the file system supports posix_fallocate, so we must pass the test if it returns EINVAL.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your suggestion! 😄

Ok(_) => {
let mut data = [1u8; LEN];
assert_eq!(tmp.read(&mut data).expect("read failure"), LEN);
assert_eq!(&data as &[u8], &[0u8; LEN] as &[u8]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of casting, you should be able to do &data[..], &[0u8; LEN][..]

CHANGELOG.md Outdated
@@ -773,3 +773,5 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#335](https://github.com/nix-rust/nix/pull/335))

## [0.5.0] 2016-03-01
- Added `posix_fallocate`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This CHANGELOG entry is seriously dislocated. It should be up in the "Unreleased" section.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sorry

@dingxiangfei2009
Copy link
Contributor Author

It is surprising to see tests failing under x86_64-unknown-linux-gnu.

Copy link
Member

@asomers asomers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rebase the PR onto master. Never merge master into PRs. As for the test failures, it looks like something on Travis's side changed.

Copy link
Member

@asomers asomers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bors r+

bors bot added a commit that referenced this pull request Sep 28, 2019
1105: posix_fallocate support r=asomers a=dingxiangfei2009

This PR add [`posix_fallocate`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fallocate.html), which is available on
- Linux
- FreeBSD
- Android
- Emscripten
- Fuchsia
- WASI

Here is a question: for some reason, `posix_fallocate` returns `EBADF` instead of `EPIPE` if a FIFO file descriptor is passed in on Linux 4.19.64. In the test `EBADF` is used for now, but I would like to know if such behaviour is expected.

Co-authored-by: Ding Xiang Fei <dingxiangfei2009@gmail.com>
@asomers
Copy link
Member

asomers commented Sep 28, 2019

Sorry, but you need to rebase again to fix the test failures.

@bors
Copy link
Contributor

bors bot commented Sep 28, 2019

Build succeeded

@bors bors bot merged commit 877afa1 into nix-rust:master Sep 28, 2019
@dingxiangfei2009 dingxiangfei2009 deleted the posix_fallocate branch September 30, 2019 12:14
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

Successfully merging this pull request may close these issues.

None yet

2 participants