path: root/bin
diff options
authorRick Macklem <rmacklem@FreeBSD.org>2021-01-03 00:58:43 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2021-01-03 00:58:43 +0000
commitc98a764c681f8b70812a9f13a6e61c96aa1a69d2 (patch)
treea01afea7c27ed16865d1147e1db08f41b8ba6232 /bin
parent9c43bd646e27241dca95958a84ea4d6948d2531d (diff)
cp(1): fix performance issue for large non-sparse file copies
PR252358 reported a serious performance problem when copying a large non-sparse file on a UFS file system. This problem seems to have been caused by a large number of SEEK_HOLE operations, with one done for each copy_file_range(2) call. This patch modifies cp(1) to use a large (SSIZE_MAX) len argument, reducing the number of system calls and resolving the performance issue. While here, convert the type of the "rcount" from "int" to "ssize_t" so that it is consistent with that returned by both read(2) and copy_file_range(2). PR: 252358 Reviewed by: asomers Differential Revision: https://reviews.freebsd.org/D27937
Diffstat (limited to 'bin')
1 files changed, 5 insertions, 6 deletions
diff --git a/bin/cp/utils.c b/bin/cp/utils.c
index 1a3b5502145a..7742b0d0a516 100644
--- a/bin/cp/utils.c
+++ b/bin/cp/utils.c
@@ -74,11 +74,10 @@ __FBSDID("$FreeBSD$");
-static int
+static ssize_t
copy_fallback(int from_fd, int to_fd, char *buf, size_t bufsize)
- int rcount;
- ssize_t wresid, wcount = 0;
+ ssize_t rcount, wresid, wcount = 0;
char *bufp;
rcount = read(from_fd, buf, bufsize);
@@ -100,10 +99,10 @@ copy_file(const FTSENT *entp, int dne)
static char *buf = NULL;
static size_t bufsize;
struct stat *fs;
- ssize_t wcount;
+ ssize_t rcount, wcount;
size_t wresid;
off_t wtotal;
- int ch, checkch, from_fd, rcount, rval, to_fd;
+ int ch, checkch, from_fd, rval, to_fd;
char *bufp;
char *p;
@@ -236,7 +235,7 @@ copy_file(const FTSENT *entp, int dne)
do {
if (use_copy_file_range) {
rcount = copy_file_range(from_fd, NULL,
- to_fd, NULL, bufsize, 0);
+ to_fd, NULL, SSIZE_MAX, 0);
if (rcount < 0 && errno == EINVAL) {
/* Prob a non-seekable FD */
use_copy_file_range = 0;