Package: coreutils Version: 9.4-3.1 strace cp --sparse=always dd dd-sparse [extraneous stuff skipped] openat(AT_FDCWD, "dd", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0755, st_size=134248, ...}) = 0 openat(AT_FDCWD, "dd-sparse", O_WRONLY|O_CREAT|O_EXCL, 0755) = 4 ioctl(4, BTRFS_IOC_CLONE or FICLONE, 3) = 0 close(4) = 0 close(3) = 0
It makes no attempt to look for sparse regions in the file, just uses FICLONE (which succeeds because it's on XFS). I worked around this by copying to /tmp, which is on a different filesystem (tmpfs): openat(AT_FDCWD, "dd", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0755, st_size=134248, ...}) = 0 openat(AT_FDCWD, "/tmp/dd-sparse", O_WRONLY|O_CREAT|O_EXCL, 0755) = 4 ioctl(4, BTRFS_IOC_CLONE or FICLONE, 3) = -1 EXDEV (Invalid cross-device link) fstat(4, {st_mode=S_IFREG|0755, st_size=0, ...}) = 0 fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0@>\0\0\0\0\0\0"..., 131072) = 131072 write(4, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0@>\0\0\0\0\0\0"..., 81920) = 81920 lseek(4, 45056, SEEK_CUR) = 126976 fallocate(4, FALLOC_FL_KEEP_SIZE|FALLOC_FL_PUNCH_HOLE, 81920, 45056) = 0 write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 read(3, "\320\34\0\0\0\0\0\0\320\34\0\0\0\0\0\0\320\34\0\0\0\0\0\0\320\34\0\0\0\0\0\0"..., 131072) = 3176 write(4, "\320\34\0\0\0\0\0\0\320\34\0\0\0\0\0\0\320\34\0\0\0\0\0\0\320\34\0\0\0\0\0\0"..., 3176) = 3176 read(3, "", 131072) = 0 close(4) = 0 close(3) = 0 Without looking at the source code, it seems likely that cp blindly tries FICLONE without checking to see whether the sparse flag is set. I suggest that setting --sparse=always should disable the FICLONE optimisation.