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