958e1b
From 61a3061760caaaaa4f025f5712dcd8f84f2f5d70 Mon Sep 17 00:00:00 2001
958e1b
From: Max Reitz <mreitz@redhat.com>
958e1b
Date: Mon, 10 Nov 2014 09:14:06 +0100
958e1b
Subject: [PATCH 29/41] raw-posix: Add falloc and full preallocation option
958e1b
958e1b
Message-id: <1415610847-15383-4-git-send-email-mreitz@redhat.com>
958e1b
Patchwork-id: 62239
958e1b
O-Subject: [RHEL-7.1 qemu-kvm PATCH v2 3/4] raw-posix: Add falloc and full preallocation option
958e1b
Bugzilla: 1087724
958e1b
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
958e1b
RH-Acked-by: Fam Zheng <famz@redhat.com>
958e1b
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
958e1b
958e1b
From: Hu Tao <hutao@cn.fujitsu.com>
958e1b
958e1b
This patch adds a new option preallocation for raw format, and implements
958e1b
falloc and full preallocation.
958e1b
958e1b
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
958e1b
Reviewed-by: Max Reitz <mreitz@redhat.com>
958e1b
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
958e1b
(cherry picked from commit 06247428be8037b3739280f82cb29efe8397695f)
958e1b
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
958e1b
958e1b
Conflicts:
958e1b
	block/raw-posix.c
958e1b
958e1b
QEMUOptionParameter has not been replaced with QemuOpts downstream
958e1b
(upstream 6f482f742dd841b45297fb0e5f3d2c81779253be) and no "nocow"
958e1b
downstream.
958e1b
958e1b
Signed-off-by: Max Reitz <mreitz@redhat.com>
958e1b
---
958e1b
 block/raw-posix.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++------
958e1b
 qemu-doc.texi     |  9 ++++++++
958e1b
 qemu-img.texi     |  9 ++++++++
958e1b
 3 files changed, 78 insertions(+), 7 deletions(-)
958e1b
958e1b
diff --git a/block/raw-posix.c b/block/raw-posix.c
958e1b
index 9ee5b8e..cfe7452 100644
958e1b
--- a/block/raw-posix.c
958e1b
+++ b/block/raw-posix.c
958e1b
@@ -30,6 +30,7 @@
958e1b
 #include "block/thread-pool.h"
958e1b
 #include "qemu/iov.h"
958e1b
 #include "raw-aio.h"
958e1b
+#include "qapi/util.h"
958e1b
 
958e1b
 #if defined(__APPLE__) && (__MACH__)
958e1b
 #include <paths.h>
958e1b
@@ -1230,11 +1231,23 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
958e1b
     int fd;
958e1b
     int result = 0;
958e1b
     int64_t total_size = 0;
958e1b
+    PreallocMode prealloc = PREALLOC_MODE_OFF;
958e1b
+    char *buf = NULL;
958e1b
+    Error *local_err = NULL;
958e1b
 
958e1b
     /* Read out options */
958e1b
     while (options && options->name) {
958e1b
         if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
958e1b
             total_size = options->value.n / BDRV_SECTOR_SIZE;
958e1b
+        } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
958e1b
+            prealloc = qapi_enum_parse(PreallocMode_lookup, options->value.s,
958e1b
+                                       PREALLOC_MODE_MAX, PREALLOC_MODE_OFF,
958e1b
+                                       &local_err);
958e1b
+            if (local_err) {
958e1b
+                error_propagate(errp, local_err);
958e1b
+                result = -EINVAL;
958e1b
+                goto out;
958e1b
+            }
958e1b
         }
958e1b
         options++;
958e1b
     }
