mirror of
https://github.com/gcc-mirror/gcc.git
synced 2024-11-21 13:40:47 +00:00
libstdc++: Use copy_file_range for filesystem::copy_file
copy_file_range is a recent-ish syscall for copying files. It is similar to sendfile but allows filesystem-specific optimizations. Common are: Reflinks: BTRFS, XFS, ZFS (does not implement the syscall yet) Server-side copy: NFS, SMB, Ceph If copy_file_range is not available for the given files, fall back to sendfile / userspace copy. libstdc++-v3/ChangeLog: * acinclude.m4 (_GLIBCXX_USE_COPY_FILE_RANGE): Define. * config.h.in: Regenerate. * configure: Regenerate. * src/filesystem/ops-common.h (copy_file_copy_file_range): Define new function. (do_copy_file): Use it. Signed-off-by: Jannik Glückert <jannik.glueckert@gmail.com>
This commit is contained in:
parent
f80a8b4229
commit
d87caacf8e
@ -4954,6 +4954,7 @@ dnl _GLIBCXX_USE_UTIMENSAT
|
||||
dnl _GLIBCXX_USE_ST_MTIM
|
||||
dnl _GLIBCXX_USE_FCHMOD
|
||||
dnl _GLIBCXX_USE_FCHMODAT
|
||||
dnl _GLIBCXX_USE_COPY_FILE_RANGE
|
||||
dnl _GLIBCXX_USE_SENDFILE
|
||||
dnl HAVE_LINK
|
||||
dnl HAVE_LSEEK
|
||||
@ -5152,6 +5153,25 @@ dnl
|
||||
if test $glibcxx_cv_truncate = yes; then
|
||||
AC_DEFINE(HAVE_TRUNCATE, 1, [Define if truncate is available in <unistd.h>.])
|
||||
fi
|
||||
dnl
|
||||
AC_CACHE_CHECK([for copy_file_range that can copy files],
|
||||
glibcxx_cv_copy_file_range, [dnl
|
||||
case "${target_os}" in
|
||||
linux*)
|
||||
GCC_TRY_COMPILE_OR_LINK(
|
||||
[#include <unistd.h>],
|
||||
[copy_file_range(1, nullptr, 2, nullptr, 1, 0);],
|
||||
[glibcxx_cv_copy_file_range=yes],
|
||||
[glibcxx_cv_copy_file_range=no])
|
||||
;;
|
||||
*)
|
||||
glibcxx_cv_copy_file_range=no
|
||||
;;
|
||||
esac
|
||||
])
|
||||
if test $glibcxx_cv_copy_file_range = yes; then
|
||||
AC_DEFINE(_GLIBCXX_USE_COPY_FILE_RANGE, 1, [Define if copy_file_range is available in <unistd.h>.])
|
||||
fi
|
||||
dnl
|
||||
AC_CACHE_CHECK([for sendfile that can copy files],
|
||||
glibcxx_cv_sendfile, [dnl
|
||||
|
@ -971,6 +971,9 @@
|
||||
/* Defined if clock_gettime has realtime clock support. */
|
||||
#undef _GLIBCXX_USE_CLOCK_REALTIME
|
||||
|
||||
/* Define if copy_file_range is available in <unistd.h>. */
|
||||
#undef _GLIBCXX_USE_COPY_FILE_RANGE
|
||||
|
||||
/* Define if ISO/IEC TR 24733 decimal floating point types are supported on
|
||||
this host. */
|
||||
#undef _GLIBCXX_USE_DECIMAL_FLOAT
|
||||
|
62
libstdc++-v3/configure
vendored
62
libstdc++-v3/configure
vendored
@ -71279,6 +71279,68 @@ $as_echo "$glibcxx_cv_truncate" >&6; }
|
||||
|
||||
$as_echo "#define HAVE_TRUNCATE 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for copy_file_range that can copy files" >&5
|
||||
$as_echo_n "checking for copy_file_range that can copy files... " >&6; }
|
||||
if ${glibcxx_cv_copy_file_range+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
case "${target_os}" in
|
||||
linux*)
|
||||
if test x$gcc_no_link = xyes; then
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <unistd.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
copy_file_range(1, nullptr, 2, nullptr, 1, 0);
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_compile "$LINENO"; then :
|
||||
glibcxx_cv_copy_file_range=yes
|
||||
else
|
||||
glibcxx_cv_copy_file_range=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
else
|
||||
if test x$gcc_no_link = xyes; then
|
||||
as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5
|
||||
fi
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <unistd.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
copy_file_range(1, nullptr, 2, nullptr, 1, 0);
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_link "$LINENO"; then :
|
||||
glibcxx_cv_copy_file_range=yes
|
||||
else
|
||||
glibcxx_cv_copy_file_range=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
glibcxx_cv_copy_file_range=no
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_copy_file_range" >&5
|
||||
$as_echo "$glibcxx_cv_copy_file_range" >&6; }
|
||||
if test $glibcxx_cv_copy_file_range = yes; then
|
||||
|
||||
$as_echo "#define _GLIBCXX_USE_COPY_FILE_RANGE 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sendfile that can copy files" >&5
|
||||
$as_echo_n "checking for sendfile that can copy files... " >&6; }
|
||||
|
@ -49,6 +49,9 @@
|
||||
#ifdef NEED_DO_COPY_FILE
|
||||
# include <filesystem>
|
||||
# include <ext/stdio_filebuf.h>
|
||||
# ifdef _GLIBCXX_USE_COPY_FILE_RANGE
|
||||
# include <unistd.h> // copy_file_range
|
||||
# endif
|
||||
# ifdef _GLIBCXX_USE_SENDFILE
|
||||
# include <sys/sendfile.h> // sendfile
|
||||
# include <unistd.h> // lseek
|
||||
@ -359,6 +362,32 @@ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
|
||||
}
|
||||
|
||||
#ifdef NEED_DO_COPY_FILE
|
||||
#ifdef _GLIBCXX_USE_COPY_FILE_RANGE
|
||||
bool
|
||||
copy_file_copy_file_range(int fd_in, int fd_out, size_t length) noexcept
|
||||
{
|
||||
// a zero-length file is either empty, or not copyable by this syscall
|
||||
// return early to avoid the syscall cost
|
||||
if (length == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
size_t bytes_left = length;
|
||||
off64_t off_in = 0, off_out = 0;
|
||||
ssize_t bytes_copied;
|
||||
do
|
||||
{
|
||||
bytes_copied = ::copy_file_range(fd_in, &off_in, fd_out, &off_out,
|
||||
bytes_left, 0);
|
||||
bytes_left -= bytes_copied;
|
||||
}
|
||||
while (bytes_left > 0 && bytes_copied > 0);
|
||||
if (bytes_copied < 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if defined _GLIBCXX_USE_SENDFILE && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
|
||||
bool
|
||||
copy_file_sendfile(int fd_in, int fd_out, size_t length) noexcept
|
||||
@ -529,6 +558,33 @@ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
|
||||
|
||||
bool has_copied = false;
|
||||
|
||||
#ifdef _GLIBCXX_USE_COPY_FILE_RANGE
|
||||
if (!has_copied)
|
||||
has_copied = copy_file_copy_file_range(in.fd, out.fd, from_st->st_size);
|
||||
if (!has_copied)
|
||||
{
|
||||
// EINVAL: src and dst are the same file (this is not cheaply
|
||||
// detectable from userspace)
|
||||
// EINVAL: copy_file_range is unsupported for this file type by the
|
||||
// underlying filesystem
|
||||
// ENOTSUP: undocumented, can arise with old kernels and NFS
|
||||
// EOPNOTSUPP: filesystem does not implement copy_file_range
|
||||
// ETXTBSY: src or dst is an active swapfile (nonsensical, but allowed
|
||||
// with normal copying)
|
||||
// EXDEV: src and dst are on different filesystems that do not support
|
||||
// cross-fs copy_file_range
|
||||
// ENOENT: undocumented, can arise with CIFS
|
||||
// ENOSYS: unsupported by kernel or blocked by seccomp
|
||||
if (errno != EINVAL && errno != ENOTSUP && errno != EOPNOTSUPP
|
||||
&& errno != ETXTBSY && errno != EXDEV && errno != ENOENT
|
||||
&& errno != ENOSYS)
|
||||
{
|
||||
ec.assign(errno, std::generic_category());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined _GLIBCXX_USE_SENDFILE && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
|
||||
if (!has_copied)
|
||||
has_copied = copy_file_sendfile(in.fd, out.fd, from_st->st_size);
|
||||
|
Loading…
Reference in New Issue
Block a user