render / rpms / libvirt

Forked from rpms/libvirt 9 months ago
Clone
3e5111
From 3b5aa0e6272a4b507034bba3d093734ebd658b3b Mon Sep 17 00:00:00 2001
3e5111
Message-Id: <3b5aa0e6272a4b507034bba3d093734ebd658b3b@dist-git>
3e5111
From: Jiri Denemark <jdenemar@redhat.com>
3e5111
Date: Wed, 31 May 2017 12:34:10 +0200
3e5111
Subject: [PATCH] qemu: Use updated CPU when starting QEMU if possible
3e5111
3e5111
If QEMU is new enough and we have the live updated CPU definition in
3e5111
either save or migration cookie, we can use it to enforce ABI. The
3e5111
original guest CPU from domain XML will be stored in private data.
3e5111
3e5111
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
3e5111
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
3e5111
(cherry picked from commit 8e34f478137c2a6b5e57e382729bd2776b042301)
3e5111
3e5111
https://bugzilla.redhat.com/show_bug.cgi?id=1441662
3e5111
3e5111
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
3e5111
---
3e5111
 src/qemu/qemu_domain.c    | 40 ++++++++++++++++++++++++++++++++++++++++
3e5111
 src/qemu/qemu_domain.h    |  5 +++++
3e5111
 src/qemu/qemu_driver.c    | 30 ++++++++++++++++++++++++------
3e5111
 src/qemu/qemu_migration.c |  2 +-
3e5111
 src/qemu/qemu_process.c   | 24 ++++++++++++++++++++++--
3e5111
 src/qemu/qemu_process.h   |  2 ++
3e5111
 6 files changed, 94 insertions(+), 9 deletions(-)
3e5111
3e5111
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
3e5111
index 7897a44634..82dacb3c9c 100644
3e5111
--- a/src/qemu/qemu_domain.c
3e5111
+++ b/src/qemu/qemu_domain.c
3e5111
@@ -9225,3 +9225,43 @@ virSaveCookieCallbacks virQEMUDriverDomainSaveCookie = {
3e5111
     .parse = qemuDomainSaveCookieParse,
3e5111
     .format = qemuDomainSaveCookieFormat,
3e5111
 };
3e5111
+
3e5111
+
3e5111
+/**
3e5111
+ * qemuDomainUpdateCPU:
3e5111
+ * @vm: domain which is being started
3e5111
+ * @cpu: CPU updated when the domain was running previously (before migration,
3e5111
+ *       snapshot, or save)
3e5111
+ * @origCPU: where to store the original CPU from vm->def in case @cpu was
3e5111
+ *           used instead
3e5111
+ *
3e5111
+ * Replace the CPU definition with the updated one when QEMU is new enough to
3e5111
+ * allow us to check extra features it is about to enable or disable when
3e5111
+ * starting a domain. The original CPU is stored in @origCPU.
3e5111
+ *
3e5111
+ * Returns 0 on success, -1 on error.
3e5111
+ */
3e5111
+int
3e5111
+qemuDomainUpdateCPU(virDomainObjPtr vm,
3e5111
+                    virCPUDefPtr cpu,
3e5111
+                    virCPUDefPtr *origCPU)
3e5111
+{
3e5111
+    qemuDomainObjPrivatePtr priv = vm->privateData;
3e5111
+
3e5111
+    *origCPU = NULL;
3e5111
+
3e5111
+    if (!cpu || !vm->def->cpu ||
3e5111
+        !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION) ||
3e5111
+        virCPUDefIsEqual(vm->def->cpu, cpu, false))
3e5111
+        return 0;
3e5111
+
3e5111
+    if (!(cpu = virCPUDefCopy(cpu)))
3e5111
+        return -1;
3e5111
+
3e5111
+    VIR_DEBUG("Replacing CPU def with the updated one");
3e5111
+
3e5111
+    *origCPU = vm->def->cpu;
3e5111
+    vm->def->cpu = cpu;
3e5111
+
3e5111
+    return 0;
3e5111
+}
3e5111
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
3e5111
index 2eea7924fb..d635d2995f 100644
3e5111
--- a/src/qemu/qemu_domain.h
3e5111
+++ b/src/qemu/qemu_domain.h
3e5111
@@ -921,4 +921,9 @@ char *qemuDomainDiskBackingStoreGetName(virDomainDiskDefPtr disk,
3e5111
 virStorageSourcePtr qemuDomainGetStorageSourceByDevstr(const char *devstr,
3e5111
                                                        virDomainDefPtr def);
3e5111
 
3e5111
+int
3e5111
+qemuDomainUpdateCPU(virDomainObjPtr vm,
3e5111
+                    virCPUDefPtr cpu,
3e5111
+                    virCPUDefPtr *origCPU);
3e5111
+
3e5111
 #endif /* __QEMU_DOMAIN_H__ */
3e5111
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
3e5111
index f5c5c302be..5567103c37 100644
3e5111
--- a/src/qemu/qemu_driver.c
3e5111
+++ b/src/qemu/qemu_driver.c
3e5111
@@ -1782,7 +1782,7 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn,
3e5111
         goto cleanup;
3e5111
     }
