diff --git a/pkgs/tools/misc/coreutils/cp-1.patch b/pkgs/tools/misc/coreutils/cp-1.patch new file mode 100644 index 000000000000..f40fdbbead79 --- /dev/null +++ b/pkgs/tools/misc/coreutils/cp-1.patch @@ -0,0 +1,32 @@ +From 231cc20195294c9774ab68f523dd06059f4b0a5c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Wed, 29 Oct 2025 23:41:55 +0000 +Subject: [PATCH] copy: avoid posix_fadvise bypassing copy offload behavior + +* src/copy-file-data.c (): pass 0 to posix_fadvise to indicate to EOF. +coreutils 9.8 used OFF_T_MAX instead, which triggered OpenZFS 2.2.2 +at least to synchronously (decompress and) populate the page cache. +Addresses https://github.com/coreutils/coreutils/issues/122 +--- + src/copy-file-data.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/copy-file-data.c b/src/copy-file-data.c +index 1eefd3071f58a54f725c96dfcd2fd352012398c5..9eb6f47244f0a62c2f4934c7663794fd4dcf21bf 100644 +--- a/src/copy-file-data.c ++++ b/src/copy-file-data.c +@@ -536,9 +536,12 @@ copy_file_data (int ifd, struct stat const *ist, off_t ipos, char const *iname, + && scantype != PLAIN_SCANTYPE))); + + /* Don't bother calling fadvise for small copies, as it is not +- likely to help performance and might even hurt it. */ ++ likely to help performance and might even hurt it. ++ Note it's important to use a 0 length to indicate the whole file ++ as OpenZFS 2.2.2 at least will otherwise synchronously ++ (decompress and) populate the cache when given a specific length. */ + if (IO_BUFSIZE < ibytes) +- fdadvise (ifd, ipos, ibytes <= OFF_T_MAX - ipos ? ibytes : 0, ++ fdadvise (ifd, ipos, ibytes < OFF_T_MAX - ipos ? ibytes : 0, + FADVISE_SEQUENTIAL); + + /* If not making a sparse file, try to use a more-efficient diff --git a/pkgs/tools/misc/coreutils/cp-2.patch b/pkgs/tools/misc/coreutils/cp-2.patch new file mode 100644 index 000000000000..197269e78768 --- /dev/null +++ b/pkgs/tools/misc/coreutils/cp-2.patch @@ -0,0 +1,68 @@ +(NB: we drop the NEWS change to avoid conflicts) + +From 64b8fdb5b4767e0f833486507c3eae46ed1b40f8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Thu, 30 Oct 2025 13:02:48 +0000 +Subject: [PATCH] copy: don't avoid copy-offload upon SEEK_HOLE indicating + non-sparse + +* src/copy-file-data.c (infer_scantype): Fall back to a plain copy +if SEEK_HOLE indicates non-sparse, as zero copy avoids copy offload. +This was seen with transparently compressed files on OpenZFS. +* tests/cp/sparse-perf.sh: Add a test case even though it might +only trigger on compressed file systems that don't support reflink. +* NEWS: Mention the bug fix. +Addresses https://github.com/coreutils/coreutils/issues/122 +--- + NEWS | 8 ++++++++ + src/copy-file-data.c | 11 +++++++++-- + tests/cp/sparse-perf.sh | 10 ++++++++++ + 3 files changed, 27 insertions(+), 2 deletions(-) + +diff --git a/src/copy-file-data.c b/src/copy-file-data.c +index 9eb6f47244f0a62c2f4934c7663794fd4dcf21bf..8fd25fee9201eda7bd0a8caf01f02821a3390448 100644 +--- a/src/copy-file-data.c ++++ b/src/copy-file-data.c +@@ -481,12 +481,19 @@ infer_scantype (int fd, struct stat const *sb, off_t pos, + if (scan_inference->hole_start < sb->st_size) + return LSEEK_SCANTYPE; + +- /* Though the file likely has holes, SEEK_DATA and SEEK_HOLE ++ /* Though the file may have holes, SEEK_DATA and SEEK_HOLE + didn't find any. This can happen with file systems like + circa-2025 squashfs that support SEEK_HOLE only trivially. +- Fall back on ZERO_SCANTYPE. */ ++ This can also happen due to transparent file compression, ++ which can also indicate fewer than the usual number of blocks. */ ++ + if (lseek (fd, pos, SEEK_SET) < 0) + return ERROR_SCANTYPE; ++ ++ /* we prefer to return PLAIN_SCANTYPE here so that copy offload ++ continues to be used. Falling through to ZERO_SCANTYPE would be ++ less performant in the compressed file case. */ ++ return PLAIN_SCANTYPE; + } + } + else if (pos < scan_inference->ext_start || errno == ENXIO) +diff --git a/tests/cp/sparse-perf.sh b/tests/cp/sparse-perf.sh +index 5a283c1fe65816a36342d9f583c1ed787947bf10..5ee984c527d7d8b6395d4193fcf81804b1135b8a 100755 +--- a/tests/cp/sparse-perf.sh ++++ b/tests/cp/sparse-perf.sh +@@ -35,6 +35,16 @@ cmp $other_partition_sparse k2 || fail=1 + grep ': avoided' cp.out && { cat cp.out; fail=1; } + + ++# Create a large-non-sparse-but-compressible file ++# Ensure we don't avoid copy offload which we saw with ++# transparent compression on OpenZFS at least ++# (as that triggers our sparse heuristic). ++mls='might-look-sparse' ++yes | head -n1M > "$mls" || framework_failure_ ++cp --debug "$mls" "$mls.cp" >cp.out || fail=1 ++cmp "$mls" "$mls.cp" || fail=1 ++grep ': avoided' cp.out && { cat cp.out; fail=1; } ++ + + # Create a large-but-sparse file on the current partition. + # We disable relinking below, thus verifying SEEK_HOLE support diff --git a/pkgs/tools/misc/coreutils/cp-3.patch b/pkgs/tools/misc/coreutils/cp-3.patch new file mode 100644 index 000000000000..0c662e042e45 --- /dev/null +++ b/pkgs/tools/misc/coreutils/cp-3.patch @@ -0,0 +1,52 @@ +From 2c5754649e08a664f3d43f7bc1df08f498bc1554 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Fri, 31 Oct 2025 15:37:55 +0000 +Subject: [PATCH] copy: be more defensive/restrictive with posix_fadvise + +* src/copy-file-data.c (copy_file_data): Only give the +POSIX_FADV_SEQUENTIAL hint when we _know_ we'll definitely +use a read/write loop to copy the data. Also only apply +the hint to the whole file, as we've seen OpenZFS at least +special case that. +(sparse_copy): Update stale comment. +--- + src/copy-file-data.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/src/copy-file-data.c b/src/copy-file-data.c +index 8fd25fee9201eda7bd0a8caf01f02821a3390448..c46b7edc5228f5f1e9c398d8ad7ff20b6fa60fb6 100644 +--- a/src/copy-file-data.c ++++ b/src/copy-file-data.c +@@ -105,8 +105,6 @@ is_CLONENOTSUP (int err) + If HOLE_SIZE, look for holes in the input; *HOLE_SIZE contains + the size of the current hole so far, and update *HOLE_SIZE + at end to be the size of the hole at the end of the copy. +- Set *TOTAL_N_READ to the number of bytes read; this counts +- the trailing hole, which has not yet been output. + Read and update *DEBUG as needed. + If successful, return the number of bytes copied, + otherwise diagnose the failure and return -1. */ +@@ -542,14 +540,17 @@ copy_file_data (int ifd, struct stat const *ist, off_t ipos, char const *iname, + || (x->sparse_mode == SPARSE_AUTO + && scantype != PLAIN_SCANTYPE))); + +- /* Don't bother calling fadvise for small copies, as it is not +- likely to help performance and might even hurt it. +- Note it's important to use a 0 length to indicate the whole file ++ /* If we _know_ we're going to read data sequentially into the process, ++ i.e., --reflink or --sparse are not in auto mode, ++ give that hint to the kernel so it can tune caching behavior. ++ Also we don't bother calling fadvise for small copies, ++ as it is not likely to help performance and might even hurt it. ++ Also we only apply this hint for the whole file (0 length) + as OpenZFS 2.2.2 at least will otherwise synchronously + (decompress and) populate the cache when given a specific length. */ +- if (IO_BUFSIZE < ibytes) +- fdadvise (ifd, ipos, ibytes < OFF_T_MAX - ipos ? ibytes : 0, +- FADVISE_SEQUENTIAL); ++ if (ipos == 0 && ibytes == COUNT_MAX ++ && (x->reflink_mode != REFLINK_AUTO || x->sparse_mode != SPARSE_AUTO)) ++ fdadvise (ifd, 0, 0, FADVISE_SEQUENTIAL); + + /* If not making a sparse file, try to use a more-efficient + buffer size. */ diff --git a/pkgs/tools/misc/coreutils/default.nix b/pkgs/tools/misc/coreutils/default.nix index 4f94c41dcf42..221f9853f6af 100644 --- a/pkgs/tools/misc/coreutils/default.nix +++ b/pkgs/tools/misc/coreutils/default.nix @@ -55,6 +55,19 @@ stdenv.mkDerivation rec { hash = "sha256-5tT9LYUskUGhwqGKE9FGoM1+RRlfcik6TkwETsbMyhU="; }; + patches = [ + # Extremely bad bug where `tail` prints fewer lines than it should. + # https://github.com/coreutils/coreutils/commit/914972e80dbf82aac9ffe3ff1f67f1028e1a788b + ./tail.patch + # Fix performance regression in cp. + # https://github.com/coreutils/coreutils/commit/231cc20195294c9774ab68f523dd06059f4b0a5c + # https://github.com/coreutils/coreutils/commit/64b8fdb5b4767e0f833486507c3eae46ed1b40f8 + # https://github.com/coreutils/coreutils/commit/2c5754649e08a664f3d43f7bc1df08f498bc1554 + ./cp-1.patch + ./cp-2.patch + ./cp-3.patch + ]; + postPatch = '' # The test tends to fail on btrfs, f2fs and maybe other unusual filesystems. sed '2i echo Skipping dd sparse test && exit 77' -i ./tests/dd/sparse.sh diff --git a/pkgs/tools/misc/coreutils/tail.patch b/pkgs/tools/misc/coreutils/tail.patch new file mode 100644 index 000000000000..40336daae137 --- /dev/null +++ b/pkgs/tools/misc/coreutils/tail.patch @@ -0,0 +1,50 @@ +(NB: we omit the new test, in order to avoid rerunning autoconf.) + +From 914972e80dbf82aac9ffe3ff1f67f1028e1a788b Mon Sep 17 00:00:00 2001 +From: Hannes Braun +Date: Wed, 24 Sep 2025 21:20:49 +0200 +Subject: [PATCH] tail: fix tailing larger number of lines in regular files + +* src/tail.c (file_lines): Seek to the previous block instead of the +beginning (or a little before) of the block that was just scanned. +Otherwise, the same block is read and scanned (at least partially) +again. This bug was introduced by commit v9.7-219-g976f8abc1. +* tests/tail/basic-seek.sh: Add a new test. +* tests/local.mk: Reference the new test. +* NEWS: mention the bug fix. +--- + NEWS | 4 ++++ + src/tail.c | 2 +- + tests/local.mk | 1 + + tests/tail/basic-seek.sh | 28 ++++++++++++++++++++++++++++ + 4 files changed, 34 insertions(+), 1 deletion(-) + create mode 100755 tests/tail/basic-seek.sh + +diff --git a/NEWS b/NEWS +index 7a1a73113e839f010aa6c734e6f07da68827b953..dc1d26879327761d35499815776477771758edd4 100644 +--- a/NEWS ++++ b/NEWS +@@ -7,6 +7,10 @@ GNU coreutils NEWS -*- outline -*- + `basenc --base58` would not operate correctly with input > 15561475 bytes. + [bug introduced with --base58 in coreutils-9.8] + ++ 'tail' outputs the correct number of lines again for non-small -n values. ++ Previously it may have output too few lines. ++ [bug introduced in coreutils-9.8] ++ + + * Noteworthy changes in release 9.8 (2025-09-22) [stable] + +diff --git a/src/tail.c b/src/tail.c +index b8bef1d91cdb6cde2b666b6c1575376e075eaeb8..c7779c77dfe4cf5a672a265b6e796c7153590170 100644 +--- a/src/tail.c ++++ b/src/tail.c +@@ -596,7 +596,7 @@ file_lines (char const *prettyname, int fd, struct stat const *sb, + goto free_buffer; + } + +- pos = xlseek (fd, -bufsize, SEEK_CUR, prettyname); ++ pos = xlseek (fd, -(bufsize + bytes_read), SEEK_CUR, prettyname); + bytes_read = read (fd, buffer, bufsize); + if (bytes_read < 0) + {