]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: Use updated CPU when starting QEMU if possible
authorJiri Denemark <jdenemar@redhat.com>
Wed, 31 May 2017 10:34:10 +0000 (12:34 +0200)
committerJiri Denemark <jdenemar@redhat.com>
Wed, 7 Jun 2017 11:36:02 +0000 (13:36 +0200)
If QEMU is new enough and we have the live updated CPU definition in
either save or migration cookie, we can use it to enforce ABI. The
original guest CPU from domain XML will be stored in private data.

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
src/qemu/qemu_domain.c
src/qemu/qemu_domain.h
src/qemu/qemu_driver.c
src/qemu/qemu_migration.c
src/qemu/qemu_process.c
src/qemu/qemu_process.h

index ec43d06d73f9d893dbe0e1992080c886b008f8ab..2aa3aaa47eb02c39b42c05ecc61a0dedb163f316 100644 (file)
@@ -9240,3 +9240,43 @@ virSaveCookieCallbacks virQEMUDriverDomainSaveCookie = {
     .parse = qemuDomainSaveCookieParse,
     .format = qemuDomainSaveCookieFormat,
 };
+
+
+/**
+ * qemuDomainUpdateCPU:
+ * @vm: domain which is being started
+ * @cpu: CPU updated when the domain was running previously (before migration,
+ *       snapshot, or save)
+ * @origCPU: where to store the original CPU from vm->def in case @cpu was
+ *           used instead
+ *
+ * Replace the CPU definition with the updated one when QEMU is new enough to
+ * allow us to check extra features it is about to enable or disable when
+ * starting a domain. The original CPU is stored in @origCPU.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int
+qemuDomainUpdateCPU(virDomainObjPtr vm,
+                    virCPUDefPtr cpu,
+                    virCPUDefPtr *origCPU)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+
+    *origCPU = NULL;
+
+    if (!cpu || !vm->def->cpu ||
+        !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION) ||
+        virCPUDefIsEqual(vm->def->cpu, cpu, false))
+        return 0;
+
+    if (!(cpu = virCPUDefCopy(cpu)))
+        return -1;
+
+    VIR_DEBUG("Replacing CPU def with the updated one");
+
+    *origCPU = vm->def->cpu;
+    vm->def->cpu = cpu;
+
+    return 0;
+}
index 44c466cb75dcefdc77e3381e9718413f5162db17..ef3a33076c70071c0c2d8583934332225b9b997d 100644 (file)
@@ -919,4 +919,9 @@ char *qemuDomainDiskBackingStoreGetName(virDomainDiskDefPtr disk,
 virStorageSourcePtr qemuDomainGetStorageSourceByDevstr(const char *devstr,
                                                        virDomainDefPtr def);
 
+int
+qemuDomainUpdateCPU(virDomainObjPtr vm,
+                    virCPUDefPtr cpu,
+                    virCPUDefPtr *origCPU);
+
 #endif /* __QEMU_DOMAIN_H__ */
index 2e23cbdc03ea11ac26a1493bef261f11d6f4e4a3..1e3c7fca0e5e79e4a5bd616eee7369a85d1fb428 100644 (file)
@@ -1779,7 +1779,7 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn,
         goto cleanup;
     }
 
