dnl Availability of various common functions (non-fatal if missing),
dnl and various less common threadsafe functions
-AC_CHECK_FUNCS_ONCE([cfmakeraw geteuid getgid getgrnam_r getmntent_r \
- getpwuid_r getuid kill mmap newlocale posix_fallocate posix_memalign \
- prlimit regexec sched_getaffinity setgroups setns setrlimit symlink \
- sysctlbyname])
+AC_CHECK_FUNCS_ONCE([cfmakeraw fallocate geteuid getgid getgrnam_r \
+ getmntent_r getpwuid_r getuid kill mmap newlocale posix_fallocate \
+ posix_memalign prlimit regexec sched_getaffinity setgroups setns \
+ setrlimit symlink sysctlbyname])
dnl Availability of pthread functions (if missing, win32 threading is
dnl assumed). Because of $LIB_PTHREAD, we cannot use AC_CHECK_FUNCS_ONCE.
virStorageVolDefPtr inputvol,
int fd,
unsigned long long *total,
- int is_dest_file)
+ int want_sparse)
{
int inputfd = -1;
int amtread = -1;
interval = ((wbytes > amtleft) ? amtleft : wbytes);
int offset = amtread - amtleft;
- if (is_dest_file && memcmp(buf+offset, zerobuf, interval) == 0) {
+ if (want_sparse && memcmp(buf+offset, zerobuf, interval) == 0) {
if (lseek(fd, interval, SEEK_CUR) < 0) {
ret = -errno;
virReportSystemError(errno,
createRawFile(int fd, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol)
{
+ int need_alloc = 1;
int ret = 0;
unsigned long long remain;
goto cleanup;
}
+#ifdef HAVE_FALLOCATE
+ /* Try to preallocate all requested disk space, but fall back to
+ * other methods if this fails with ENOSYS or EOPNOTSUPP.
+ * NOTE: do not use posix_fallocate; posix_fallocate falls back
+ * to writing zeroes block by block in case fallocate isn't
+ * available, and since we're going to copy data from another
+ * file it doesn't make sense to write the file twice. */
+ if (fallocate(fd, 0, 0, vol->allocation) == 0) {
+ need_alloc = 0;
+ } else if (errno != ENOSYS && errno != EOPNOTSUPP) {
+ ret = -errno;
+ virReportSystemError(errno,
+ _("cannot allocate %llu bytes in file '%s'"),
+ vol->allocation, vol->target.path);
+ goto cleanup;
+ }
+#endif
+
remain = vol->allocation;
if (inputvol) {
- ret = virStorageBackendCopyToFD(vol, inputvol, fd, &remain, 1);
+ /* allow zero blocks to be skipped if we've requested sparse
+ * allocation (allocation < capacity) or we have already
+ * been able to allocate the required space. */
+ int want_sparse = (need_alloc == 0) ||
+ (vol->allocation < inputvol->capacity);
+
+ ret = virStorageBackendCopyToFD(vol, inputvol, fd, &remain, want_sparse);
if (ret < 0) {
goto cleanup;
}
}
- if (remain) {
- if (safezero(fd, 0, remain) < 0) {
+ if (remain && need_alloc) {
+ if (safezero(fd, vol->allocation - remain, remain) < 0) {
ret = -errno;
virReportSystemError(errno, _("cannot fill file '%s'"),
vol->target.path);