From c29d0929051ad8847be6952afd5d81664bb4c1a3 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Fri, 20 Mar 2009 12:17:56 +0000 Subject: [PATCH] use posix_fallocate() to allocate diskspace faster * src/libvirt_private.syms src/storage_backend_fs.c src/util.c src/util.h: use posix_fallocate() on supported systems to allocate diskspace faster, patches by Amit Shah Daniel --- AUTHORS | 1 + ChangeLog | 6 ++++ configure.in | 2 +- src/libvirt_private.syms | 1 + src/storage_backend_fs.c | 44 +++++++++++++++++++------- src/util.c | 68 ++++++++++++++++++++++++++++++++++++++++ src/util.h | 1 + 7 files changed, 111 insertions(+), 12 deletions(-) diff --git a/AUTHORS b/AUTHORS index 906fff61d9..1c4f3b8668 100644 --- a/AUTHORS +++ b/AUTHORS @@ -65,6 +65,7 @@ Patches have also been contributed by: Maximilian Wilhelm Ryota Ozaki Pritesh Kothari + Amit Shah [....send patches to get your name here....] diff --git a/ChangeLog b/ChangeLog index ff79c06e55..4e55fad4c6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Fri Mar 20 13:16:01 CET 2009 Daniel Veillard + + * src/libvirt_private.syms src/storage_backend_fs.c src/util.c + src/util.h: use posix_fallocate() on supported systems to + allocate diskspace faster, patches by Amit Shah + Fri Mar 20 11:41:40 GMT 2009 Daniel P. Berrange Fix test breakage on x86_64 from previous change diff --git a/configure.in b/configure.in index 413d27cc6a..6b2bb5e0d2 100644 --- a/configure.in +++ b/configure.in @@ -72,7 +72,7 @@ dnl Use --disable-largefile if you don't want this. AC_SYS_LARGEFILE dnl Availability of various common functions (non-fatal if missing). -AC_CHECK_FUNCS([cfmakeraw regexec uname sched_getaffinity getuid getgid]) +AC_CHECK_FUNCS([cfmakeraw regexec uname sched_getaffinity getuid getgid posix_fallocate mmap]) dnl Availability of various not common threadsafe functions AC_CHECK_FUNCS([strerror_r strtok_r getmntent_r getgrnam_r getpwuid_r]) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f0d8afac15..a5f9f925a6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -308,6 +308,7 @@ virStrToLong_ui; virFileLinkPointsTo; saferead; safewrite; +safezero; virMacAddrCompare; virEnumFromString; virEnumToString; diff --git a/src/storage_backend_fs.c b/src/storage_backend_fs.c index c0b130e1f3..5000f4366f 100644 --- a/src/storage_backend_fs.c +++ b/src/storage_backend_fs.c @@ -62,6 +62,8 @@ static int qcowXGetBackingStore(virConnectPtr, char **, static int vmdk4GetBackingStore(virConnectPtr, char **, const unsigned char *, size_t); +static int track_allocation_progress = 0; + /* Either 'magic' or 'extension' *must* be provided */ struct FileTypeInfo { int type; /* One of the constants above */ @@ -1016,24 +1018,44 @@ virStorageBackendFileSystemVolCreate(virConnectPtr conn, } /* Pre-allocate any data if requested */ - /* XXX slooooooooooooooooow. - * Need to add in progress bars & bg thread somehow */ + /* XXX slooooooooooooooooow on non-extents-based file systems */ + /* FIXME: Add in progress bars & bg thread if progress bar requested */ if (vol->allocation) { - unsigned long long remain = vol->allocation; - static char const zeros[4096]; - while (remain) { - int bytes = sizeof(zeros); - if (bytes > remain) - bytes = remain; - if ((bytes = safewrite(fd, zeros, bytes)) < 0) { - virReportSystemError(conn, errno, + if (track_allocation_progress) { + unsigned long long remain = vol->allocation; + + while (remain) { + /* Allocate in chunks of 512MiB: big-enough chunk + * size and takes approx. 9s on ext3. A progress + * update every 9s is a fair-enough trade-off + */ + unsigned long long bytes = 512 * 1024 * 1024; + int r; + + if (bytes > remain) + bytes = remain; + if ((r = safezero(fd, 0, vol->allocation - remain, + bytes)) != 0) { + virReportSystemError(conn, r, + _("cannot fill file '%s'"), + vol->target.path); + unlink(vol->target.path); + close(fd); + return -1; + } + remain -= bytes; + } + } else { /* No progress bars to be shown */ + int r; + + if ((r = safezero(fd, 0, 0, vol->allocation)) != 0) { + virReportSystemError(conn, r, _("cannot fill file '%s'"), vol->target.path); unlink(vol->target.path); close(fd); return -1; } - remain -= bytes; } } diff --git a/src/util.c b/src/util.c index 66ad9a4a37..93d2937d2b 100644 --- a/src/util.c +++ b/src/util.c @@ -39,6 +39,9 @@ #if HAVE_SYS_WAIT_H #include #endif +#if HAVE_MMAP +#include +#endif #include #include #if HAVE_TERMIOS_H @@ -117,6 +120,71 @@ ssize_t safewrite(int fd, const void *buf, size_t count) return nwritten; } +#ifdef HAVE_POSIX_FALLOCATE +int safezero(int fd, int flags, off_t offset, off_t len) +{ + return posix_fallocate(fd, offset, len); +} +#else + +#ifdef HAVE_MMAP +int safezero(int fd, int flags, off_t offset, off_t len) +{ + int r; + char *buf; + + /* memset wants the mmap'ed file to be present on disk so create a + * sparse file + */ + r = ftruncate(fd, len); + if (r < 0) + return -errno; + + buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); + if (buf == MAP_FAILED) + return -errno; + + memset(buf, 0, len); + munmap(buf, len); + + return 0; +} + +#else /* HAVE_MMAP */ + +int safezero(int fd, int flags, off_t offset, off_t len) +{ + int r; + char *buf; + unsigned long long remain, bytes; + + /* Split up the write in small chunks so as not to allocate lots of RAM */ + remain = len; + bytes = 1024 * 1024; + + r = VIR_ALLOC_N(buf, bytes); + if (r < 0) + return -ENOMEM; + + while (remain) { + if (bytes > remain) + bytes = remain; + + r = safewrite(fd, buf, len); + if (r < 0) { + VIR_FREE(buf); + return r; + } + + /* safewrite() guarantees all data will be written */ + remain -= bytes; + } + VIR_FREE(buf); + return 0; +} +#endif /* HAVE_MMAP */ +#endif /* HAVE_POSIX_FALLOCATE */ + #ifndef PROXY int virFileStripSuffix(char *str, diff --git a/src/util.h b/src/util.h index 87cbf67477..3fd5d2511c 100644 --- a/src/util.h +++ b/src/util.h @@ -31,6 +31,7 @@ int saferead(int fd, void *buf, size_t count); ssize_t safewrite(int fd, const void *buf, size_t count); +int safezero(int fd, int flags, off_t offset, off_t len); enum { VIR_EXEC_NONE = 0, -- GitLab