Daniel P. Berrange e3a592
From 2ba8625d6d148fa489586efabdfaf2ef20903762 Mon Sep 17 00:00:00 2001
Daniel P. Berrange e3a592
From: Daniel P. Berrange <berrange@redhat.com>
Daniel P. Berrange e3a592
Date: Wed, 16 Jun 2010 14:14:05 +0100
Daniel P. Berrange e3a592
Subject: [PATCH 10/11] Rewrite qemu-img backing store format handling
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
When creating qcow2 files with a backing store, it is important
Daniel P. Berrange e3a592
to set an explicit format to prevent QEMU probing. The storage
Daniel P. Berrange e3a592
backend was only doing this if it found a 'kvm-img' binary. This
Daniel P. Berrange e3a592
is wrong because plenty of kvm-img binaries don't support an
Daniel P. Berrange e3a592
explicit format, and plenty of 'qemu-img' binaries do support
Daniel P. Berrange e3a592
a format. The result was that most qcow2 files were not getting
Daniel P. Berrange e3a592
a backing store format.
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
This patch runs 'qemu-img -h' to check for the two support
Daniel P. Berrange e3a592
argument formats
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
  '-o backing_format=raw'
Daniel P. Berrange e3a592
  '-F raw'
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
and use whichever option it finds
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
* src/storage/storage_backend.c: Query binary to determine
Daniel P. Berrange e3a592
  how to set the backing store format
Daniel P. Berrange e3a592
---
Daniel P. Berrange e3a592
 src/storage/storage_backend.c |  214 +++++++++++++++++++++++++++++------------
Daniel P. Berrange e3a592
 1 files changed, 152 insertions(+), 62 deletions(-)
Daniel P. Berrange e3a592
Daniel P. Berrange e3a592
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
Daniel P. Berrange e3a592
index aba8937..c185693 100644
Daniel P. Berrange e3a592
--- a/src/storage/storage_backend.c
Daniel P. Berrange e3a592
+++ b/src/storage/storage_backend.c
Daniel P. Berrange e3a592
@@ -561,6 +561,69 @@ static int virStorageBackendCreateExecCommand(virStoragePoolObjPtr pool,
Daniel P. Berrange e3a592
     return 0;
Daniel P. Berrange e3a592
 }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
