Closed
Description
I tried this code:
// On a CentOS 7 VM, where the current directory is an NFS mount containing a file called "a" with any content
use std::fs;
fn main() {
println!("Hello, world!");
fs::copy("a", "b").unwrap();
}
I expected to see this happen: The file is successfully copied
Instead, this happened:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 95, kind: Other, message: "Operation not Supported" }', src/main.rs:4:4
Meta
rustc --version --verbose
:
Apologies for screenshots, I'm running in a VM I can't easily copy/paste out of.
See also rust-lang/rustup#2452, which has a likely explanation of the cause of this.
Activity
Tavi-Kohn commentedon Aug 11, 2020
This bug doesn't occur every time, because I think
fs::copy
remembers if thecopy_file_range
system call is available. Iffs::copy
is called with two files on the same XFS filesystem, it determines that thecopy_file_range
system call failed. It then sets a flag to always fall back to a more generic copy method, which prevents the bug from occurring for subsequent calls.Code Example
the8472 commentedon Aug 11, 2020
This might be a kernel bug or documentation error because EOPNOTSUPP is not listed in the
copy_file_range
man page as possible error and the kernel even has a warning that this stuff shouldn't happen along with a commit comment that it's the responsibility of the filesystem to perform the fallback.And indeed NFS does have fallback code
So that's probably fixed in a newer kernel version, but who knows with redhat's frankenkernels.
the8472 commentedon Aug 11, 2020
If a kernel update doesn't fix it you could also report this to the distro maintainers too, they might have missed something when backporting patches. I haven't looked at the centos kernel sources though, so that's just a guess.
Mark-Simulacrum commentedon Aug 11, 2020
Cc @cuviper @joshtriplett, though not sure if you are the right people to ask about the possible kernel issue mentioned above.
Regardless we will likely need to handle this ourselves as kernel or distro updates will likely be slow.
the8472 commentedon Aug 11, 2020
Ok, should be easy enough. @rustbot claim
the8472 commentedon Aug 11, 2020
It only remembers that if it encounters specific error codes (
ENOSYS
orEPERM
but notEOPNOTSUPP
). So it should also try copy_file_range on the second attempt and encounter the same error.Could this be related to automounting?
Can you trace the syscalls of your test program via
strace -ff [...]
and post the output?cuviper commentedon Aug 11, 2020
I know that RHEL 7.8 disabled
copy_file_range
-- see the last note in the 7.8 release notes, section 9.4:However, I think an
EOPNOTSUPP
from NFS accidentally leaked through, and will be changed toENOSYS
too:https://bugzilla.redhat.com/show_bug.cgi?id=1783554
the8472 commentedon Aug 11, 2020
Oh that's a mess, so it returns ENOSYS in most cases but in some cases
copy_file_range
would still succeed? The detection logic behaves overly pessimistic then, but I guess that's ok if it was broken in older centos versions.I'll treat EOPNOTSUPP like ENOSYS then.
joshtriplett commentedon Aug 12, 2020
Yes, treating EOPNOTSUPP as ENOSYS here seems like an appropriate workaround for the kernel bug.
Tavi-Kohn commentedon Aug 12, 2020
I've run strace on the test program I wrote earlier.
For two files on an XFS filesystem:
On an NFS filesystem:
8 remaining items