Feature #16965
closedio.c: Unsupported copy_file_range() not detected properly on certain kernels
Description
In recent RedHat kernels (for example: RHEL 7.8 using kernel 3.10.0-1127.8.2.el7.x86_64), copy_file_range()
may return EOPNOTSUP
when Ruby attempts to call this in IO.copy_stream
on an NFS mount. A simple FileUtils.copy_file
will fail with Operation not supported - copy_file_range
on these kernels.
This was possibly changed during a recent security release: https://access.redhat.com/errata/RHSA-2020:1465
Ruby's io.c detects whether copy_file_range()
is defined, not whether it is actually supported. The following test program illustrates the hole in the detection mechanism:
#include <syscall.h>
#include <stdio.h>
#if defined __linux__ && defined __NR_copy_file_range
# define USE_COPY_FILE_RANGE 1
#else
# define USE_COPY_FILE_RANGE 0
#endif
int main()
{
printf("copy_file_range? %d\n", USE_COPY_FILE_RANGE);
}
USE_COPY_FILE_RANGE
gets set to 1 even in when the system call doesn't succeed.
I suggest a few improvements:
- Use a compile-time test to verify that
copy_file_range()
can actually be executed. - Make it possible to disable
USE_COPY_FILE_RANGE
via a build option. Since the test in 1 could still pass if it is run on a Docker host that supportscopy_file_range()
, it would be helpful for us to manually disable it.
Reported by GitLab customers: https://gitlab.com/gitlab-org/gitlab/-/issues/218999