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 | |
| 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).
| -rw-r--r-- | TODO | 2 | ||||
| -rw-r--r-- | src/basic/copy.c | 40 | 
2 files changed, 38 insertions, 4 deletions
| @@ -49,8 +49,6 @@ Features:  * cache sd_event_now() result from before the first iteration... -* support for the new copy_file_range() syscall -  * add systemctl stop --job-mode=triggering that follows TRIGGERED_BY deps and adds them to the same transaction  * Maybe add a way how users can "pin" units into memory, so that they are not subject to automatic GC? 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); | 