3e5111
 
3e5111
-    if (qemuProcessStart(conn, driver, vm, QEMU_ASYNC_JOB_START,
3e5111
+    if (qemuProcessStart(conn, driver, vm, NULL, QEMU_ASYNC_JOB_START,
3e5111
                          NULL, -1, NULL, NULL,
3e5111
                          VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
3e5111
                          start_flags) < 0) {
3e5111
@@ -6500,8 +6500,8 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
3e5111
         }
3e5111
     }
3e5111
 
3e5111
-    if (qemuProcessStart(conn, driver, vm, asyncJob,
3e5111
-                         "stdio", *fd, path, NULL,
3e5111
+    if (qemuProcessStart(conn, driver, vm, cookie ? cookie->cpu : NULL,
3e5111
+                         asyncJob, "stdio", *fd, path, NULL,
3e5111
                          VIR_NETDEV_VPORT_PROFILE_OP_RESTORE,
3e5111
                          VIR_QEMU_PROCESS_START_PAUSED) == 0)
3e5111
         restored = true;
3e5111
@@ -7118,7 +7118,7 @@ qemuDomainObjStart(virConnectPtr conn,
3e5111
         }
3e5111
     }
3e5111
 
3e5111
-    ret = qemuProcessStart(conn, driver, vm, asyncJob,
3e5111
+    ret = qemuProcessStart(conn, driver, vm, NULL, asyncJob,
3e5111
                            NULL, -1, NULL, NULL,
3e5111
                            VIR_NETDEV_VPORT_PROFILE_OP_CREATE, start_flags);
3e5111
     virDomainAuditStart(vm, "booted", ret >= 0);
3e5111
@@ -15295,6 +15295,8 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
3e5111
     virCapsPtr caps = NULL;
3e5111
     bool was_running = false;
3e5111
     bool was_stopped = false;
3e5111
+    qemuDomainSaveCookiePtr cookie;
3e5111
+    virCPUDefPtr origCPU = NULL;
3e5111
 
3e5111
     virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
3e5111
                   VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
3e5111
@@ -15400,6 +15402,8 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
3e5111
             goto endjob;
3e5111
     }
3e5111
 
3e5111
+    cookie = (qemuDomainSaveCookiePtr) snap->def->cookie;
3e5111
+
3e5111
     switch ((virDomainState) snap->def->state) {
3e5111
     case VIR_DOMAIN_RUNNING:
3e5111
     case VIR_DOMAIN_PAUSED:
3e5111
@@ -15411,6 +15415,15 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
3e5111
          * to have finer control.  */
3e5111
         if (virDomainObjIsActive(vm)) {
3e5111
             /* Transitions 5, 6, 8, 9 */
3e5111
+            /* Replace the CPU in config and put the original one in priv
3e5111
+             * once we're done.
3e5111
+             */
3e5111
+            if (cookie && cookie->cpu && config->cpu) {
3e5111
+                origCPU = config->cpu;
3e5111
+                if (!(config->cpu = virCPUDefCopy(cookie->cpu)))
3e5111
+                    goto endjob;
3e5111
+            }
3e5111
+
3e5111
             /* Check for ABI compatibility. We need to do this check against
3e5111
              * the migratable XML or it will always fail otherwise */
3e5111
             if (config &&
3e5111
@@ -15470,8 +15483,11 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
3e5111
                  * failed loadvm attempt? */
3e5111
                 goto endjob;
3e5111
             }
3e5111
-            if (config)
3e5111
+            if (config) {
3e5111
                 virDomainObjAssignDef(vm, config, false, NULL);
3e5111
+                virCPUDefFree(priv->origCPU);
3e5111
+                VIR_STEAL_PTR(priv->origCPU, origCPU);
3e5111
+            }
3e5111
         } else {
3e5111
             /* Transitions 2, 3 */
3e5111
         load:
3e5111
@@ -15480,6 +15496,7 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
3e5111
                 virDomainObjAssignDef(vm, config, false, NULL);
3e5111
 
3e5111
             rc = qemuProcessStart(snapshot->domain->conn, driver, vm,
3e5111
+                                  cookie ? cookie->cpu : NULL,
3e5111
                                   QEMU_ASYNC_JOB_START, NULL, -1, NULL, snap,
3e5111
                                   VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
3e5111
                                   VIR_QEMU_PROCESS_START_PAUSED);
3e5111
@@ -15573,7 +15590,7 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
3e5111
             start_flags |= paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
3e5111
 
3e5111
             qemuDomainEventQueue(driver, event);
3e5111
-            rc = qemuProcessStart(snapshot->domain->conn, driver, vm,
3e5111
+            rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL,
3e5111
                                   QEMU_ASYNC_JOB_START, NULL, -1, NULL, NULL,
3e5111
                                   VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
3e5111
                                   start_flags);
3e5111
@@ -15645,6 +15662,7 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
3e5111
     virObjectUnref(caps);
3e5111
     virObjectUnref(cfg);
3e5111
     virNWFilterUnlockFilterUpdates();
3e5111
+    virCPUDefFree(origCPU);
3e5111
 
3e5111
     return ret;
3e5111
 }
3e5111
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
3e5111
index c03f1be575..a4540ce3c4 100644
3e5111
--- a/src/qemu/qemu_migration.c
3e5111
+++ b/src/qemu/qemu_migration.c
3e5111
@@ -2650,7 +2650,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
3e5111
         goto stopjob;
3e5111
     }
3e5111
 
3e5111
-    if (qemuProcessInit(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN,
3e5111
+    if (qemuProcessInit(driver, vm, mig->cpu, QEMU_ASYNC_JOB_MIGRATION_IN,
3e5111
                         true, VIR_QEMU_PROCESS_START_AUTODESTROY) < 0)
3e5111
         goto stopjob;
3e5111
     stopProcess = true;
3e5111
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
3e5111
index 79f780ed46..a7abfc720e 100644
3e5111
--- a/src/qemu/qemu_process.c
3e5111
+++ b/src/qemu/qemu_process.c
3e5111
@@ -3946,6 +3946,13 @@ qemuProcessUpdateLiveGuestCPU(virQEMUDriverPtr driver,
3e5111
         if (qemuProcessVerifyCPUFeatures(def, cpu) < 0)
3e5111
             goto cleanup;
3e5111
 
3e5111
+        /* Don't update the CPU if we already did so when starting a domain
3e5111
+         * during migration, restore or snapshot revert. */
3e5111
+        if (priv->origCPU) {
3e5111
+            ret = 0;
3e5111
+            goto cleanup;
3e5111
+        }
3e5111
+
3e5111
         if (!(orig = virCPUDefCopy(def->cpu)))
3e5111
             goto cleanup;
3e5111
 
3e5111
@@ -4864,6 +4871,7 @@ qemuProcessStartValidate(virQEMUDriverPtr driver,
3e5111
 int
3e5111
 qemuProcessInit(virQEMUDriverPtr driver,
3e5111
                 virDomainObjPtr vm,
3e5111
+                virCPUDefPtr updatedCPU,
3e5111
                 qemuDomainAsyncJob asyncJob,
3e5111
                 bool migration,
3e5111
                 unsigned int flags)
3e5111
@@ -4872,6 +4880,7 @@ qemuProcessInit(virQEMUDriverPtr driver,
3e5111
     virCapsPtr caps = NULL;
3e5111
     qemuDomainObjPrivatePtr priv = vm->privateData;
3e5111
     int stopFlags;
3e5111
+    virCPUDefPtr origCPU = NULL;
3e5111
     int ret = -1;
3e5111
 
3e5111
     VIR_DEBUG("vm=%p name=%s id=%d migration=%d",
3e5111
@@ -4896,6 +4905,9 @@ qemuProcessInit(virQEMUDriverPtr driver,
3e5111
                                                       vm->def->os.machine)))
3e5111
         goto cleanup;
3e5111
 
3e5111
+    if (qemuDomainUpdateCPU(vm, updatedCPU, &origCPU) < 0)
3e5111
+        goto cleanup;
3e5111
+
3e5111
     if (qemuProcessStartValidate(driver, vm, priv->qemuCaps, caps, flags) < 0)
3e5111
         goto cleanup;
3e5111
 
3e5111
@@ -4928,11 +4940,14 @@ qemuProcessInit(virQEMUDriverPtr driver,
3e5111
 
3e5111
         if (qemuDomainSetPrivatePaths(driver, vm) < 0)
3e5111
             goto stop;
3e5111
+
3e5111
+        VIR_STEAL_PTR(priv->origCPU, origCPU);
3e5111
     }
3e5111
 
3e5111
     ret = 0;
3e5111
 
3e5111
  cleanup:
3e5111
+    virCPUDefFree(origCPU);
3e5111
     virObjectUnref(cfg);
3e5111
     virObjectUnref(caps);
3e5111
     return ret;
3e5111
@@ -5963,6 +5978,7 @@ int
3e5111
 qemuProcessStart(virConnectPtr conn,
3e5111
                  virQEMUDriverPtr driver,
3e5111
                  virDomainObjPtr vm,
3e5111
+                 virCPUDefPtr updatedCPU,
3e5111
                  qemuDomainAsyncJob asyncJob,
3e5111
                  const char *migrateFrom,
3e5111
                  int migrateFd,
3e5111
@@ -5993,7 +6009,8 @@ qemuProcessStart(virConnectPtr conn,
3e5111
     if (!migrateFrom && !snapshot)
3e5111
         flags |= VIR_QEMU_PROCESS_START_NEW;
3e5111
 
3e5111
-    if (qemuProcessInit(driver, vm, asyncJob, !!migrateFrom, flags) < 0)
3e5111
+    if (qemuProcessInit(driver, vm, updatedCPU,
3e5111
+                        asyncJob, !!migrateFrom, flags) < 0)
3e5111
         goto cleanup;
3e5111
 
3e5111
     if (migrateFrom) {
3e5111
@@ -6072,7 +6089,8 @@ qemuProcessCreatePretendCmd(virConnectPtr conn,
3e5111
     flags |= VIR_QEMU_PROCESS_START_PRETEND;
3e5111
     flags |= VIR_QEMU_PROCESS_START_NEW;
3e5111
 
3e5111
-    if (qemuProcessInit(driver, vm, QEMU_ASYNC_JOB_NONE, !!migrateURI, flags) < 0)
3e5111
+    if (qemuProcessInit(driver, vm, NULL, QEMU_ASYNC_JOB_NONE,
3e5111
+                        !!migrateURI, flags) < 0)
3e5111
         goto cleanup;
3e5111
 
3e5111
     if (qemuProcessPrepareDomain(conn, driver, vm, flags) < 0)
3e5111
@@ -6474,6 +6492,8 @@ void qemuProcessStop(virQEMUDriverPtr driver,
3e5111
 
3e5111
     /* clean up migration data */
3e5111
     VIR_FREE(priv->migTLSAlias);
3e5111
+    virCPUDefFree(priv->origCPU);
3e5111
+    priv->origCPU = NULL;
3e5111
 
3e5111
     /* clear previously used namespaces */
3e5111
     virBitmapFree(priv->namespaces);
3e5111
diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h
3e5111
index 830d8cef84..c38310b47a 100644
3e5111
--- a/src/qemu/qemu_process.h
3e5111
+++ b/src/qemu/qemu_process.h
3e5111
@@ -75,6 +75,7 @@ typedef enum {
3e5111
 int qemuProcessStart(virConnectPtr conn,
3e5111
                      virQEMUDriverPtr driver,
3e5111
                      virDomainObjPtr vm,
3e5111
+                     virCPUDefPtr updatedCPU,
3e5111
                      qemuDomainAsyncJob asyncJob,
3e5111
                      const char *migrateFrom,
3e5111
                      int stdin_fd,
3e5111
@@ -93,6 +94,7 @@ virCommandPtr qemuProcessCreatePretendCmd(virConnectPtr conn,
3e5111
 
3e5111
 int qemuProcessInit(virQEMUDriverPtr driver,
3e5111
                     virDomainObjPtr vm,
3e5111
+                    virCPUDefPtr updatedCPU,
3e5111
                     qemuDomainAsyncJob asyncJob,
3e5111
                     bool migration,
3e5111
                     unsigned int flags);
3e5111
-- 
3e5111
2.13.1
3e5111