+2025-08-01 Paul Eggert <eggert@cs.ucla.edu>
+
+ copy-file-range: tune for more-modern kernels
+ * lib/copy-file-range.c [__linux__ && HAVE_COPY_FILE_RANGE]:
+ Include <linux/version.h>. Include <sys/utsname.h>
+ only for kernel 5.2 and earlier.
+ (CHECK_LINUX_KERNEL_VERSION): New macro.
+ (copy_file_range) [__linux__ && HAVE_COPY_FILE_RANGE]:
+ Call utsname only when built for kernel 5.2 and earlier.
+ (copy_file_range) [!__linux__ && HAVE_COPY_FILE_RANGE]:
+ Use underlying copy_file_range. This doesn’t change
+ behavior since the code is not compiled in this case,
+ but it makes the code a bit cleaner.
+ * modules/copy-file-range (Depends-on): Add bool.
+
2025-08-01 Bruno Haible <bruno@clisp.org>
sigsegv: Use new ioctl available in Linux >= 6.11.
#include <errno.h>
#if defined __linux__ && HAVE_COPY_FILE_RANGE
+# include <linux/version.h>
# include <sys/utsname.h>
+# if LINUX_VERSION_CODE < KERNEL_VERSION (5, 3, 0)
+# define CHECK_LINUX_KERNEL_VERSION true
+# else
+# define CHECK_LINUX_KERNEL_VERSION false
+# endif
#endif
ssize_t
{
#undef copy_file_range
-#if defined __linux__ && HAVE_COPY_FILE_RANGE
+#if HAVE_COPY_FILE_RANGE
+ bool ok = true;
+
+# if CHECK_LINUX_KERNEL_VERSION
/* The implementation of copy_file_range (which first appeared in
Linux kernel release 4.5) had many issues before release 5.3
<https://lwn.net/Articles/789527/>, so fail with ENOSYS for Linux
kernels 5.2 and earlier.
- This workaround, and the configure-time check for Linux, can be
- removed when such kernels (released March 2016 through September
- 2019) are no longer a consideration. As of January 2021, the
- furthest-future planned kernel EOL is December 2024 for kernel
- release 4.19. */
+ This workaround can be removed when such kernels (released March
+ 2016 through September 2019) are no longer a consideration.
+ Although all such kernels have reached EOL, some distros use
+ older kernels. For example, RHEL 8 uses kernel 4.18 and has an
+ EOL of 2029. */
- static signed char ok;
+ static signed char kernel_ok;
+ if (! kernel_ok)
+ {
+ struct utsname name;
+ uname (&name);
+ char *p = name.release;
+ kernel_ok = ((p[1] != '.' || '5' < p[0]
+ || (p[0] == '5' && (p[3] != '.' || '2' < p[2])))
+ ? 1 : -1);
+ }
- if (! ok)
- {
- struct utsname name;
- uname (&name);
- char *p = name.release;
- ok = ((p[1] != '.' || '5' < p[0]
- || (p[0] == '5' && (p[3] != '.' || '2' < p[2])))
- ? 1 : -1);
- }
+ if (kernel_ok < 0)
+ ok = false;
+# endif
- if (0 < ok)
- return copy_file_range (infd, pinoff, outfd, poutoff, length, flags);
+ if (ok)
+ return copy_file_range (infd, pinoff, outfd, poutoff, length, flags);
#endif
/* There is little need to emulate copy_file_range with read+write,