Project

General

Profile

Feature #16965

io.c: Unsupported copy_file_range() not detected properly on certain kernels

Added by stanhu (Stan Hu) 3 months ago. Updated 22 days ago.

Status:
Closed
Priority:
Normal
Target version:
-
[ruby-core:98837]

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:

  1. Use a compile-time test to verify that copy_file_range() can actually be executed.
  2. 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 supports copy_file_range(), it would be helpful for us to manually disable it.

Reported by GitLab customers: https://gitlab.com/gitlab-org/gitlab/-/issues/218999

Also available in: Atom PDF