QFileSystemEngine/Unix: use copy_file_range(2) in cloneFile()
For remote filesystems on Linux, this can invoke a server-side copy to avoid network traffic. For local filesystems, Linux can use an optimized FS-specific call (which may be the same operation as the FICLONE, but I'm not sure) or splice the data on its own. Tested with: - FreeBSD ufs - FreeBSD ufs-to-tmpfs - FreeBSD tmpfs (tested ENOSPC with it) - Linux btrfs - Linux ext4 - Linux tmpfs (tested ENOSPC with it) Change-Id: I3ae11d555882bdbb0487fffd81cb5568171cee3f Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
This commit is contained in:
parent
fe75526542
commit
9b006eb91a
@ -143,6 +143,19 @@ int pipes[2];
|
|||||||
}
|
}
|
||||||
")
|
")
|
||||||
|
|
||||||
|
# copy_file_range
|
||||||
|
qt_config_compile_test(copy_file_range
|
||||||
|
LABEL "copy_file_range()"
|
||||||
|
CODE
|
||||||
|
"#include <unistd.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
off_t off_in = 0, off_out = 1024;
|
||||||
|
return copy_file_range(0, &off_in, 1, &off_out, 2147483647, 0) != 0;
|
||||||
|
}
|
||||||
|
")
|
||||||
|
|
||||||
# Check if __cxa_thread_atexit{,_impl} are present in the C library (hence why
|
# Check if __cxa_thread_atexit{,_impl} are present in the C library (hence why
|
||||||
# PROJECT_PATH instead of CODE for C++). Either one suffices to disable
|
# PROJECT_PATH instead of CODE for C++). Either one suffices to disable
|
||||||
# FEATURE_broken_threadlocal_dtors. See details in qthread_unix.cpp.
|
# FEATURE_broken_threadlocal_dtors. See details in qthread_unix.cpp.
|
||||||
@ -615,6 +628,11 @@ qt_feature("close_range" PRIVATE
|
|||||||
CONDITION QT_FEATURE_process AND TEST_close_range
|
CONDITION QT_FEATURE_process AND TEST_close_range
|
||||||
AUTODETECT UNIX
|
AUTODETECT UNIX
|
||||||
)
|
)
|
||||||
|
qt_feature("copy_file_range" PRIVATE
|
||||||
|
LABEL "copy_file_range()"
|
||||||
|
CONDITION QT_FEATURE_process AND TEST_copy_file_range
|
||||||
|
AUTODETECT UNIX AND NOT DARWIN
|
||||||
|
)
|
||||||
qt_feature("doubleconversion" PRIVATE
|
qt_feature("doubleconversion" PRIVATE
|
||||||
LABEL "DoubleConversion"
|
LABEL "DoubleConversion"
|
||||||
)
|
)
|
||||||
|
@ -41,6 +41,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
* - accept4 2.6.28
|
* - accept4 2.6.28
|
||||||
* - renameat2 3.16 QT_CONFIG(renameat2)
|
* - renameat2 3.16 QT_CONFIG(renameat2)
|
||||||
* - getrandom 3.17 QT_CONFIG(getentropy)
|
* - getrandom 3.17 QT_CONFIG(getentropy)
|
||||||
|
* - copy_file_range 4.5 QT_CONFIG(copy_file_range)
|
||||||
* - statx 4.11 STATX_BASIC_STATS
|
* - statx 4.11 STATX_BASIC_STATS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -50,6 +51,10 @@ QT_BEGIN_NAMESPACE
|
|||||||
# define QT_ELF_NOTE_OS_MAJOR 4
|
# define QT_ELF_NOTE_OS_MAJOR 4
|
||||||
# define QT_ELF_NOTE_OS_MINOR 11
|
# define QT_ELF_NOTE_OS_MINOR 11
|
||||||
# define QT_ELF_NOTE_OS_PATCH 0
|
# define QT_ELF_NOTE_OS_PATCH 0
|
||||||
|
#elif QT_CONFIG(copy_file_range)
|
||||||
|
# define QT_ELF_NOTE_OS_MAJOR 4
|
||||||
|
# define QT_ELF_NOTE_OS_MINOR 5
|
||||||
|
# define QT_ELF_NOTE_OS_PATCH 0
|
||||||
#elif QT_CONFIG(getentropy)
|
#elif QT_CONFIG(getentropy)
|
||||||
# define QT_ELF_NOTE_OS_MAJOR 3
|
# define QT_ELF_NOTE_OS_MAJOR 3
|
||||||
# define QT_ELF_NOTE_OS_MINOR 17
|
# define QT_ELF_NOTE_OS_MINOR 17
|
||||||
@ -59,7 +64,6 @@ QT_BEGIN_NAMESPACE
|
|||||||
# define QT_ELF_NOTE_OS_MINOR 16
|
# define QT_ELF_NOTE_OS_MINOR 16
|
||||||
# define QT_ELF_NOTE_OS_PATCH 0
|
# define QT_ELF_NOTE_OS_PATCH 0
|
||||||
#else
|
#else
|
||||||
|
|
||||||
# define QT_ELF_NOTE_OS_MAJOR 2
|
# define QT_ELF_NOTE_OS_MAJOR 2
|
||||||
# define QT_ELF_NOTE_OS_MINOR 6
|
# define QT_ELF_NOTE_OS_MINOR 6
|
||||||
# define QT_ELF_NOTE_OS_PATCH 28
|
# define QT_ELF_NOTE_OS_PATCH 28
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#define QT_FEATURE_cborstreamwriter 1
|
#define QT_FEATURE_cborstreamwriter 1
|
||||||
#define QT_FEATURE_commandlineparser 1
|
#define QT_FEATURE_commandlineparser 1
|
||||||
#define QT_NO_COMPRESS
|
#define QT_NO_COMPRESS
|
||||||
|
#define QT_FEATURE_copy_file_range -1
|
||||||
#define QT_FEATURE_cxx17_filesystem -1
|
#define QT_FEATURE_cxx17_filesystem -1
|
||||||
#define QT_NO_DATASTREAM
|
#define QT_NO_DATASTREAM
|
||||||
#define QT_FEATURE_datestring 1
|
#define QT_FEATURE_datestring 1
|
||||||
|
@ -1096,8 +1096,41 @@ auto QFileSystemEngine::cloneFile(int srcfd, int dstfd, const QFileSystemMetaDat
|
|||||||
// first, try FICLONE (only works on regular files and only on certain fs)
|
// first, try FICLONE (only works on regular files and only on certain fs)
|
||||||
if (::ioctl(dstfd, FICLONE, srcfd) == 0)
|
if (::ioctl(dstfd, FICLONE, srcfd) == 0)
|
||||||
return TriStateResult::Success;
|
return TriStateResult::Success;
|
||||||
|
#elif defined(Q_OS_DARWIN)
|
||||||
|
// try fcopyfile
|
||||||
|
if (fcopyfile(srcfd, dstfd, nullptr, COPYFILE_DATA | COPYFILE_STAT) == 0)
|
||||||
|
return TriStateResult::Success;
|
||||||
|
switch (errno) {
|
||||||
|
case ENOTSUP:
|
||||||
|
case ENOMEM:
|
||||||
|
return TriStateResult::NotSupported; // let QFile try
|
||||||
|
}
|
||||||
|
return TriStateResult::Failed;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Second, try sendfile (it can send to some special types too).
|
#if QT_CONFIG(copy_file_range)
|
||||||
|
// Second, try copy_file_range. Tested on Linux & FreeBSD: FreeBSD can copy
|
||||||
|
// across mountpoints, Linux currently (6.12) can only if the source and
|
||||||
|
// destination mountpoints are the same filesystem type.
|
||||||
|
QT_OFF_T srcoffset = 0;
|
||||||
|
QT_OFF_T dstoffset = 0;
|
||||||
|
ssize_t copied;
|
||||||
|
do {
|
||||||
|
copied = ::copy_file_range(srcfd, &srcoffset, dstfd, &dstoffset, SSIZE_MAX, 0);
|
||||||
|
} while (copied > 0 || (copied < 0 && errno == EINTR));
|
||||||
|
if (copied == 0)
|
||||||
|
return TriStateResult::Success; // EOF -> success
|
||||||
|
if (srcoffset) {
|
||||||
|
// some bytes were copied, so this is a real error (like ENOSPC).
|
||||||
|
copied = ftruncate(dstfd, 0);
|
||||||
|
return TriStateResult::Failed;
|
||||||
|
}
|
||||||
|
if (errno != EXDEV)
|
||||||
|
return TriStateResult::Failed;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(Q_OS_LINUX)
|
||||||
|
// For Linux, try sendfile (it can send to some special types too).
|
||||||
// sendfile(2) is limited in the kernel to 2G - 4k
|
// sendfile(2) is limited in the kernel to 2G - 4k
|
||||||
const size_t SendfileSize = 0x7ffff000;
|
const size_t SendfileSize = 0x7ffff000;
|
||||||
|
|
||||||
@ -1125,16 +1158,6 @@ auto QFileSystemEngine::cloneFile(int srcfd, int dstfd, const QFileSystemMetaDat
|
|||||||
}
|
}
|
||||||
|
|
||||||
return TriStateResult::Success;
|
return TriStateResult::Success;
|
||||||
#elif defined(Q_OS_DARWIN)
|
|
||||||
// try fcopyfile
|
|
||||||
if (fcopyfile(srcfd, dstfd, nullptr, COPYFILE_DATA | COPYFILE_STAT) == 0)
|
|
||||||
return TriStateResult::Success;
|
|
||||||
switch (errno) {
|
|
||||||
case ENOTSUP:
|
|
||||||
case ENOMEM:
|
|
||||||
return TriStateResult::NotSupported; // let QFile try
|
|
||||||
}
|
|
||||||
return TriStateResult::Failed;
|
|
||||||
#else
|
#else
|
||||||
Q_UNUSED(dstfd);
|
Q_UNUSED(dstfd);
|
||||||
return TriStateResult::NotSupported;
|
return TriStateResult::NotSupported;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user