Subject: Re: bug#51857: cross-filesystem copying broken on macOS with coreutils >= 9.0

From: Pádraig Brady <[email-masked]>
Date: Mon, 15 Nov 2021 23:20:08 +0000

On 15/11/2021 18:37, Sudhip Nashi via GNU coreutils Bug Reports wrote:
> 
>> On Nov 15, 2021, at 11:33, Paul Eggert <[email-masked]> wrote:
>>
>> Is the source file on a ZFS file system by any chance? See my lseek comment below.
>>
>>> On 11/15/21 07:48, Cameron Katri via GNU coreutils Bug Reports wrote:
>>>
>>> stat64("/tmp/test\0", 0x16DDC36C0, 0x0)         = 0 0
>>> fstatat64(0xFFFFFFFFFFFFFFFE, 0x16DDC3C21, 0x16DDC2BA0)         = 0 0
>>> fstatat64(0xFFFFFFFFFFFFFFFE, 0x16DDC3C30, 0x16DDC2B10)         = 0 0
>>> open("/usr/bin/clear\0", 0x0, 0x0)         = 3 0
>>> fstat64(0x3, 0x16DDC2C30, 0x0)         = 0 0
>>> open("/tmp/test\0", 0x401, 0x0)         = 4 0
>>> fstat64(0x4, 0x16DDC2CC0, 0x0)         = 0 0
>>> fstat64(0x4, 0x16DDC2D50, 0x0)         = 0 0
>>> fcntl(0x3, 0x32, 0x16DDC3200)         = 0 0
>>> fcntl(0x4, 0x32, 0x16DDC2E00)         = 0 0
>>> unlink("/private/tmp/test\0", 0x0, 0x0)         = 0 0
>>
>> What's causing this use of "/private/tmp"? I don't see that in the GNU cp source code. Can you put a breakpoint on clonefileat and see what's calling it and what its arguments are?
>>
>>> clonefileat(0xFFFFFFFFFFFFFFFE, 0x16DDC3200, 0xFFFFFFFFFFFFFFFE)         = -1 Err#18
>>> open("/private/tmp/test\0", 0x601, 0x81ED)         = 5 0
>>> close(0x5)         = 0 0
>>> open("/private/tmp/test\0", 0x2, 0x0)         = 5 0
>>> dup2(0x5, 0x4, 0x0)         = 4 0
>>> close(0x5)         = 0 0
>>> fchmod(0x4, 0x81ED, 0x0)         = 0 0
>>> fchown(0x4, 0x0, 0x0)         = 0 0
>>> futimes(0x4, 0x16DDC2DE0, 0x0)         = 0 0
>>> sysctl([CTL_HW, 7, 0, 0, 0, 0] (2), 0x207EC4068, 0x16DDC2A30, 0x0, 0x0)         = 0 0
>>> lseek(0x3, 0x0, 0x4)         = -1 Err#6
>>
>> That lseek call looks like OpenZFS bug 11900 <https://github.com/openzfs/zfs/issues/11900>. If you're using ZFS, the bug really should be fixed in your ZFS implementation as it can affect programs other than coreutils and there's no easy workaround (other than to disable efficient copying). Is this something you can look into, or ask someone with macOS and/or ZFS expertise to look into? For more, see <https://bugs.gnu.org/51433>.
>>
>>> ftruncate(0x4, 0x1D770, 0x0)         = 0 0
>>> close(0x4)         = 0 0
>>> close(0x3)         = 0 0
> 
> Turns out lseek is broken (or at least works differently) on macOS as well (https://lists.gnu.org/archive/html/bug-gnulib/2018-09/msg00054.html). Funny coincidence! I’ll take a better look later this week if I can and try to see what the exact problem is.

I saw on other report of failure on macOS.
I think we should disable the SEEK_DATA optimization there for now.
The attached does that.

I'll apply that later.
I also have access to a macOS system, so I'll also test out
if there are ways to use SEEK_DATA there.

thanks,
Pádraig
From e82670759e7eea3fb9faec99fcd94ad9f2fe03b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email-masked]>
Date: Mon, 15 Nov 2021 23:15:07 +0000
Subject: [PATCH] copy: avoid SEEK_DATA on macOS

* src/copy.c (infer_scantype): Don't probe for SEEK_DATA support
on __APPLE__ systems, as SEEK_DATA was seen to return ENXIO
inappropriately there.
* init.cfg (seek_data_capable_): Return failure on Darwin systems.
Addresses https://bugs.gnu.org/51857
---
 init.cfg   | 6 ++++++
 src/copy.c | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/init.cfg b/init.cfg
index b92f717f5..2ab607cf3 100644
--- a/init.cfg
+++ b/init.cfg
@@ -533,6 +533,12 @@ require_kill_group_()
 # which SEEK_DATA support exists.
 seek_data_capable_()
 {
+  # The SEEK_DATA implementation on macOS is not supported
+  if test "$(uname)" = Darwin; then
+    warn_ 'seek_data_capable_: Darwin detected: assuming not SEEK_DATA capable'
+    return 1
+  fi
+
   { python3 < /dev/null && PYTHON_=python3; } ||
   { python  < /dev/null && PYTHON_=python; }
 
diff --git a/src/copy.c b/src/copy.c
index f88bf3ed3..ecb37a02c 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -1100,7 +1100,7 @@ infer_scantype (int fd, struct stat const *sb,
          && ST_NBLOCKS (*sb) < sb->st_size / ST_NBLOCKSIZE))
     return PLAIN_SCANTYPE;
 
-#ifdef SEEK_HOLE
+#if defined SEEK_HOLE && !defined __APPLE__
   scan_inference->ext_start = lseek (fd, 0, SEEK_DATA);
   if (0 <= scan_inference->ext_start || errno == ENXIO)
     return LSEEK_SCANTYPE;
-- 
2.26.2