diff --git a/coreutils-8.32-cp-file-range.patch b/coreutils-8.32-cp-file-range.patch index 6efdf52..6d3f651 100644 --- a/coreutils-8.32-cp-file-range.patch +++ b/coreutils-8.32-cp-file-range.patch @@ -1,7 +1,7 @@ From 5f2dac18054d9d9b3d84e7fba8c2a6e750d2c245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?= Date: Wed, 1 Apr 2020 12:51:34 +0100 -Subject: [PATCH 1/8] cp: ensure --attributes-only doesn't remove files +Subject: [PATCH 01/12] cp: ensure --attributes-only doesn't remove files * src/copy.c (copy_internal): Ensure we don't unlink the destination unless explicitly requested. @@ -77,7 +77,7 @@ index 59ce641..14fc844 100755 From c728747b06e71894c96d1f27434f2484af992c75 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 23 Jun 2020 19:18:04 -0700 -Subject: [PATCH 2/8] cp: refactor extent_copy +Subject: [PATCH 02/12] cp: refactor extent_copy * src/copy.c (extent_copy): New arg SCAN, replacing REQUIRE_NORMAL_COPY. All callers changed. @@ -320,7 +320,7 @@ index 54601ce..f694f91 100644 From ed7ff81de507bef46991f4caac550f41ab65e3ed Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 24 Jun 2020 17:05:20 -0700 -Subject: [PATCH 3/8] cp: avoid copy_reg goto +Subject: [PATCH 03/12] cp: avoid copy_reg goto * src/copy.c (copy_reg): Redo to avoid label and goto. @@ -390,7 +390,7 @@ index f694f91..b382cfa 100644 From 5631bded3a385ca0bbd77456b50767fe5580240c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 25 Jun 2020 16:31:44 -0700 -Subject: [PATCH 4/8] cp: use SEEK_DATA/SEEK_HOLE if available +Subject: [PATCH 04/12] cp: use SEEK_DATA/SEEK_HOLE if available If it works, prefer lseek with SEEK_DATA and SEEK_HOLE to FIEMAP, as lseek is simpler and more portable (will be in next POSIX). @@ -701,7 +701,7 @@ index b382cfa..d88f8cf 100644 From be7466be92d779cfbece418d4de33191ae52ab4a Mon Sep 17 00:00:00 2001 From: Kamil Dudka Date: Wed, 24 Mar 2021 16:06:53 +0100 -Subject: [PATCH 5/8] import the copy-file-range module from gnulib +Subject: [PATCH 05/12] import the copy-file-range module from gnulib --- aclocal.m4 | 1 + @@ -896,7 +896,7 @@ index dead90e..953e7f0 100644 From 48370c95bcf7c25ce021fbd2145062d3d29ae6d5 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 25 Jun 2020 17:34:23 -0700 -Subject: [PATCH 6/8] cp: use copy_file_range if available +Subject: [PATCH 06/12] cp: use copy_file_range if available * NEWS: Mention this. * bootstrap.conf (gnulib_modules): Add copy-file-range. @@ -980,7 +980,7 @@ index d88f8cf..4050f69 100644 From 23ea1ba463d33e268f35847059e637a5935e4581 Mon Sep 17 00:00:00 2001 From: Zorro Lang Date: Mon, 26 Apr 2021 17:25:18 +0200 -Subject: [PATCH 7/8] copy: do not refuse to copy a swap file +Subject: [PATCH 07/12] copy: do not refuse to copy a swap file * src/copy.c (sparse_copy): Fallback to read() if copy_file_range() fails with ETXTBSY. Otherwise it would be impossible to copy files @@ -1013,7 +1013,7 @@ index 4050f69..1798bb7 100644 From cd7c7a6b5ad89ef0a61722552d532901fc1bed05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?= Date: Sun, 2 May 2021 21:27:17 +0100 -Subject: [PATCH 8/8] copy: ensure we enforce --reflink=never +Subject: [PATCH 08/12] copy: ensure we enforce --reflink=never * src/copy.c (sparse_copy): Don't use copy_file_range() with --reflink=never as copy_file_range() may implicitly @@ -1115,3 +1115,225 @@ index 4050f69..0337538 100644 -- 2.30.2 + +From 7978f1de88dcdb17b67db9268038930e9c71154f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Sat, 8 May 2021 17:18:54 +0100 +Subject: [PATCH 09/12] copy: handle ENOTSUP from copy_file_range() + +* src/copy.c (sparse_copy): Ensure we fall back to +a standard copy if copy_file_range() returns ENOTSUP. +This generally is best checked when checking ENOSYS, +but it also seems to be a practical concern on Centos 7, +as a quick search gave https://bugzilla.redhat.com/1840284 + +Upstream-commit: 8ec0d1799e19a079b8a661c6bb69f6c58e52f1aa +Signed-off-by: Kamil Dudka +--- + src/copy.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/copy.c b/src/copy.c +index 9977193..e3977cd 100644 +--- a/src/copy.c ++++ b/src/copy.c +@@ -290,8 +290,9 @@ sparse_copy (int src_fd, int dest_fd, char *buf, size_t buf_size, + } + if (n_copied < 0) + { +- if (errno == ENOSYS || errno == EINVAL +- || errno == EBADF || errno == EXDEV || errno == ETXTBSY) ++ if (errno == ENOSYS || is_ENOTSUP (errno) ++ || errno == EINVAL || errno == EBADF ++ || errno == EXDEV || errno == ETXTBSY) + break; + if (errno == EINTR) + n_copied = 0; +-- +2.31.1 + + +From d8d3edbfc13ff13c185f23436209b788f906aa41 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Sun, 9 May 2021 21:55:22 +0100 +Subject: [PATCH 10/12] copy: handle EOPNOTSUPP from SEEK_DATA + +* src/copy.c (infer_scantype): Ensure we don't error out +if SEEK_DATA returns EOPNOTSUPP, on systems where this value +is distinct from ENOTSUP. Generally both of these should be checked. + +Upstream-commit: 017877bd088284d515753d78b81ca6e6a88c1350 +Signed-off-by: Kamil Dudka +--- + src/copy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/copy.c b/src/copy.c +index e3977cd..de8030d 100644 +--- a/src/copy.c ++++ b/src/copy.c +@@ -1246,7 +1246,7 @@ infer_scantype (int fd, struct stat const *sb, + scan_inference->ext_start = lseek (fd, 0, SEEK_DATA); + if (0 <= scan_inference->ext_start) + return LSEEK_SCANTYPE; +- else if (errno != EINVAL && errno != ENOTSUP) ++ else if (errno != EINVAL && !is_ENOTSUP (errno)) + return errno == ENXIO ? LSEEK_SCANTYPE : ERROR_SCANTYPE; + #endif + +-- +2.31.1 + + +From 1daf8c0fc9a5766c22b7ea84bea8c88c86a0c495 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Sat, 8 May 2021 19:23:20 +0100 +Subject: [PATCH 11/12] copy: handle system security config issues with + copy_file_range() + +* src/copy.c (sparse_copy): Upon EPERM from copy_file_range(), +fall back to a standard copy, which will give a more accurate +error as to whether the issue is with the source or destination. +Also this will avoid the issue where seccomp or apparmor are +not configured to handle copy_file_range(), in which case +the fall back standard copy would succeed without issue. +This specific issue with seccomp was noticed for example in: +https://github.com/golang/go/issues/40900 + +Upstream-commit: 2e66e1732fced7af20fa76c60e636d39a1767d48 +Signed-off-by: Kamil Dudka +--- + src/copy.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/copy.c b/src/copy.c +index de8030d..62eec7b 100644 +--- a/src/copy.c ++++ b/src/copy.c +@@ -294,6 +294,15 @@ sparse_copy (int src_fd, int dest_fd, char *buf, size_t buf_size, + || errno == EINVAL || errno == EBADF + || errno == EXDEV || errno == ETXTBSY) + break; ++ ++ /* copy_file_range might not be enabled in seccomp filters, ++ so retry with a standard copy. EPERM can also occur ++ for immutable files, but that would only be in the edge case ++ where the file is made immutable after creating/truncating, ++ in which case the (more accurate) error is still shown. */ ++ if (errno == EPERM && *total_n_read == 0) ++ break; ++ + if (errno == EINTR) + n_copied = 0; + else +-- +2.31.1 + + +From 42c9e598f61ba6bc27a615e39e40023a676a523b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Wed, 12 May 2021 23:47:38 +0100 +Subject: [PATCH 12/12] copy: disallow copy_file_range() on Linux kernels + before 5.3 + +copy_file_range() before Linux kernel release 5.3 had many issues, +as described at https://lwn.net/Articles/789527/, which was +referenced from https://lwn.net/Articles/846403/; a more general +article discussing the generality of copy_file_range(). +Linux kernel 5.3 was released in September 2019, which is new enough +that we need to actively avoid older kernels. + +* src/copy.c (functional_copy_file_range): A new function +that returns false for Linux kernels before version 5.3. +(sparse_copy): Call this new function to gate use of +copy_file_range(). + +Upstream-commit: ba5e6885d2c255648cddb87b4e795659c1990374 +Signed-off-by: Kamil Dudka +--- + src/copy.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 45 insertions(+), 2 deletions(-) + +diff --git a/src/copy.c b/src/copy.c +index 62eec7b..2e1699b 100644 +--- a/src/copy.c ++++ b/src/copy.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + #if HAVE_HURD_H +@@ -64,6 +65,7 @@ + #include "write-any-file.h" + #include "areadlink.h" + #include "yesno.h" ++#include "xstrtol.h" + #include "selinux.h" + + #if USE_XATTR +@@ -244,6 +246,47 @@ create_hole (int fd, char const *name, bool punch_holes, off_t size) + return true; + } + ++/* copy_file_range() before Linux kernel release 5.3 had many issues, ++ as described at https://lwn.net/Articles/789527/, ++ so return FALSE for Linux kernels earlier than that. ++ This function can be removed when such kernels (released before Sep 2019) ++ are no longer a consideration. */ ++ ++static bool ++functional_copy_file_range (void) ++{ ++#ifdef __linux__ ++ static int version_allowed = -1; ++ ++ if (version_allowed == -1) ++ version_allowed = 0; ++ else ++ return version_allowed; ++ ++ struct utsname name; ++ if (uname (&name) == -1) ++ return version_allowed; ++ ++ char *p = name.release; ++ uintmax_t ver[2] = {0, 0}; ++ size_t iver = 0; ++ ++ do ++ { ++ strtol_error err = xstrtoumax (p, &p, 10, &ver[iver], NULL); ++ if (err != LONGINT_OK || *p++ != '.') ++ break; ++ } ++ while (++iver < ARRAY_CARDINALITY (ver)); ++ ++ version_allowed = (ver[0] > 5 || (ver[0] == 5 && ver[1] >= 3)); ++ ++ return version_allowed; ++#else ++ return true; ++#endif ++ ++} + + /* Copy the regular file open on SRC_FD/SRC_NAME to DST_FD/DST_NAME, + honoring the MAKE_HOLES setting and using the BUF_SIZE-byte buffer +@@ -266,9 +309,9 @@ sparse_copy (int src_fd, int dest_fd, char *buf, size_t buf_size, + *last_write_made_hole = false; + *total_n_read = 0; + +- /* If not looking for holes, use copy_file_range if available, ++ /* If not looking for holes, use copy_file_range if functional, + but don't use if reflink disallowed as that may be implicit. */ +- if ((! hole_size) && allow_reflink) ++ if ((! hole_size) && allow_reflink && functional_copy_file_range ()) + while (max_n_read) + { + /* Copy at most COPY_MAX bytes at a time; this is min +-- +2.31.1 + diff --git a/coreutils.spec b/coreutils.spec index 17c1b71..806886b 100644 --- a/coreutils.spec +++ b/coreutils.spec @@ -1,7 +1,7 @@ Summary: A set of basic GNU tools commonly used in shell scripts Name: coreutils Version: 8.32 -Release: 25%{?dist} +Release: 26%{?dist} License: GPLv3+ Url: https://www.gnu.org/software/coreutils/ Source0: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz @@ -308,6 +308,9 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir %license COPYING %changelog +* Mon May 17 2021 Kamil Dudka - 8.32-26 +- cp: pick additional copy_file_range()-related fixes from upstream + * Mon May 03 2021 Kamil Dudka - 8.32-25 - copy: ensure we enforce --reflink=never