diff options
| -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); | 
