Skip to content

Commit

Permalink
Use fancy and more efficient syscalls to copy (sparse) files on Linux
Browse files Browse the repository at this point in the history
The FICLONE ioctl() is the most efficient way to copy a file
inside one file system if available and supported.
copy_file_range() is an alternative that can provide similar
efficiency, but also only works inside one file system and
requires us to take care of holes in files. sendfile() is very
similar, but unline copy_file_range() it doesn't support
reflinks.

Ticket: CFE-4380
Changelog: FileSparseCopy() now uses FICLONE ioctl(),
           copy_file_range() or sendfile() on Linux
           platforms (if available)
  • Loading branch information
vpodzime committed May 6, 2024
1 parent d26863d commit b23d9f4
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 3 deletions.
8 changes: 8 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,14 @@ dnl Fancy new Linux syscalls for file/data copying
dnl ######################################################################
AC_CHECK_HEADERS([linux/fs.h])
AC_CHECK_DECLS([FICLONE], [], [], [#include <linux/fs.h>])
AC_CHECK_DECLS([SEEK_DATA], [], [], [
#define _GNU_SOURCE
#include <unistd.h>
])
AC_CHECK_DECLS([FALLOC_FL_PUNCH_HOLE], [], [], [
#define _GNU_SOURCE
#include <fcntl.h>
])
AC_CHECK_HEADERS([sys/sendfile.h])
AC_CHECK_FUNCS([sendfile])
AC_CHECK_FUNCS([copy_file_range])
Expand Down
21 changes: 18 additions & 3 deletions libutils/file_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1529,9 +1529,11 @@ bool FileSparseWrite(int fd, const void *buf, size_t count,
*/
#ifdef __linux__
#if HAVE_SENDFILE || HAVE_COPY_FILE_RANGE
#if HAVE_DECL_SEEK_DATA && HAVE_DECL_FALLOC_FL_PUNCH_HOLE
#define SMART_FILE_COPY_SYSCALLS_AVAILABLE 1
#define SMART_SYSCALLS_UNUSED ARG_UNUSED
#endif
#endif /* HAVE_DECL_SEEK_DATA && HAVE_DECL_FALLOC_FL_PUNCH_HOLE */
#endif /* HAVE_SENDFILE || HAVE_COPY_FILE_RANGE */
#endif /* __linux__ */
#ifndef SMART_FILE_COPY_SYSCALLS_AVAILABLE
#define SMART_FILE_COPY_SYSCALLS_AVAILABLE 0
Expand Down Expand Up @@ -1782,9 +1784,20 @@ bool FileSparseCopy(int sd, const char *src_name,
bool FileSparseClose(int fd, const
char *filename,
bool do_sync,
size_t total_bytes_written,
bool last_write_was_hole)
SMART_SYSCALLS_UNUSED size_t total_bytes_written,
SMART_SYSCALLS_UNUSED bool last_write_was_hole)
{
#if SMART_FILE_COPY_SYSCALLS_AVAILABLE
/* Not much to do here with smart syscalls (see above). */
bool success = true;
if (do_sync && (fsync(fd) != 0))
{
Log(LOG_LEVEL_WARNING, "Could not sync to disk file '%s': %m)", filename);
success = false;
}
close(fd);
return success;
#else
if (last_write_was_hole)
{
ssize_t ret1 = FullWrite(fd, "", 1);
Expand Down Expand Up @@ -1828,7 +1841,9 @@ bool FileSparseClose(int fd, const
}

return true;
#endif /* SMART_FILE_COPY_SYSCALLS_AVAILABLE */
}
#undef SMART_FILE_COPY_SYSCALLS_AVAILABLE

ssize_t CfReadLine(char **buff, size_t *size, FILE *fp)
{
Expand Down

0 comments on commit b23d9f4

Please sign in to comment.