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_RANGEvia 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