diff --git a/Doc/library/os.rst b/Doc/library/os.rst index fceadde7df6bf4..525ec3a0c858ff 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1011,10 +1011,14 @@ as internal buffering of data. It will always copy no bytes and return 0 as if the file was empty because of a known Linux kernel issue. - .. availability:: Linux >= 4.5 with glibc >= 2.27. + .. availability:: Linux >= 4.5. .. versionadded:: 3.8 + .. versionchanged:: 3.16 + The function is now also available when Python is built against a libc + that lacks ``copy_file_range()``, such as glibc older than 2.27. + .. function:: device_encoding(fd) @@ -4400,10 +4404,14 @@ The following flags are used in :attr:`statvfs_result.f_flag`. the file descriptor, and as such multiple files can have the same name without any side effects. - .. availability:: Linux >= 3.17 with glibc >= 2.27. + .. availability:: Linux >= 3.17. .. versionadded:: 3.8 + .. versionchanged:: 3.16 + The function is now also available when Python is built against a libc + that lacks ``memfd_create()``, such as glibc older than 2.27. + .. data:: MFD_CLOEXEC MFD_ALLOW_SEALING diff --git a/Misc/NEWS.d/next/Library/2026-08-10-22-23-29.gh-issue-153400.nucElC.rst b/Misc/NEWS.d/next/Library/2026-08-10-22-23-29.gh-issue-153400.nucElC.rst new file mode 100644 index 00000000000000..78545a40c6b501 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-10-22-23-29.gh-issue-153400.nucElC.rst @@ -0,0 +1,4 @@ +On Linux, :func:`os.copy_file_range` and :func:`os.memfd_create` now fall back +to the raw syscall when the libc Python is built against does not provide the +wrapper function, so they stay available on interpreters built against a libc +older than glibc 2.27. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index a6092dd9f5638f..c9307a1c44d315 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -8853,7 +8853,7 @@ os_pwritev(PyObject *module, PyObject *const *args, Py_ssize_t nargs) #endif /* (defined(HAVE_PWRITEV) || defined (HAVE_PWRITEV2)) */ -#if defined(HAVE_COPY_FILE_RANGE) +#if defined(_Py_HAVE_COPY_FILE_RANGE) PyDoc_STRVAR(os_copy_file_range__doc__, "copy_file_range($module, /, src, dst, count, offset_src=None,\n" @@ -8969,7 +8969,7 @@ os_copy_file_range(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py return return_value; } -#endif /* defined(HAVE_COPY_FILE_RANGE) */ +#endif /* defined(_Py_HAVE_COPY_FILE_RANGE) */ #if ((defined(HAVE_SPLICE) && !defined(_AIX))) @@ -11547,7 +11547,7 @@ os_urandom(PyObject *module, PyObject *arg) return return_value; } -#if defined(HAVE_MEMFD_CREATE) +#if defined(_Py_HAVE_MEMFD_CREATE) PyDoc_STRVAR(os_memfd_create__doc__, "memfd_create($module, /, name, flags=MFD_CLOEXEC)\n" @@ -11633,7 +11633,7 @@ os_memfd_create(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj return return_value; } -#endif /* defined(HAVE_MEMFD_CREATE) */ +#endif /* defined(_Py_HAVE_MEMFD_CREATE) */ #if (defined(HAVE_EVENTFD) && defined(EFD_CLOEXEC)) @@ -13746,4 +13746,4 @@ os__emscripten_log(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #ifndef OS__EMSCRIPTEN_LOG_METHODDEF #define OS__EMSCRIPTEN_LOG_METHODDEF #endif /* !defined(OS__EMSCRIPTEN_LOG_METHODDEF) */ -/*[clinic end generated code: output=6dc1e061bfd47375 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f77ed566165d51da input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index a7208aeef1871e..d94291e2ae524b 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -157,8 +157,8 @@ #ifdef HAVE_LINUX_RANDOM_H # include // GRND_RANDOM #endif -#ifdef HAVE_GETRANDOM_SYSCALL -# include // syscall() +#ifdef HAVE_SYS_SYSCALL_H +# include // syscall(), __NR_xxx syscall numbers #endif #ifdef HAVE_POSIX_SPAWN @@ -13133,7 +13133,12 @@ os_pwritev_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset, } #endif /* HAVE_PWRITEV */ -#ifdef HAVE_COPY_FILE_RANGE +#if defined(HAVE_COPY_FILE_RANGE) || \ + (defined(__linux__) && defined(__NR_copy_file_range)) +# define _Py_HAVE_COPY_FILE_RANGE +#endif + +#ifdef _Py_HAVE_COPY_FILE_RANGE /*[clinic input] os.copy_file_range @@ -13185,7 +13190,13 @@ os_copy_file_range_impl(PyObject *module, int src, int dst, Py_ssize_t count, do { Py_BEGIN_ALLOW_THREADS +#ifdef HAVE_COPY_FILE_RANGE ret = copy_file_range(src, p_offset_src, dst, p_offset_dst, count, flags); +#else + /* Largefile support makes off_t 64-bit, as the kernel expects. */ + ret = syscall(__NR_copy_file_range, src, p_offset_src, dst, p_offset_dst, + count, flags); +#endif Py_END_ALLOW_THREADS } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); @@ -13195,7 +13206,7 @@ os_copy_file_range_impl(PyObject *module, int src, int dst, Py_ssize_t count, return PyLong_FromSsize_t(ret); } -#endif /* HAVE_COPY_FILE_RANGE*/ +#endif /* _Py_HAVE_COPY_FILE_RANGE */ #if (defined(HAVE_SPLICE) && !defined(_AIX)) /*[clinic input] @@ -15897,7 +15908,12 @@ os_urandom_impl(PyObject *module, Py_ssize_t size) return PyBytesWriter_Finish(writer); } -#ifdef HAVE_MEMFD_CREATE +#if defined(HAVE_MEMFD_CREATE) || \ + (defined(__linux__) && defined(__NR_memfd_create) && defined(MFD_CLOEXEC)) +# define _Py_HAVE_MEMFD_CREATE +#endif + +#ifdef _Py_HAVE_MEMFD_CREATE /*[clinic input] os.memfd_create @@ -15913,7 +15929,11 @@ os_memfd_create_impl(PyObject *module, PyObject *name, unsigned int flags) int fd; const char *bytes = PyBytes_AS_STRING(name); Py_BEGIN_ALLOW_THREADS +#ifdef HAVE_MEMFD_CREATE fd = memfd_create(bytes, flags); +#else + fd = syscall(__NR_memfd_create, bytes, flags); +#endif Py_END_ALLOW_THREADS if (fd == -1) { return PyErr_SetFromErrno(PyExc_OSError); @@ -18533,7 +18553,7 @@ all_ins(PyObject *m) if (PyModule_AddIntMacro(m, GRND_RANDOM)) return -1; if (PyModule_AddIntMacro(m, GRND_NONBLOCK)) return -1; #endif -#ifdef HAVE_MEMFD_CREATE +#ifdef _Py_HAVE_MEMFD_CREATE if (PyModule_AddIntMacro(m, MFD_CLOEXEC)) return -1; if (PyModule_AddIntMacro(m, MFD_ALLOW_SEALING)) return -1; #ifdef MFD_HUGETLB @@ -18581,7 +18601,7 @@ all_ins(PyObject *m) #ifdef MFD_HUGE_16GB if (PyModule_AddIntMacro(m, MFD_HUGE_16GB)) return -1; #endif -#endif /* HAVE_MEMFD_CREATE */ +#endif /* _Py_HAVE_MEMFD_CREATE */ #if defined(HAVE_EVENTFD) && defined(EFD_CLOEXEC) if (PyModule_AddIntMacro(m, EFD_CLOEXEC)) return -1; @@ -18837,7 +18857,7 @@ static const struct have_function { { "HAVE_LUTIMES", NULL }, #endif -#ifdef HAVE_MEMFD_CREATE +#ifdef _Py_HAVE_MEMFD_CREATE { "HAVE_MEMFD_CREATE", NULL }, #endif