aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2019-06-06 21:18:11 -0700
committerPaul Eggert2019-06-07 00:44:45 -0700
commit486a81f387bb59b2fbbc6aff7b41adbe1621394e (patch)
tree7b61ed0a44666f10e4da54ef3e0905974c861944
parent111408a0e9eb3a9492c4057ac7d6ddbb8b365aa9 (diff)
downloademacs-486a81f387bb59b2fbbc6aff7b41adbe1621394e.tar.gz
emacs-486a81f387bb59b2fbbc6aff7b41adbe1621394e.zip
Use copy_file_range to copy files
The copy_file_range syscall (introduced in Linux kernel version 4.5) can copy files more efficiently via server-side copy etc. * admin/merge-gnulib (GNULIB_MODULES): Add copy-file-range. * lib/copy-file-range.c, m4/copy-file-range.m4: New files, copied from Gnulib. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate. * src/fileio.c (Fcopy_file): Try copy_file_range first, falling back on read+write only if copy_file_range failed or if the input is empty and so could be a /proc file.
-rwxr-xr-xadmin/merge-gnulib2
-rw-r--r--lib/copy-file-range.c33
-rw-r--r--lib/gnulib.mk.in12
-rw-r--r--m4/copy-file-range.m436
-rw-r--r--m4/gnulib-comp.m48
-rw-r--r--src/fileio.c41
6 files changed, 123 insertions, 9 deletions
diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index 4a69310d83c..c2d9291b843 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -27,7 +27,7 @@ GNULIB_URL=git://git.savannah.gnu.org/gnulib.git
27 27
28GNULIB_MODULES=' 28GNULIB_MODULES='
29 alloca-opt binary-io byteswap c-ctype c-strcase 29 alloca-opt binary-io byteswap c-ctype c-strcase
30 careadlinkat close-stream 30 careadlinkat close-stream copy-file-range
31 count-leading-zeros count-one-bits count-trailing-zeros 31 count-leading-zeros count-one-bits count-trailing-zeros
32 crypto/md5-buffer crypto/sha1-buffer crypto/sha256-buffer crypto/sha512-buffer 32 crypto/md5-buffer crypto/sha1-buffer crypto/sha256-buffer crypto/sha512-buffer
33 d-type diffseq dosname dtoastr dtotimespec dup2 33 d-type diffseq dosname dtoastr dtotimespec dup2
diff --git a/lib/copy-file-range.c b/lib/copy-file-range.c
new file mode 100644
index 00000000000..39b5efbc1cc
--- /dev/null
+++ b/lib/copy-file-range.c
@@ -0,0 +1,33 @@
1/* Stub for copy_file_range
2 Copyright 2019 Free Software Foundation, Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#include <unistd.h>
20
21#include <errno.h>
22
23ssize_t
24copy_file_range (int infd, off_t *pinoff,
25 int outfd, off_t *poutoff,
26 size_t length, unsigned int flags)
27{
28 /* There is little need to emulate copy_file_range with read+write,
29 since programs that use copy_file_range must fall back on
30 read+write anyway. */
31 errno = ENOSYS;
32 return -1;
33}
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 403d83829cd..6e817fa6897 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -74,6 +74,7 @@
74# c-strcase \ 74# c-strcase \
75# careadlinkat \ 75# careadlinkat \
76# close-stream \ 76# close-stream \
77# copy-file-range \
77# count-leading-zeros \ 78# count-leading-zeros \
78# count-one-bits \ 79# count-one-bits \
79# count-trailing-zeros \ 80# count-trailing-zeros \
@@ -1274,6 +1275,17 @@ EXTRA_DIST += close-stream.h
1274endif 1275endif
1275## end gnulib module close-stream 1276## end gnulib module close-stream
1276 1277
1278## begin gnulib module copy-file-range
1279ifeq (,$(OMIT_GNULIB_MODULE_copy-file-range))
1280
1281
1282EXTRA_DIST += copy-file-range.c
1283
1284EXTRA_libgnu_a_SOURCES += copy-file-range.c
1285
1286endif
1287## end gnulib module copy-file-range
1288
1277## begin gnulib module count-leading-zeros 1289## begin gnulib module count-leading-zeros
1278ifeq (,$(OMIT_GNULIB_MODULE_count-leading-zeros)) 1290ifeq (,$(OMIT_GNULIB_MODULE_count-leading-zeros))
1279 1291
diff --git a/m4/copy-file-range.m4 b/m4/copy-file-range.m4
new file mode 100644
index 00000000000..20fd05697fe
--- /dev/null
+++ b/m4/copy-file-range.m4
@@ -0,0 +1,36 @@
1# copy-file-range.m4
2dnl Copyright 2019 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved.
6
7AC_DEFUN([gl_FUNC_COPY_FILE_RANGE],
8[
9 AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
10
11 dnl Persuade glibc <unistd.h> to declare copy_file_range.
12 AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
13
14 dnl Use AC_LINK_IFELSE, rather than AC_CHECK_FUNCS or a variant,
15 dnl since we don't want AC_CHECK_FUNCS's checks for glibc stubs.
16 dnl Programs that use copy_file_range must fall back on read+write
17 dnl anyway, and there's little point to substituting the Gnulib stub
18 dnl for a glibc stub.
19 AC_CACHE_CHECK([for copy_file_range], [gl_cv_func_copy_file_range],
20 [AC_LINK_IFELSE(
21 [AC_LANG_PROGRAM(
22 [[#include <unistd.h>
23 ]],
24 [[ssize_t (*func) (int, off_t *, int, off_t, size_t, unsigned)
25 = copy_file_range;
26 return func (0, 0, 0, 0, 0, 0) & 127;
27 ]])
28 ],
29 [gl_cv_func_copy_file_range=yes],
30 [gl_cv_func_copy_file_range=no])
31 ])
32
33 if test "$gl_cv_func_copy_file_range" != yes; then
34 HAVE_COPY_FILE_RANGE=0
35 fi
36])
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index 0a7a30e5ae2..4627575bf63 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -56,6 +56,7 @@ AC_DEFUN([gl_EARLY],
56 # Code from module clock-time: 56 # Code from module clock-time:
57 # Code from module cloexec: 57 # Code from module cloexec:
58 # Code from module close-stream: 58 # Code from module close-stream:
59 # Code from module copy-file-range:
59 # Code from module count-leading-zeros: 60 # Code from module count-leading-zeros:
60 # Code from module count-one-bits: 61 # Code from module count-one-bits:
61 # Code from module count-trailing-zeros: 62 # Code from module count-trailing-zeros:
@@ -201,6 +202,11 @@ AC_DEFUN([gl_INIT],
201 AC_CHECK_FUNCS_ONCE([readlinkat]) 202 AC_CHECK_FUNCS_ONCE([readlinkat])
202 gl_CLOCK_TIME 203 gl_CLOCK_TIME
203 gl_MODULE_INDICATOR([close-stream]) 204 gl_MODULE_INDICATOR([close-stream])
205 gl_FUNC_COPY_FILE_RANGE
206 if test $HAVE_COPY_FILE_RANGE = 0; then
207 AC_LIBOBJ([copy-file-range])
208 fi
209 gl_UNISTD_MODULE_INDICATOR([copy-file-range])
204 gl_COUNT_LEADING_ZEROS 210 gl_COUNT_LEADING_ZEROS
205 gl_COUNT_ONE_BITS 211 gl_COUNT_ONE_BITS
206 gl_COUNT_TRAILING_ZEROS 212 gl_COUNT_TRAILING_ZEROS
@@ -846,6 +852,7 @@ AC_DEFUN([gl_FILE_LIST], [
846 lib/cloexec.h 852 lib/cloexec.h
847 lib/close-stream.c 853 lib/close-stream.c
848 lib/close-stream.h 854 lib/close-stream.h
855 lib/copy-file-range.c
849 lib/count-leading-zeros.c 856 lib/count-leading-zeros.c
850 lib/count-leading-zeros.h 857 lib/count-leading-zeros.h
851 lib/count-one-bits.c 858 lib/count-one-bits.c
@@ -995,6 +1002,7 @@ AC_DEFUN([gl_FILE_LIST], [
995 m4/builtin-expect.m4 1002 m4/builtin-expect.m4
996 m4/byteswap.m4 1003 m4/byteswap.m4
997 m4/clock_time.m4 1004 m4/clock_time.m4
1005 m4/copy-file-range.m4
998 m4/count-leading-zeros.m4 1006 m4/count-leading-zeros.m4
999 m4/count-one-bits.m4 1007 m4/count-one-bits.m4
1000 m4/count-trailing-zeros.m4 1008 m4/count-trailing-zeros.m4
diff --git a/src/fileio.c b/src/fileio.c
index 9e9779967dd..f7376ce74fe 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2117,14 +2117,39 @@ permissions. */)
2117 newsize = st.st_size; 2117 newsize = st.st_size;
2118 else 2118 else
2119 { 2119 {
2120 char buf[MAX_ALLOCA]; 2120 off_t insize = st.st_size;
2121 ptrdiff_t n; 2121 ssize_t copied;
2122 for (newsize = 0; 0 < (n = emacs_read_quit (ifd, buf, sizeof buf)); 2122
2123 newsize += n) 2123 for (newsize = 0; newsize < insize; newsize += copied)
2124 if (emacs_write_quit (ofd, buf, n) != n) 2124 {
2125 report_file_error ("Write error", newname); 2125 /* Copy at most COPY_MAX bytes at a time; this is min
2126 if (n < 0) 2126 (PTRDIFF_MAX, SIZE_MAX) truncated to a value that is
2127 report_file_error ("Read error", file); 2127 surely aligned well. */
2128 ptrdiff_t copy_max = min (PTRDIFF_MAX, SIZE_MAX) >> 30 << 30;
2129 off_t intail = insize - newsize;
2130 ptrdiff_t len = min (intail, copy_max);
2131 copied = copy_file_range (ifd, NULL, ofd, NULL, len, 0);
2132 if (copied <= 0)
2133 break;
2134 maybe_quit ();
2135 }
2136
2137 /* Fall back on read+write if copy_file_range failed, or if the
2138 input is empty and so could be a /proc file. read+write will
2139 either succeed, or report an error more precisely than
2140 copy_file_range would. */
2141 if (newsize != insize || insize == 0)
2142 {
2143 char buf[MAX_ALLOCA];
2144 for (; (copied = emacs_read_quit (ifd, buf, sizeof buf));
2145 newsize += copied)
2146 {
2147 if (copied < 0)
2148 report_file_error ("Read error", file);
2149 if (emacs_write_quit (ofd, buf, copied) != copied)
2150 report_file_error ("Write error", newname);
2151 }
2152 }
2128 } 2153 }
2129 2154
2130 /* Truncate any existing output file after writing the data. This 2155 /* Truncate any existing output file after writing the data. This