diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2016-03-15 19:26:34 -0400 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2016-03-17 13:02:18 -0400 |
commit | a44202e98b638024c45e50ad404c7069c7835c04 (patch) | |
tree | 1b82ca988d199923f37315d2f935626abdb2a8a3 /src/basic | |
parent | 1d4b557d1b5cd200b27562808c690653658ffadf (diff) |
basic/copy: use copy_file_range()
For btrfs, c_f_r() is like BTRFS_IOC_CLONE which we already used, but also
works when max_bytes is set. We do call copy_bytes in coredump code with
max_bytes set, and for large files, so we might see some benefit from using
c_f_r() on btrfs.
For other filesystems, c_f_r() falls back to do_splice_direct(), the same as
sendfile, which we already call, so there shouldn't be much difference.
Tested with test-copy and systemd-coredump on Linux 4.3 (w/o c_f_r)
and 4.5 (w/ c_f_r).
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/copy.c | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/src/basic/copy.c b/src/basic/copy.c index dbbb1d0fd2..41dc8ca79a 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -40,6 +40,7 @@ #include "fs-util.h" #include "io-util.h" #include "macro.h" +#include "missing.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -48,10 +49,29 @@ #define COPY_BUFFER_SIZE (16*1024u) +static ssize_t try_copy_file_range(int fd_in, loff_t *off_in, + int fd_out, loff_t *off_out, + size_t len, + unsigned int flags) { + static int have = -1; + ssize_t r; + + if (have == false) + return -ENOSYS; + + r = copy_file_range(fd_in, off_in, fd_out, off_out, len, flags); + if (_unlikely_(have < 0)) + have = r >= 0 || errno != ENOSYS; + if (r >= 0) + return r; + else + return -errno; +} + int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { - bool try_sendfile = true, try_splice = true; + bool try_cfr = true, try_sendfile = true, try_splice = true; int r; - size_t m = SSIZE_MAX; /* that the maximum that sendfile accepts */ + size_t m = SSIZE_MAX; /* that the maximum that sendfile and c_f_r accept */ assert(fdf >= 0); assert(fdt >= 0); @@ -78,6 +98,22 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { m = (size_t) max_bytes; } + /* First try copy_file_range(), unless we already tried */ + if (try_cfr) { + n = try_copy_file_range(fdf, NULL, fdt, NULL, m, 0u); + if (n < 0) { + if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV)) + return n; + + try_cfr = false; + /* use fallback below */ + } else if (n == 0) /* EOF */ + break; + else + /* Success! */ + goto next; + } + /* First try sendfile(), unless we already tried */ if (try_sendfile) { n = sendfile(fdt, fdf, NULL, m); |