]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
cp: with --sparse=never, avoid COW and copy offload
authorPádraig Brady <P@draigBrady.com>
Mon, 21 Aug 2023 12:39:14 +0000 (13:39 +0100)
committerPádraig Brady <P@draigBrady.com>
Mon, 21 Aug 2023 13:28:14 +0000 (14:28 +0100)
* src/cp.c (main): Set default reflink mode appropriately
with --sparse=never.
* src/copy.c (infer_scantype): Add a comment to related code.
* tests/cp/sparse-2.sh: Add a test case.
* NEWS: Mention the bug.

NEWS
src/copy.c
src/cp.c
tests/cp/sparse-2.sh

diff --git a/NEWS b/NEWS
index c7e6b47c3def96198f9fc1ef1ab4507fe64c88c5..a104c97a264583befb44306cf555105f37e0aa13 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   Previously it would have failed with a "No such file or directory" error.
   [bug introduced in coreutils-9.1]
 
+  'cp --sparse=never' will avoid copy-on-write (reflinking) and copy offloading,
+  to ensure no holes present in the destination copy.
+  [bug introduced in coreutils-9.0]
+
   cksum again diagnoses read errors in its default CRC32 mode.
   [bug introduced in coreutils-9.0]
 
index a4aad06a8ec826273a1bb4cfb2530ffefa4d7d31..4943619c201707ad878bafc3ab160cbb341dd1fa 100644 (file)
@@ -1139,6 +1139,8 @@ infer_scantype (int fd, struct stat const *sb,
 {
   scan_inference->ext_start = -1;  /* avoid -Wmaybe-uninitialized */
 
+  /* Only attempt SEEK_HOLE if this heuristic
+     suggests the file is sparse.  */
   if (! (HAVE_STRUCT_STAT_ST_BLOCKS
          && S_ISREG (sb->st_mode)
          && ST_NBLOCKS (*sb) < sb->st_size / ST_NBLOCKSIZE))
index 412ef500bc52a74bba430e85e53464de25818c49..e451a7e294be5c93231175f949ee30ea8ca70c7d 100644 (file)
--- a/src/cp.c
+++ b/src/cp.c
@@ -1201,6 +1201,13 @@ main (int argc, char **argv)
         }
     }
 
+  /* With --sparse=never, disable reflinking so we create a non sparse copy.
+     This will also have the effect of disabling copy offload as that may
+     propagate holes.  For e.g. FreeBSD documents that copy_file_range()
+     will try to propagate holes.  */
+  if (x.reflink_mode == REFLINK_AUTO && x.sparse_mode == SPARSE_NEVER)
+    x.reflink_mode = REFLINK_NEVER;
+
   if (x.hard_link && x.symbolic_link)
     {
       error (0, 0, _("cannot make both hard and symbolic links"));
index 65607648ac828eafac6e6369fa7679c586e95ee5..5d3c5ece9abe0bc1908ebdd97d14d6cda9f88a00 100755 (executable)
@@ -48,4 +48,9 @@ cp --debug --reflink=never --sparse=always k k2 >cp.out || fail=1
 cmp k k2 || fail=1
 grep 'sparse detection: .*zeros' cp.out || { cat cp.out; fail=1; }
 
+# cp should disable reflink AND copy offload with --sparse=never
+cp --debug --sparse=never k k2 >cp.out || fail=1
+cmp k k2 || fail=1
+grep 'copy offload: avoided, reflink: no' cp.out || { cat cp.out; fail=1; }
+
 Exit $fail