From: Paul Eggert Date: Wed, 6 Aug 2025 18:48:21 +0000 (-0700) Subject: cp: don’t allocate a separate zero buffer X-Git-Tag: v9.8~45 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=12d03a04446a8da4f5dc3cacd6888416687dd8a2;p=thirdparty%2Fcoreutils.git cp: don’t allocate a separate zero buffer * src/copy-file-data.c (write_zeros): New args abuf, buf_size. Use the lazily-allocated buffer, which most likely already exists, rather than allocating a separate buffer just for zeros. This makes the code more reentrant as there is no longer a need for static storage here. Although there is some CPU overhead due to the need to zero out the buffer for each file, the overhead is relatively small as the buffer is smallish and should be cached. All callers changed. --- diff --git a/src/copy-file-data.c b/src/copy-file-data.c index fb0b1dc409..513699e96e 100644 --- a/src/copy-file-data.c +++ b/src/copy-file-data.c @@ -271,29 +271,19 @@ sparse_copy (int src_fd, int dest_fd, char **abuf, size_t buf_size, /* Write N_BYTES zero bytes to file descriptor FD. Return true if successful. Upon write failure, set errno and return false. */ static bool -write_zeros (int fd, off_t n_bytes) +write_zeros (int fd, off_t n_bytes, char **abuf, idx_t buf_size) { - static char *zeros; - static size_t nz = IO_BUFSIZE; - - /* Attempt to use a relatively large calloc'd source buffer for - efficiency, but if that allocation fails, resort to a smaller - statically allocated one. */ - if (zeros == nullptr) + char *zeros = nullptr; + while (n_bytes) { - static char fallback[1024]; - zeros = calloc (nz, 1); - if (zeros == nullptr) + idx_t n = MIN (buf_size, n_bytes); + if (!zeros) { - zeros = fallback; - nz = sizeof fallback; + if (!*abuf) + *abuf = xalignalloc (getpagesize (), buf_size); + zeros = memset (*abuf, 0, n); } - } - - while (n_bytes) - { - size_t n = MIN (nz, n_bytes); - if ((full_write (fd, zeros, n)) != n) + if (full_write (fd, zeros, n) != n) return false; n_bytes -= n; } @@ -397,7 +387,7 @@ lseek_copy (int src_fd, int dest_fd, char **abuf, size_t buf_size, /* When not inducing holes and when there is a hole between the end of the previous extent and the beginning of the current one, write zeros to the destination file. */ - if (! write_zeros (dest_fd, ext_hole_size)) + if (! write_zeros (dest_fd, ext_hole_size, abuf, buf_size)) { error (0, errno, _("%s: write failed"), quotef (dst_name)); @@ -601,7 +591,7 @@ copy_file_data (int ifd, struct stat const *ist, off_t ipos, char const *iname, ? (errno = EOVERFLOW, true) : make_holes ? ftruncate (ofd, oend) < 0 - : !write_zeros (ofd, hole_size)) + : !write_zeros (ofd, hole_size, &buf, buf_size)) { error (0, errno, _("failed to extend %s"), quoteaf (oname)); result = -1;