+enum {
Daniel P. Berrange e3a592
+    QEMU_IMG_BACKING_FORMAT_NONE = 0,
Daniel P. Berrange e3a592
+    QEMU_IMG_BACKING_FORMAT_FLAG,
Daniel P. Berrange e3a592
+    QEMU_IMG_BACKING_FORMAT_OPTIONS,
Daniel P. Berrange e3a592
+};
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+static int virStorageBackendQEMUImgBackingFormat(const char *qemuimg)
Daniel P. Berrange e3a592
+{
Daniel P. Berrange e3a592
+    const char *const qemuarg[] = { qemuimg, "-h", NULL };
Daniel P. Berrange e3a592
+    const char *const qemuenv[] = { "LC_ALL=C", NULL };
Daniel P. Berrange e3a592
+    pid_t child = 0;
Daniel P. Berrange e3a592
+    int status;
Daniel P. Berrange e3a592
+    int newstdout = -1;
Daniel P. Berrange e3a592
+    char *help = NULL;
Daniel P. Berrange e3a592
+    enum { MAX_HELP_OUTPUT_SIZE = 1024*8 };
Daniel P. Berrange e3a592
+    int len;
Daniel P. Berrange e3a592
+    char *start;
Daniel P. Berrange e3a592
+    char *end;
Daniel P. Berrange e3a592
+    char *tmp;
Daniel P. Berrange e3a592
+    int ret = -1;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if (virExec(qemuarg, qemuenv, NULL,
Daniel P. Berrange e3a592
+                &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
Daniel P. Berrange e3a592
+        goto cleanup;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if ((len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help)) < 0) {
Daniel P. Berrange e3a592
+        virReportSystemError(errno,
Daniel P. Berrange e3a592
+                             _("Unable to read '%s -h' output"),
Daniel P. Berrange e3a592
+                             qemuimg);
Daniel P. Berrange e3a592
+        goto cleanup;
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    start = strstr(help, " create ");
Daniel P. Berrange e3a592
+    end = strstr(start, "\n");
Daniel P. Berrange e3a592
+    if ((tmp = strstr(start, "-F fmt")) && tmp < end)
Daniel P. Berrange e3a592
+        ret = QEMU_IMG_BACKING_FORMAT_FLAG;
Daniel P. Berrange e3a592
+    else if ((tmp = strstr(start, "[-o options]")) && tmp < end)
Daniel P. Berrange e3a592
+        ret = QEMU_IMG_BACKING_FORMAT_OPTIONS;
Daniel P. Berrange e3a592
+    else
Daniel P. Berrange e3a592
+        ret = QEMU_IMG_BACKING_FORMAT_NONE;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+cleanup:
Daniel P. Berrange e3a592
+    VIR_FREE(help);
Daniel P. Berrange e3a592
+    close(newstdout);
Daniel P. Berrange e3a592
+rewait:
Daniel P. Berrange e3a592
+    if (child) {
Daniel P. Berrange e3a592
+        if (waitpid(child, &status, 0) != child) {
Daniel P. Berrange e3a592
+            if (errno == EINTR)
Daniel P. Berrange e3a592
+                goto rewait;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+            VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
Daniel P. Berrange e3a592
+                      WEXITSTATUS(status), (unsigned long)child);
Daniel P. Berrange e3a592
+        }
Daniel P. Berrange e3a592
+        if (WEXITSTATUS(status) != 0) {
Daniel P. Berrange e3a592
+            VIR_WARN("Unexpected exit status '%d', qemu probably failed",
Daniel P. Berrange e3a592
+                     WEXITSTATUS(status));
Daniel P. Berrange e3a592
+        }
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    return ret;
Daniel P. Berrange e3a592
+}
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
 static int
Daniel P. Berrange e3a592
 virStorageBackendCreateQemuImg(virConnectPtr conn,
Daniel P. Berrange e3a592
                                virStoragePoolObjPtr pool,
Daniel P. Berrange e3a592
@@ -568,10 +631,9 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
Daniel P. Berrange e3a592
                                virStorageVolDefPtr inputvol,
Daniel P. Berrange e3a592
                                unsigned int flags ATTRIBUTE_UNUSED)
Daniel P. Berrange e3a592
 {
Daniel P. Berrange e3a592
-    int ret;
Daniel P. Berrange e3a592
+    int ret = -1;
Daniel P. Berrange e3a592
     char size[100];
Daniel P. Berrange e3a592
     char *create_tool;
Daniel P. Berrange e3a592
-    short use_kvmimg;
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
     const char *type = virStorageFileFormatTypeToString(vol->target.format);
Daniel P. Berrange e3a592
     const char *backingType = vol->backingStore.path ?
Daniel P. Berrange e3a592
@@ -582,41 +644,10 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
Daniel P. Berrange e3a592
     const char *inputPath = inputvol ? inputvol->target.path : NULL;
Daniel P. Berrange e3a592
     /* Treat input block devices as 'raw' format */
Daniel P. Berrange e3a592
     const char *inputType = inputPath ?
Daniel P. Berrange e3a592
-                            virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ? VIR_STORAGE_FILE_RAW : inputvol->target.format) :
Daniel P. Berrange e3a592
-                            NULL;
Daniel P. Berrange e3a592
-
Daniel P. Berrange e3a592
-    const char **imgargv;
Daniel P. Berrange e3a592
-    /* The extra NULL field is for indicating encryption (-e). */
Daniel P. Berrange e3a592
-    const char *imgargvnormal[] = {
Daniel P. Berrange e3a592
-        NULL, "create",
Daniel P. Berrange e3a592
-        "-f", type,
Daniel P. Berrange e3a592
-        vol->target.path,
Daniel P. Berrange e3a592
-        size,
Daniel P. Berrange e3a592
-        NULL,
Daniel P. Berrange e3a592
-        NULL
Daniel P. Berrange e3a592
-    };
Daniel P. Berrange e3a592
-    /* Extra NULL fields are for including "backingType" when using
Daniel P. Berrange e3a592
-     * kvm-img (-F backingType), and for indicating encryption (-e).
Daniel P. Berrange e3a592
-     */
Daniel P. Berrange e3a592
-    const char *imgargvbacking[] = {
Daniel P. Berrange e3a592
-        NULL, "create",
Daniel P. Berrange e3a592
-        "-f", type,
Daniel P. Berrange e3a592
-        "-b", vol->backingStore.path,
Daniel P. Berrange e3a592
-        vol->target.path,
Daniel P. Berrange e3a592
-        size,
Daniel P. Berrange e3a592
-        NULL,
Daniel P. Berrange e3a592
-        NULL,
Daniel P. Berrange e3a592
-        NULL,
Daniel P. Berrange e3a592
-        NULL
Daniel P. Berrange e3a592
-    };
Daniel P. Berrange e3a592
-    const char *convargv[] = {
Daniel P. Berrange e3a592
-        NULL, "convert",
Daniel P. Berrange e3a592
-        "-f", inputType,
Daniel P. Berrange e3a592
-        "-O", type,
Daniel P. Berrange e3a592
-        inputPath,
Daniel P. Berrange e3a592
-        vol->target.path,
Daniel P. Berrange e3a592
-        NULL,
Daniel P. Berrange e3a592
-    };
Daniel P. Berrange e3a592
+        virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ?
Daniel P. Berrange e3a592
+                                         VIR_STORAGE_FILE_RAW :
Daniel P. Berrange e3a592
+                                         inputvol->target.format) :
Daniel P. Berrange e3a592
+        NULL;
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
     if (type == NULL) {
Daniel P. Berrange e3a592
         virStorageReportError(VIR_ERR_INTERNAL_ERROR,
Daniel P. Berrange e3a592
@@ -690,44 +721,103 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
Daniel P. Berrange e3a592
         }
Daniel P. Berrange e3a592
     }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-    if ((create_tool = virFindFileInPath("kvm-img")) != NULL)
Daniel P. Berrange e3a592
-        use_kvmimg = 1;
Daniel P. Berrange e3a592
-    else if ((create_tool = virFindFileInPath("qemu-img")) != NULL)
Daniel P. Berrange e3a592
-        use_kvmimg = 0;
Daniel P. Berrange e3a592
-    else {
Daniel P. Berrange e3a592
+    /* Size in KB */
Daniel P. Berrange e3a592
+    snprintf(size, sizeof(size), "%lluK", vol->capacity/1024);
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    /* KVM is usually ahead of qemu on features, so try that first */
Daniel P. Berrange e3a592
+    create_tool = virFindFileInPath("kvm-img");
Daniel P. Berrange e3a592
+    if (!create_tool)
Daniel P. Berrange e3a592
+        create_tool = virFindFileInPath("qemu-img");
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+    if (!create_tool) {
Daniel P. Berrange e3a592
         virStorageReportError(VIR_ERR_INTERNAL_ERROR,
Daniel P. Berrange e3a592
                               "%s", _("unable to find kvm-img or qemu-img"));
Daniel P. Berrange e3a592
         return -1;
Daniel P. Berrange e3a592
     }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
     if (inputvol) {
Daniel P. Berrange e3a592
-        convargv[0] = create_tool;
Daniel P. Berrange e3a592
-        imgargv = convargv;
Daniel P. Berrange e3a592
+        const char *imgargv[] = {
Daniel P. Berrange e3a592
+            create_tool,
Daniel P. Berrange e3a592
+            "convert",
Daniel P. Berrange e3a592
+            "-f", inputType,
Daniel P. Berrange e3a592
+            "-O", type,
Daniel P. Berrange e3a592
+            inputPath,
Daniel P. Berrange e3a592
+            vol->target.path,
Daniel P. Berrange e3a592
+            NULL,
Daniel P. Berrange e3a592
+        };
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
Daniel P. Berrange e3a592
     } else if (vol->backingStore.path) {
Daniel P. Berrange e3a592
-        imgargvbacking[0] = create_tool;
Daniel P. Berrange e3a592
-        if (use_kvmimg) {
Daniel P. Berrange e3a592
-            imgargvbacking[6] = "-F";
Daniel P. Berrange e3a592
-            imgargvbacking[7] = backingType;
Daniel P. Berrange e3a592
-            imgargvbacking[8] = vol->target.path;
Daniel P. Berrange e3a592
-            imgargvbacking[9] = size;
Daniel P. Berrange e3a592
+        const char *imgargv[] = {
Daniel P. Berrange e3a592
+            create_tool,
Daniel P. Berrange e3a592
+            "create",
Daniel P. Berrange e3a592
+            "-f", type,
Daniel P. Berrange e3a592
+            "-b", vol->backingStore.path,
Daniel P. Berrange e3a592
+            NULL,
Daniel P. Berrange e3a592
+            NULL,
Daniel P. Berrange e3a592
+            NULL,
Daniel P. Berrange e3a592
+            NULL,
Daniel P. Berrange e3a592
+            NULL,
Daniel P. Berrange e3a592
+            NULL
Daniel P. Berrange e3a592
+        };
Daniel P. Berrange e3a592
+        int imgformat = virStorageBackendQEMUImgBackingFormat(create_tool);
Daniel P. Berrange e3a592
+        char *optflag = NULL;
Daniel P. Berrange e3a592
+        if (imgformat < 0)
Daniel P. Berrange e3a592
+            goto cleanup;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        switch (imgformat) {
Daniel P. Berrange e3a592
+        case QEMU_IMG_BACKING_FORMAT_FLAG:
Daniel P. Berrange e3a592
+            imgargv[6] = "-F";
Daniel P. Berrange e3a592
+            imgargv[7] = backingType;
Daniel P. Berrange e3a592
+            imgargv[8] = vol->target.path;
Daniel P. Berrange e3a592
+            imgargv[9] = size;
Daniel P. Berrange e3a592
+            if (vol->target.encryption != NULL)
Daniel P. Berrange e3a592
+                imgargv[10] = "-e";
Daniel P. Berrange e3a592
+            break;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        case QEMU_IMG_BACKING_FORMAT_OPTIONS:
Daniel P. Berrange e3a592
+            if (virAsprintf(&optflag, "backing_fmt=%s", backingType) < 0) {
Daniel P. Berrange e3a592
+                virReportOOMError();
Daniel P. Berrange e3a592
+                goto cleanup;
Daniel P. Berrange e3a592
+            }
Daniel P. Berrange e3a592
+            imgargv[6] = "-o";
Daniel P. Berrange e3a592
+            imgargv[7] = optflag;
Daniel P. Berrange e3a592
+            imgargv[8] = vol->target.path;
Daniel P. Berrange e3a592
+            imgargv[9] = size;
Daniel P. Berrange e3a592
             if (vol->target.encryption != NULL)
Daniel P. Berrange e3a592
-                imgargvbacking[10] = "-e";
Daniel P. Berrange e3a592
-        } else if (vol->target.encryption != NULL)
Daniel P. Berrange e3a592
-            imgargvbacking[8] = "-e";
Daniel P. Berrange e3a592
-        imgargv = imgargvbacking;
Daniel P. Berrange e3a592
+                imgargv[10] = "-e";
Daniel P. Berrange e3a592
+            break;
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        default:
Daniel P. Berrange e3a592
+            VIR_INFO("Unable to set backing store format for %s with %s",
Daniel P. Berrange e3a592
+                     vol->target.path, create_tool);
Daniel P. Berrange e3a592
+            imgargv[6] = vol->target.path;
Daniel P. Berrange e3a592
+            imgargv[7] = size;
Daniel P. Berrange e3a592
+            if (vol->target.encryption != NULL)
Daniel P. Berrange e3a592
+                imgargv[8] = "-e";
Daniel P. Berrange e3a592
+        }
Daniel P. Berrange e3a592
+
Daniel P. Berrange e3a592
+        ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
Daniel P. Berrange e3a592
+        VIR_FREE(optflag);
Daniel P. Berrange e3a592
     } else {
Daniel P. Berrange e3a592
-        imgargvnormal[0] = create_tool;
Daniel P. Berrange e3a592
-        imgargv = imgargvnormal;
Daniel P. Berrange e3a592
+        /* The extra NULL field is for indicating encryption (-e). */
Daniel P. Berrange e3a592
+        const char *imgargv[] = {
Daniel P. Berrange e3a592
+            create_tool,
Daniel P. Berrange e3a592
+            "create",
Daniel P. Berrange e3a592
+            "-f", type,
Daniel P. Berrange e3a592
+            vol->target.path,
Daniel P. Berrange e3a592
+            size,
Daniel P. Berrange e3a592
+            NULL,
Daniel P. Berrange e3a592
+            NULL
Daniel P. Berrange e3a592
+        };
Daniel P. Berrange e3a592
         if (vol->target.encryption != NULL)
Daniel P. Berrange e3a592
             imgargv[6] = "-e";
Daniel P. Berrange e3a592
-    }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
+        ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
Daniel P. Berrange e3a592
+    }
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
-    /* Size in KB */
Daniel P. Berrange e3a592
-    snprintf(size, sizeof(size), "%lluK", vol->capacity/1024);
Daniel P. Berrange e3a592
-
Daniel P. Berrange e3a592
-    ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
Daniel P. Berrange e3a592
-    VIR_FREE(imgargv[0]);
Daniel P. Berrange e3a592
+    cleanup:
Daniel P. Berrange e3a592
+    VIR_FREE(create_tool);
Daniel P. Berrange e3a592
 
Daniel P. Berrange e3a592
     return ret;
Daniel P. Berrange e3a592
 }
Daniel P. Berrange e3a592
-- 
Daniel P. Berrange e3a592
1.7.1.1
Daniel P. Berrange e3a592