'cp -rx / /mnt' no longer complains "cannot create directory /mnt/".
[bug introduced in coreutils-9.1]
+ cp, mv, and install avoid allocating too much memory, and possibly
+ triggering "memory exhausted" failures, on file systems like ZFS,
+ which can return varied file system I/O block size values for files.
+ [bug introduced in coreutils-6.0]
+
'mv --backup=simple f d/' no longer mistakenly backs up d/f to f~.
[bug introduced in coreutils-9.1]
/* sys/stat.h and minmax.h will already have been included by system.h. */
#include "idx.h"
+#include "count-leading-zeros.h"
#include "stat-size.h"
static inline idx_t
io_blksize (struct stat sb)
{
+ /* Treat impossible blocksizes as if they were IO_BUFSIZE. */
+ idx_t blocksize = ST_BLKSIZE (sb) <= 0 ? IO_BUFSIZE : ST_BLKSIZE (sb);
+
+ /* Use a blocksize of at least IO_BUFSIZE bytes, keeping it a
+ multiple of the original blocksize. */
+ blocksize += (IO_BUFSIZE - 1) - (IO_BUFSIZE - 1) % blocksize;
+
+ /* For regular files we can ignore the blocksize if we think we know better.
+ ZFS sometimes understates the blocksize, because it thinks
+ apps stupidly allocate a block that large even for small files.
+ This misinformation can cause coreutils to use wrong-sized blocks.
+ Work around some of the performance bug by substituting the next
+ power of two when the reported blocksize is not a power of two. */
+ if (S_ISREG (sb.st_mode)
+ && blocksize & (blocksize - 1))
+ {
+ int leading_zeros = count_leading_zeros_ll (blocksize);
+ if (IDX_MAX < ULLONG_MAX || leading_zeros)
+ {
+ unsigned long long power = 1ull << (ULLONG_WIDTH - leading_zeros);
+ if (power <= IDX_MAX)
+ blocksize = power;
+ }
+ }
+
/* Don’t go above the largest power of two that fits in idx_t and size_t,
as that is asking for trouble. */
return MIN (MIN (IDX_MAX, SIZE_MAX) / 2 + 1,
- MAX (IO_BUFSIZE, ST_BLKSIZE (sb)));
+ blocksize);
}