diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index ec43d06d73..2aa3aaa47e 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -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; +} diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 44c466cb75..ef3a33076c 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -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__ */ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2e23cbdc03..1e3c7fca0e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -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; } diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 134c76c5e1..505e61e5f4 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -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; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index c063494747..4a66f0d5d6 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -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); diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 830d8cef84..c38310b47a 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -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);