Add patch to fix filesystem::copy_file EXDEV handling
Resolves: #2106878
This commit is contained in:
parent
2844380e87
commit
5117e662ba
|
@ -0,0 +1,152 @@
|
|||
From 4b9052f1e0b2acf625e8247582f44acdcc78a4ce Mon Sep 17 00:00:00 2001
|
||||
From: Andrey Semashev <andrey.semashev@gmail.com>
|
||||
Date: Tue, 18 May 2021 22:53:40 +0300
|
||||
Subject: [PATCH] Fallback to read/write loop if sendfile/copy_file_range fail.
|
||||
|
||||
Since sendfile and copy_file_range can fail for some filesystems
|
||||
(e.g. eCryptFS), we have to fallback to the read/write loop in copy_file
|
||||
implementation. Additionally, since we implement the fallback now,
|
||||
fallback to sendfile if copy_file_range fails with EXDEV and use
|
||||
copy_file_range on older kernels that don't implement it for
|
||||
cross-filesystem copying. This may be beneficial if copy_file_range
|
||||
is used within a filesystem, and is performed on a remote server NFS or CIFS).
|
||||
|
||||
Also, it was discovered that copy_file_range can also fail with EOPNOTSUPP
|
||||
when it is performed on an NFSv4 filesystem and the remote server does
|
||||
not support COPY operation. This happens on some patched kernels in RHEL/CentOS.
|
||||
|
||||
Lastly, to make sure the copy_file_data pointer is accessed atomically,
|
||||
it is now declared as an atomic value. If std::atomic is unavailable,
|
||||
Boost.Atomic is used.
|
||||
|
||||
Fixes https://github.com/boostorg/filesystem/issues/184.
|
||||
---
|
||||
|
||||
diff --git a/src/operations.cpp b/src/operations.cpp
|
||||
index abc7e4f6e..8f1130f00 100644
|
||||
--- a/libs/filesystem/src/operations.cpp
|
||||
+++ b/libs/filesystem/src/operations.cpp
|
||||
@@ -135,6 +135,8 @@ using std::time_t;
|
||||
# endif // BOOST_WINDOWS_API
|
||||
|
||||
#include "error_handling.hpp"
|
||||
+#include <atomic>
|
||||
+namespace atomic_ns = std;
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
using boost::filesystem::path;
|
||||
@@ -521,6 +522,9 @@ int copy_file_data_read_write(int infile, int outfile, uintmax_t size)
|
||||
if (BOOST_UNLIKELY(!buf.get()))
|
||||
return ENOMEM;
|
||||
|
||||
+ // Don't use file size to limit the amount of data to copy since some filesystems, like procfs or sysfs,
|
||||
+ // provide files with generated content and indicate that their size is zero or 4096. Just copy as much data
|
||||
+ // as we can read from the input file.
|
||||
while (true)
|
||||
{
|
||||
ssize_t sz_read = ::read(infile, buf.get(), buf_sz);
|
||||
@@ -555,7 +559,7 @@ int copy_file_data_read_write(int infile, int outfile, uintmax_t size)
|
||||
}
|
||||
|
||||
//! Pointer to the actual implementation of the copy_file_data implementation
|
||||
-copy_file_data_t* copy_file_data = ©_file_data_read_write;
|
||||
+atomic_ns::atomic< copy_file_data_t* > copy_file_data(©_file_data_read_write);
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_USE_SENDFILE)
|
||||
|
||||
@@ -577,6 +581,23 @@ int copy_file_data_sendfile(int infile, int outfile, uintmax_t size)
|
||||
int err = errno;
|
||||
if (err == EINTR)
|
||||
continue;
|
||||
+
|
||||
+ if (offset == 0u)
|
||||
+ {
|
||||
+ // sendfile may fail with EINVAL if the underlying filesystem does not support it
|
||||
+ if (err == EINVAL)
|
||||
+ {
|
||||
+ fallback_to_read_write:
|
||||
+ return copy_file_data_read_write(infile, outfile, size);
|
||||
+ }
|
||||
+
|
||||
+ if (err == ENOSYS)
|
||||
+ {
|
||||
+ copy_file_data.store(©_file_data_read_write, atomic_ns::memory_order_relaxed);
|
||||
+ goto fallback_to_read_write;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -611,6 +632,44 @@ int copy_file_data_copy_file_range(int infile, int outfile, uintmax_t size)
|
||||
int err = errno;
|
||||
if (err == EINTR)
|
||||
continue;
|
||||
+
|
||||
+ if (offset == 0u)
|
||||
+ {
|
||||
+ // copy_file_range may fail with EINVAL if the underlying filesystem does not support it.
|
||||
+ // In some RHEL/CentOS 7.7-7.8 kernel versions, copy_file_range on NFSv4 is also known to return EOPNOTSUPP
|
||||
+ // if the remote server does not support COPY, despite that it is not a documented error code.
|
||||
+ // See https://patchwork.kernel.org/project/linux-nfs/patch/20190411183418.4510-1-olga.kornievskaia@gmail.com/
|
||||
+ // and https://bugzilla.redhat.com/show_bug.cgi?id=1783554.
|
||||
+ if (err == EINVAL || err == EOPNOTSUPP)
|
||||
+ {
|
||||
+#if !defined(BOOST_FILESYSTEM_USE_SENDFILE)
|
||||
+ fallback_to_read_write:
|
||||
+#endif
|
||||
+ return copy_file_data_read_write(infile, outfile, size);
|
||||
+ }
|
||||
+
|
||||
+ if (err == EXDEV)
|
||||
+ {
|
||||
+#if defined(BOOST_FILESYSTEM_USE_SENDFILE)
|
||||
+ fallback_to_sendfile:
|
||||
+ return copy_file_data_sendfile(infile, outfile, size);
|
||||
+#else
|
||||
+ goto fallback_to_read_write;
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+ if (err == ENOSYS)
|
||||
+ {
|
||||
+#if defined(BOOST_FILESYSTEM_USE_SENDFILE)
|
||||
+ copy_file_data.store(©_file_data_sendfile, atomic_ns::memory_order_relaxed);
|
||||
+ goto fallback_to_sendfile;
|
||||
+#else
|
||||
+ copy_file_data.store(©_file_data_read_write, atomic_ns::memory_order_relaxed);
|
||||
+ goto fallback_to_read_write;
|
||||
+#endif
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -646,13 +705,14 @@ struct copy_file_data_initializer
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE)
|
||||
- // Although copy_file_range appeared in Linux 4.5, it did not support cross-filesystem copying until 5.3
|
||||
- if (major > 5u || (major == 5u && minor >= 3u))
|
||||
+ // Although copy_file_range appeared in Linux 4.5, it did not support cross-filesystem copying until 5.3.
|
||||
+ // copy_file_data_copy_file_range will fallback to copy_file_data_sendfile if copy_file_range returns EXDEV.
|
||||
+ if (major > 4u || (major == 4u && minor >= 5u))
|
||||
cfd = ©_file_data_copy_file_range;
|
||||
#endif
|
||||
|
||||
- copy_file_data = cfd;
|
||||
+ copy_file_data.store(cfd, atomic_ns::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
const copy_file_data_init;
|
||||
|
||||
@@ -1412,7 +1472,7 @@ bool copy_file(path const& from, path const& to, unsigned int options, error_cod
|
||||
goto fail_errno;
|
||||
}
|
||||
|
||||
- err = detail::copy_file_data(infile.fd, outfile.fd, get_size(from_stat));
|
||||
+ err = detail::copy_file_data.load(atomic_ns::memory_order_relaxed)(infile.fd, outfile.fd, get_size(from_stat));
|
||||
if (BOOST_UNLIKELY(err != 0))
|
||||
goto fail; // err already contains the error code
|
||||
|
|
@ -168,6 +168,10 @@ Patch105: boost-1.76.0-ptr_cont-xml.patch
|
|||
# https://bugzilla.redhat.com/show_bug.cgi?id=2106441
|
||||
Patch106: boost-1.76.0-asio-header.patch
|
||||
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2106878
|
||||
# https://github.com/boostorg/filesystem/issues/184
|
||||
Patch107: boost-1.76.0-filesystem-copy_file-exdev.patch
|
||||
|
||||
%bcond_with tests
|
||||
%bcond_with docs_generated
|
||||
|
||||
|
@ -694,6 +698,7 @@ find ./boost -name '*.hpp' -perm /111 | xargs chmod a-x
|
|||
%patch102 -p1
|
||||
%patch105 -p1
|
||||
%patch106 -p2
|
||||
%patch107 -p1
|
||||
|
||||
%build
|
||||
%set_build_flags
|
||||
|
@ -1311,6 +1316,7 @@ fi
|
|||
- Add patch to fix XML validation errors in ptr_container docs
|
||||
- Add BuildRequires: libzstd-devel (#2042336)
|
||||
- Add patch to fix Asio includes (#2106441)
|
||||
- Add patch to fix filesystem::copy_file EXDEV handling (#2106878)
|
||||
|
||||
* Thu Aug 05 2021 Thomas Rodgers <trodgers@redhat.com> - 1.76.0-4
|
||||
- Third attempt at making the long double c99 and tr1 math libs conditional
|
||||
|
|
Loading…
Reference in New Issue