-    if (qemuProcessStart(conn, driver, vm, QEMU_ASYNC_JOB_START,
+    if (qemuProcessStart(conn, driver, vm, NULL, QEMU_ASYNC_JOB_START,
                          NULL, -1, NULL, NULL,
                          VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                          start_flags) < 0) {
@@ -6506,8 +6506,8 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
         }
     }
 
-    if (qemuProcessStart(conn, driver, vm, asyncJob,
-                         "stdio", *fd, path, NULL,
+    if (qemuProcessStart(conn, driver, vm, cookie ? cookie->cpu : NULL,
+                         asyncJob, "stdio", *fd, path, NULL,
                          VIR_NETDEV_VPORT_PROFILE_OP_RESTORE,
                          VIR_QEMU_PROCESS_START_PAUSED) == 0)
         restored = true;
@@ -7124,7 +7124,7 @@ qemuDomainObjStart(virConnectPtr conn,
         }
     }
 
-    ret = qemuProcessStart(conn, driver, vm, asyncJob,
+    ret = qemuProcessStart(conn, driver, vm, NULL, asyncJob,
                            NULL, -1, NULL, NULL,
                            VIR_NETDEV_VPORT_PROFILE_OP_CREATE, start_flags);
     virDomainAuditStart(vm, "booted", ret >= 0);
@@ -15294,6 +15294,8 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
     virCapsPtr caps = NULL;
     bool was_running = false;
     bool was_stopped = false;
+    qemuDomainSaveCookiePtr cookie;
+    virCPUDefPtr origCPU = NULL;
 
     virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
                   VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
@@ -15399,6 +15401,8 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
             goto endjob;
     }
 
+    cookie = (qemuDomainSaveCookiePtr) snap->def->cookie;
+
     switch ((virDomainState) snap->def->state) {
     case VIR_DOMAIN_RUNNING:
     case VIR_DOMAIN_PAUSED:
@@ -15410,6 +15414,15 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
          * to have finer control.  */
         if (virDomainObjIsActive(vm)) {
             /* Transitions 5, 6, 8, 9 */
+            /* Replace the CPU in config and put the original one in priv
+             * once we're done.
+             */
+            if (cookie && cookie->cpu && config->cpu) {
+                origCPU = config->cpu;
+                if (!(config->cpu = virCPUDefCopy(cookie->cpu)))
+                    goto endjob;
+            }
+
             /* Check for ABI compatibility. We need to do this check against
              * the migratable XML or it will always fail otherwise */
             if (config &&
@@ -15469,8 +15482,11 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
                  * failed loadvm attempt? */
                 goto endjob;
             }
-            if (config)
+            if (config) {
                 virDomainObjAssignDef(vm, config, false, NULL);
+                virCPUDefFree(priv->origCPU);
+                VIR_STEAL_PTR(priv->origCPU, origCPU);
+            }
         } else {
             /* Transitions 2, 3 */
         load:
@@ -15479,6 +15495,7 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
                 virDomainObjAssignDef(vm, config, false, NULL);
 
             rc = qemuProcessStart(snapshot->domain->conn, driver, vm,
+                                  cookie ? cookie->cpu : NULL,
                                   QEMU_ASYNC_JOB_START, NULL, -1, NULL, snap,
                                   VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                   VIR_QEMU_PROCESS_START_PAUSED);
@@ -15572,7 +15589,7 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
             start_flags |= paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
 
             qemuDomainEventQueue(driver, event);
-            rc = qemuProcessStart(snapshot->domain->conn, driver, vm,
+            rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL,
                                   QEMU_ASYNC_JOB_START, NULL, -1, NULL, NULL,
                                   VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                   start_flags);
@@ -15644,6 +15661,7 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
     virObjectUnref(caps);
     virObjectUnref(cfg);
     virNWFilterUnlockFilterUpdates();
+    virCPUDefFree(origCPU);
 
     return ret;
 }
index 134c76c5e1381f5709534dd26b95dd605e14a09d..505e61e5f4a71f685f956bc38d2b51a8cec27442 100644 (file)
@@ -2681,7 +2681,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
         goto stopjob;
     }
 
-    if (qemuProcessInit(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN,
+    if (qemuProcessInit(driver, vm, mig->cpu, QEMU_ASYNC_JOB_MIGRATION_IN,
                         true, VIR_QEMU_PROCESS_START_AUTODESTROY) < 0)
         goto stopjob;
     stopProcess = true;
index c06349474710448d8580d8e67ba60f612993c0f7..4a66f0d5d6b30d0656c976009303f71b7164ec96 100644 (file)
@@ -3946,6 +3946,13 @@ qemuProcessUpdateLiveGuestCPU(virQEMUDriverPtr driver,
         if (qemuProcessVerifyCPUFeatures(def, cpu) < 0)
             goto cleanup;
 
+        /* Don't update the CPU if we already did so when starting a domain
+         * during migration, restore or snapshot revert. */
+        if (priv->origCPU) {
+            ret = 0;
+            goto cleanup;
+        }
+
         if (!(orig = virCPUDefCopy(def->cpu)))
             goto cleanup;
 
@@ -4864,6 +4871,7 @@ qemuProcessStartValidate(virQEMUDriverPtr driver,
 int
 qemuProcessInit(virQEMUDriverPtr driver,
                 virDomainObjPtr vm,
+                virCPUDefPtr updatedCPU,
                 qemuDomainAsyncJob asyncJob,
                 bool migration,
                 unsigned int flags)
@@ -4872,6 +4880,7 @@ qemuProcessInit(virQEMUDriverPtr driver,
     virCapsPtr caps = NULL;
     qemuDomainObjPrivatePtr priv = vm->privateData;
     int stopFlags;
+    virCPUDefPtr origCPU = NULL;
     int ret = -1;
 
     VIR_DEBUG("vm=%p name=%s id=%d migration=%d",
@@ -4896,6 +4905,9 @@ qemuProcessInit(virQEMUDriverPtr driver,
                                                       vm->def->os.machine)))
         goto cleanup;
 
+    if (qemuDomainUpdateCPU(vm, updatedCPU, &origCPU) < 0)
+        goto cleanup;
+
     if (qemuProcessStartValidate(driver, vm, priv->qemuCaps, caps, flags) < 0)
         goto cleanup;
 
@@ -4928,11 +4940,14 @@ qemuProcessInit(virQEMUDriverPtr driver,
 
         if (qemuDomainSetPrivatePaths(driver, vm) < 0)
             goto stop;
+
+        VIR_STEAL_PTR(priv->origCPU, origCPU);
     }
 
     ret = 0;
 
  cleanup:
+    virCPUDefFree(origCPU);
     virObjectUnref(cfg);
     virObjectUnref(caps);
     return ret;
@@ -5963,6 +5978,7 @@ int
 qemuProcessStart(virConnectPtr conn,
                  virQEMUDriverPtr driver,
                  virDomainObjPtr vm,
+                 virCPUDefPtr updatedCPU,
                  qemuDomainAsyncJob asyncJob,
                  const char *migrateFrom,
                  int migrateFd,
@@ -5993,7 +6009,8 @@ qemuProcessStart(virConnectPtr conn,
     if (!migrateFrom && !snapshot)
         flags |= VIR_QEMU_PROCESS_START_NEW;
 
-    if (qemuProcessInit(driver, vm, asyncJob, !!migrateFrom, flags) < 0)
+    if (qemuProcessInit(driver, vm, updatedCPU,
+                        asyncJob, !!migrateFrom, flags) < 0)
         goto cleanup;
 
     if (migrateFrom) {
@@ -6072,7 +6089,8 @@ qemuProcessCreatePretendCmd(virConnectPtr conn,
     flags |= VIR_QEMU_PROCESS_START_PRETEND;
     flags |= VIR_QEMU_PROCESS_START_NEW;
 
-    if (qemuProcessInit(driver, vm, QEMU_ASYNC_JOB_NONE, !!migrateURI, flags) < 0)
+    if (qemuProcessInit(driver, vm, NULL, QEMU_ASYNC_JOB_NONE,
+                        !!migrateURI, flags) < 0)
         goto cleanup;
 
     if (qemuProcessPrepareDomain(conn, driver, vm, flags) < 0)
@@ -6476,6 +6494,8 @@ void qemuProcessStop(virQEMUDriverPtr driver,
 
     /* clean up migration data */
     VIR_FREE(priv->migTLSAlias);
+    virCPUDefFree(priv->origCPU);
+    priv->origCPU = NULL;
 
     /* clear previously used namespaces */
     virBitmapFree(priv->namespaces);
index 830d8cef84cfa557ef14b49e92f032f9f0fa8e82..c38310b47a8539129fda07ebb1ef560173162b9a 100644 (file)
@@ -75,6 +75,7 @@ typedef enum {
 int qemuProcessStart(virConnectPtr conn,
                      virQEMUDriverPtr driver,
                      virDomainObjPtr vm,
+                     virCPUDefPtr updatedCPU,
                      qemuDomainAsyncJob asyncJob,
                      const char *migrateFrom,
                      int stdin_fd,
@@ -93,6 +94,7 @@ virCommandPtr qemuProcessCreatePretendCmd(virConnectPtr conn,
 
 int qemuProcessInit(virQEMUDriverPtr driver,
                     virDomainObjPtr vm,
+                    virCPUDefPtr updatedCPU,
                     qemuDomainAsyncJob asyncJob,
                     bool migration,
                     unsigned int flags);