aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2025-08-06 11:48:21 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2025-09-15 23:17:35 -0700
commit12d03a04446a8da4f5dc3cacd6888416687dd8a2 (patch)
tree0de3012f937cb0b4fda1e25f4921e1fcbad89efb
parentcp: refactor copying to return bytes copied (diff)
downloadcoreutils-12d03a04446a8da4f5dc3cacd6888416687dd8a2.tar.gz
coreutils-12d03a04446a8da4f5dc3cacd6888416687dd8a2.zip
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.
-rw-r--r--src/copy-file-data.c32
1 files changed, 11 insertions, 21 deletions
diff --git a/src/copy-file-data.c b/src/copy-file-data.c
index fb0b1dc40..513699e96 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;