Subject: Re: bug#60455: Missing fallback if copy_file_range returns ENOENT?

From: Pádraig Brady <[email-masked]>
Date: Sat, 7 Jan 2023 16:25:07 +0000

On 07/01/2023 07:34, Sam James wrote:
> 
> 
>> On 31 Dec 2022, at 18:51, Pádraig Brady <[email-masked]> wrote:
>>
>> On 31/12/2022 17:00, Sam James wrote:
>>> Hi folks,
>>> Originally reported in Gentoo at https://bugs.gentoo.org/885793.
>>> Frank Limpert reported that when copying large files across CIFS shares,
>>> cp may abort because copy_file_range returns ENOENT sometimes.
>>> This sounds like a suspicious kernel bug if CIFS interactions are sometimes
>>> spuriously giving ENOENT, but I'm wondering if coreutils needs to do
>>> anything to handle this as well.
>>> strace output from his cp invocation: https://bugs.gentoo.org/attachment.cgi?id=842497
>>
>> We may be able to fallback, but it depends if the errno
>> is possible to be returned at a partial copy or not.
>> If partial then there is not much we can do.
>> Now ENOENT is not a documented errno for copy_file_range()
>> so I'm not sure what we should do with it.
>> I didn't see on the bug above if any data was copied.
>> Could we get more info about that?
> 
> Frank got back to me and said an empty file gets created:
> ```
> # cp /mnt/Backup/EAV/data-eav-eav-aktiv-20221207.dump.xz /mnt/OldBackup/EAV/1
> cp: error copying '/mnt/Backup/EAV/data-eav-eav-aktiv-20221207.dump.xz' to '/mnt/OldBackup/EAV/1/data-eav-eav-aktiv-20221207.dump.xz': No such file or directory
> # stat /mnt/OldBackup/EAV/1/data-eav-eav-aktiv-20221207.dump.xz
> File: /mnt/OldBackup/EAV/1/data-eav-eav-aktiv-20221207.dump.xz
> Size: 0 Blocks: 8 IO Block: 1048576 regular empty file

OK then it's probably worth handling in coreutils then.
Note I still get the feeling this is a race in CIFS
that is only being made more apparent with copy_file_range(),
but fair enough that this is a regressions for users and
we should be able to cater for it easy enough.

The attached does that for ENOENT.

cheers,
Pádraig
From d4ffe81e2bb738a304f6d6d65edd1fa4a56929e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email-masked]>
Date: Sat, 7 Jan 2023 16:10:01 +0000
Subject: [PATCH] copy: copy_file_range: handle ENOENT for CIFS

* src/copy.c (sparse_copy): Fallback to standard copy upon ENOENT,
which was seen intermittently across CIFS file systems.
* NEWS: Mention the bug fix.
Fixes https://bugs.gnu.org/60455
---
 NEWS       | 4 ++++
 src/copy.c | 5 +++++
 2 files changed, 9 insertions(+)

diff --git a/NEWS b/NEWS
index 3105df3f8..5cae1197e 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   which may have resulted in data corruption.
   [bug introduced in coreutils-7.5 and enabled by default in coreutils-9.0]
 
+  cp, mv, and install now handle ENOENT failures across CIFS file systems,
+  falling back from copy_file_range to a better supported standard copy.
+  [bug introduced in coreutils-9.0]
+
   'mv --backup=simple f d/' no longer mistakenly backs up d/f to f~.
   [bug introduced in coreutils-9.1]
 
diff --git a/src/copy.c b/src/copy.c
index 519c43b00..98f2ba45a 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -290,6 +290,11 @@ sparse_copy (int src_fd, int dest_fd, char **abuf, size_t buf_size,
             if (errno == EPERM && *total_n_read == 0)
               break;
 
+            /* ENOENT was seen sometimes across CIFS shares, resulting in
+               no data being copied, but subsequent standard copies succeed.  */
+            if (errno == ENOENT && *total_n_read == 0)
+              break;
+
             if (errno == EINTR)
               n_copied = 0;
             else
-- 
2.26.2