From 06247428be8037b3739280f82cb29efe8397695f Mon Sep 17 00:00:00 2001 From: Hu Tao Date: Wed, 10 Sep 2014 17:05:48 +0800 Subject: [PATCH] raw-posix: Add falloc and full preallocation option This patch adds a new option preallocation for raw format, and implements falloc and full preallocation. Signed-off-by: Hu Tao Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- block/raw-posix.c | 102 +++++++++++++++++++++++++++++++++++----------- qemu-doc.texi | 9 ++++ qemu-img.texi | 9 ++++ 3 files changed, 96 insertions(+), 24 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index 7208c05f38..a253697427 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -30,6 +30,7 @@ #include "block/thread-pool.h" #include "qemu/iov.h" #include "raw-aio.h" +#include "qapi/util.h" #if defined(__APPLE__) && (__MACH__) #include @@ -1365,6 +1366,9 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp) int result = 0; int64_t total_size = 0; bool nocow = false; + PreallocMode prealloc; + char *buf = NULL; + Error *local_err = NULL; strstart(filename, "file:", &filename); @@ -1372,37 +1376,82 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp) total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), BDRV_SECTOR_SIZE); nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false); + buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); + prealloc = qapi_enum_parse(PreallocMode_lookup, buf, + PREALLOC_MODE_MAX, PREALLOC_MODE_OFF, + &local_err); + g_free(buf); + if (local_err) { + error_propagate(errp, local_err); + result = -EINVAL; + goto out; + } fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); if (fd < 0) { result = -errno; error_setg_errno(errp, -result, "Could not create file"); - } else { - if (nocow) { -#ifdef __linux__ - /* Set NOCOW flag to solve performance issue on fs like btrfs. - * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value - * will be ignored since any failure of this operation should not - * block the left work. - */ - int attr; - if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) { - attr |= FS_NOCOW_FL; - ioctl(fd, FS_IOC_SETFLAGS, &attr); - } -#endif - } - - if (ftruncate(fd, total_size) != 0) { - result = -errno; - error_setg_errno(errp, -result, "Could not resize file"); - } - if (qemu_close(fd) != 0) { - result = -errno; - error_setg_errno(errp, -result, "Could not close the new file"); - } + goto out; } + + if (nocow) { +#ifdef __linux__ + /* Set NOCOW flag to solve performance issue on fs like btrfs. + * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value + * will be ignored since any failure of this operation should not + * block the left work. + */ + int attr; + if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) { + attr |= FS_NOCOW_FL; + ioctl(fd, FS_IOC_SETFLAGS, &attr); + } +#endif + } + + if (ftruncate(fd, total_size) != 0) { + result = -errno; + error_setg_errno(errp, -result, "Could not resize file"); + goto out_close; + } + + if (prealloc == PREALLOC_MODE_FALLOC) { + /* posix_fallocate() doesn't set errno. */ + result = -posix_fallocate(fd, 0, total_size); + if (result != 0) { + error_setg_errno(errp, -result, + "Could not preallocate data for the new file"); + } + } else if (prealloc == PREALLOC_MODE_FULL) { + buf = g_malloc0(65536); + int64_t num = 0, left = total_size; + + while (left > 0) { + num = MIN(left, 65536); + result = write(fd, buf, num); + if (result < 0) { + result = -errno; + error_setg_errno(errp, -result, + "Could not write to the new file"); + break; + } + left -= num; + } + fsync(fd); + g_free(buf); + } else if (prealloc != PREALLOC_MODE_OFF) { + result = -EINVAL; + error_setg(errp, "Unsupported preallocation mode: %s", + PreallocMode_lookup[prealloc]); + } + +out_close: + if (qemu_close(fd) != 0 && result == 0) { + result = -errno; + error_setg_errno(errp, -result, "Could not close the new file"); + } +out: return result; } @@ -1585,6 +1634,11 @@ static QemuOptsList raw_create_opts = { .type = QEMU_OPT_BOOL, .help = "Turn off copy-on-write (valid only on btrfs)" }, + { + .name = BLOCK_OPT_PREALLOC, + .type = QEMU_OPT_STRING, + .help = "Preallocation mode (allowed values: off, falloc, full)" + }, { /* end of list */ } } }; diff --git a/qemu-doc.texi b/qemu-doc.texi index 2b232ae8b7..1f289d6a08 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -527,6 +527,15 @@ Linux or NTFS on Windows), then only the written sectors will reserve space. Use @code{qemu-img info} to know the real size used by the image or @code{ls -ls} on Unix/Linux. +Supported options: +@table @code +@item preallocation +Preallocation mode (allowed values: @code{off}, @code{falloc}, @code{full}). +@code{falloc} mode preallocates space for image by calling posix_fallocate(). +@code{full} mode preallocates space for image by writing zeros to underlying +storage. +@end table + @item qcow2 QEMU image format, the most versatile format. Use it to have smaller images (useful if your filesystem does not supports holes, for example diff --git a/qemu-img.texi b/qemu-img.texi index cc4668e64f..d64d05edda 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -419,6 +419,15 @@ Linux or NTFS on Windows), then only the written sectors will reserve space. Use @code{qemu-img info} to know the real size used by the image or @code{ls -ls} on Unix/Linux. +Supported options: +@table @code +@item preallocation +Preallocation mode (allowed values: @code{off}, @code{falloc}, @code{full}). +@code{falloc} mode preallocates space for image by calling posix_fallocate(). +@code{full} mode preallocates space for image by writing zeros to underlying +storage. +@end table + @item qcow2 QEMU image format, the most versatile format. Use it to have smaller images (useful if your filesystem does not supports holes, for example