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