958e1b
@@ -1244,16 +1257,51 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
958e1b
     if (fd < 0) {
958e1b
         result = -errno;
958e1b
         error_setg_errno(errp, -result, "Could not create file");
958e1b
-    } else {
958e1b
-        if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
958e1b
-            result = -errno;
958e1b
-            error_setg_errno(errp, -result, "Could not resize file");
958e1b
+        goto out;
958e1b
+    }
958e1b
+
958e1b
+    if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
958e1b
+        result = -errno;
958e1b
+        error_setg_errno(errp, -result, "Could not resize file");
958e1b
+        goto out_close;
958e1b
+    }
958e1b
+
958e1b
+    if (prealloc == PREALLOC_MODE_FALLOC) {
958e1b
+        /* posix_fallocate() doesn't set errno. */
958e1b
+        result = -posix_fallocate(fd, 0, total_size * BDRV_SECTOR_SIZE);
958e1b
+        if (result != 0) {
958e1b
+            error_setg_errno(errp, -result,
958e1b
+                             "Could not preallocate data for the new file");
958e1b
         }
958e1b
-        if (qemu_close(fd) != 0) {
958e1b
-            result = -errno;
958e1b
-            error_setg_errno(errp, -result, "Could not close the new file");
958e1b
+    } else if (prealloc == PREALLOC_MODE_FULL) {
958e1b
+        buf = g_malloc0(65536);
958e1b
+        int64_t num = 0, left = total_size * BDRV_SECTOR_SIZE;
958e1b
+
958e1b
+        while (left > 0) {
958e1b
+            num = MIN(left, 65536);
958e1b
+            result = write(fd, buf, num);
958e1b
+            if (result < 0) {
958e1b
+                result = -errno;
958e1b
+                error_setg_errno(errp, -result,
958e1b
+                                 "Could not write to the new file");
958e1b
+                break;
958e1b
+            }
958e1b
+            left -= num;
958e1b
         }
958e1b
+        fsync(fd);
958e1b
+        g_free(buf);
958e1b
+    } else if (prealloc != PREALLOC_MODE_OFF) {
958e1b
+        result = -EINVAL;
958e1b
+        error_setg(errp, "Unsupported preallocation mode: %s",
958e1b
+                   PreallocMode_lookup[prealloc]);
958e1b
+    }
958e1b
+
958e1b
+out_close:
958e1b
+    if (qemu_close(fd) != 0 && result == 0) {
958e1b
+        result = -errno;
958e1b
+        error_setg_errno(errp, -result, "Could not close the new file");
958e1b
     }
958e1b
+out:
958e1b
     return result;
958e1b
 }
958e1b
 
958e1b
@@ -1404,6 +1452,11 @@ static QEMUOptionParameter raw_create_options[] = {
958e1b
         .type = OPT_SIZE,
958e1b
         .help = "Virtual disk size"
958e1b
     },
958e1b
+    {
958e1b
+        .name = BLOCK_OPT_PREALLOC,
958e1b
+        .type = OPT_STRING,
958e1b
+        .help = "Preallocation mode (allowed values: off, falloc, full)"
958e1b
+    },
958e1b
     { NULL }
958e1b
 };
958e1b
 
958e1b
diff --git a/qemu-doc.texi b/qemu-doc.texi
958e1b
index 54ab3c5..dc5b49e 100644
958e1b
--- a/qemu-doc.texi
958e1b
+++ b/qemu-doc.texi
958e1b
@@ -527,6 +527,15 @@ Linux or NTFS on Windows), then only the written sectors will reserve
958e1b
 space. Use @code{qemu-img info} to know the real size used by the
958e1b
 image or @code{ls -ls} on Unix/Linux.
958e1b
 
958e1b
+Supported options:
958e1b
+@table @code
958e1b
+@item preallocation
958e1b
+Preallocation mode (allowed values: @code{off}, @code{falloc}, @code{full}).
958e1b
+@code{falloc} mode preallocates space for image by calling posix_fallocate().
958e1b
+@code{full} mode preallocates space for image by writing zeros to underlying
958e1b
+storage.
958e1b
+@end table
958e1b
+
958e1b
 @item qcow2
958e1b
 QEMU image format, the most versatile format. Use it to have smaller
958e1b
 images (useful if your filesystem does not supports holes, for example
958e1b
diff --git a/qemu-img.texi b/qemu-img.texi
958e1b
index 5f99ebb..80d3261 100644
958e1b
--- a/qemu-img.texi
958e1b
+++ b/qemu-img.texi
958e1b
@@ -392,6 +392,15 @@ Linux or NTFS on Windows), then only the written sectors will reserve
958e1b
 space. Use @code{qemu-img info} to know the real size used by the
958e1b
 image or @code{ls -ls} on Unix/Linux.
958e1b
 
958e1b
+Supported options:
958e1b
+@table @code
958e1b
+@item preallocation
958e1b
+Preallocation mode (allowed values: @code{off}, @code{falloc}, @code{full}).
958e1b
+@code{falloc} mode preallocates space for image by calling posix_fallocate().
958e1b
+@code{full} mode preallocates space for image by writing zeros to underlying
958e1b
+storage.
958e1b
+@end table
958e1b
+
958e1b
 @item qcow2
958e1b
 QEMU image format, the most versatile format. Use it to have smaller
958e1b
 images (useful if your filesystem does not supports holes, for example
958e1b
-- 
958e1b
1.8.3.1
958e1b