[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH] Canonicalize qemu machine types



In qemu-0.11 there is a 'pc-0.10' machine type which allows you to run
guests with a machine which is compatible with the pc machine in
qemu-0.10 - e.g. using the original PCI class for virtio-blk and
virtio-console and disabling MSI support in virtio-net. The idea here
is that we don't want to surprise guests by changing the hardware when
qemu is updated.

I've just posted some patches for qemu-0.11 which allows libvirt to
canonicalize the 'pc' machine alias to the latest machine version.

This patches makes us use that so that when a guest is configured to
use the 'pc' machine type, we resolve that to 'pc-0.11' machine and
save that in the guest XML.

See also:

  https://fedoraproject.org/wiki/Features/KVM_Stable_Guest_ABI

* src/qemu_conf.c: add qemudCanonicalizeMachine() to parse the output
  of 'qemu -M ?'

* src/qemu_driver.c: canonicalize the machine type in qemudDomainDefine()
---
 src/qemu_conf.c   |  114 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/qemu_conf.h   |    3 +
 src/qemu_driver.c |    3 +
 3 files changed, 120 insertions(+), 0 deletions(-)

diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index 4043d70..3f4edfa 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -470,6 +470,120 @@ virCapsPtr qemudCapsInit(void) {
     return NULL;
 }
 
+/* Format is:
+ * <machine> <desc> [(alias of <machine>)]
+ */
+static int
+qemudParseMachineTypesStr(const char *machines ATTRIBUTE_UNUSED,
+                          const char *machine ATTRIBUTE_UNUSED,
+                          char **canonical)
+{
+    const char *p = machines;
+
+    *canonical = NULL;
+
+    do {
+        const char *eol;
+        char *s;
+
+        if (!(eol = strchr(p, '\n')))
+            return -1; /* eof file without finding @machine */
+
+        if (!STRPREFIX(p, machine)) {
+            p = eol + 1;
+            continue; /* doesn't match @machine */
+        }
+
+        p += strlen(machine);
+
+        if (*p != ' ') {
+            p = eol + 1;
+            continue; /* not a complete match of @machine */
+        }
+
+        do {
+            p++;
+        } while (*p == ' ');
+
+        p = strstr(p, "(alias of ");
+        if (!p || p > eol)
+            return 0; /* not an alias, name is canonical */
+
+        *canonical = strndup(p + strlen("(alias of "), eol - p);
+
+        s = strchr(*canonical, ')');
+        if (!s) {
+            VIR_FREE(*canonical);
+            *canonical = NULL;
+            return -1; /* output is screwed up */
+        }
+
+        *s = '\0';
+        break;
+    } while (1);
+
+    return 0;
+}
+
+int
+qemudCanonicalizeMachine(virConnectPtr conn ATTRIBUTE_UNUSED,
+                         virDomainDefPtr def)
+{
+    const char *const qemuarg[] = { def->emulator, "-M", "?", NULL };
+    const char *const qemuenv[] = { "LC_ALL=C", NULL };
+    char *machines, *canonical;
+    enum { MAX_MACHINES_OUTPUT_SIZE = 1024*4 };
+    pid_t child;
+    int newstdout = -1, len;
+    int ret = -1, status;
+
+    if (virExec(NULL, qemuarg, qemuenv, NULL,
+                &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
+        return -1;
+
+    len = virFileReadLimFD(newstdout, MAX_MACHINES_OUTPUT_SIZE, &machines);
+    if (len < 0) {
+        virReportSystemError(NULL, errno, "%s",
+                             _("Unable to read 'qemu -M ?' output"));
+        goto cleanup;
+    }
+
+    if (qemudParseMachineTypesStr(machines, def->os.machine, &canonical) < 0)
+        goto cleanup2;
+
+    if (canonical) {
+        VIR_FREE(def->os.machine);
+        def->os.machine = canonical;
+    }
+
+    ret = 0;
+
+cleanup2:
+    VIR_FREE(machines);
+cleanup:
+    if (close(newstdout) < 0)
+        ret = -1;
+
+rewait:
+    if (waitpid(child, &status, 0) != child) {
+        if (errno == EINTR)
+            goto rewait;
+
+        VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
+                  WEXITSTATUS(status), (unsigned long)child);
+        ret = -1;
+    }
+    /* Check & log unexpected exit status, but don't fail,
+     * as there's really no need to throw an error if we did
+     * actually read a valid version number above */
+    if (WEXITSTATUS(status) != 0) {
+        VIR_WARN(_("Unexpected exit status '%d', qemu probably failed"),
+                 WEXITSTATUS(status));
+    }
+
+    return ret;
+}
+
 static unsigned int qemudComputeCmdFlags(const char *help,
                                          unsigned int version,
                                          unsigned int is_kvm,
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
index fbf2ab9..b668669 100644
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -123,6 +123,9 @@ int         qemudExtractVersionInfo     (const char *qemu,
                                          unsigned int *version,
                                          unsigned int *flags);
 
+int         qemudCanonicalizeMachine    (virConnectPtr conn,
+                                         virDomainDefPtr def);
+
 int         qemudParseHelpStr           (const char *str,
                                          unsigned int *flags,
                                          unsigned int *version,
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index d2db1a2..98f8e95 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -4102,6 +4102,9 @@ static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
         }
     }
 
+    if (qemudCanonicalizeMachine(conn, def) < 0)
+        goto cleanup;
+
     if (!(vm = virDomainAssignDef(conn,
                                   &driver->domains,
                                   def))) {
-- 
1.6.2.5


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]