]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
basic/copy: use copy_file_range()
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 15 Mar 2016 23:26:34 +0000 (19:26 -0400)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 17 Mar 2016 17:02:18 +0000 (13:02 -0400)
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).

TODO
src/basic/copy.c

diff --git a/TODO b/TODO
index 08b74083d35d60ea0a06f5e3e7df15f9d4f02a73..b2840ba4ab395959d09992add6906b348050ea00 100644 (file)
--- a/TODO
+++ b/TODO
@@ -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?
index dbbb1d0fd25ea793213c6d8fd1bc20c93f578e97..41dc8ca79a60314362fb9ebc0c6d19ead654f991 100644 (file)
@@ -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"
 
 #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);