There are few function calls done while cleaning up a stopped VM which do require the old VM id, to e.g. clean up paths containing the 'short' domain name in the path. Anything else, which doesn't strictly require it can be moved after clearing the 'id' in order to decrease likelyhood of potential bugs. This patch moves all the code which does not require the 'id' (except for the log entry and closing the monitor socket) after the statement clearing the id and adds a comment explaining that anything in the section must not unlock the VM object. Signed-off-by: Peter Krempa <pkrempa@xxxxxxxxxx> --- src/qemu/qemu_process.c | 85 ++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index aef83d2409..3187f0a9a2 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8482,10 +8482,11 @@ void qemuProcessStop(virQEMUDriver *driver, goto endjob; } - qemuProcessBuildDestroyMemoryPaths(driver, vm, NULL, false); - - if (!!g_atomic_int_dec_and_test(&driver->nactive) && driver->inhibitCallback) - driver->inhibitCallback(false, driver->inhibitOpaque); + /* BEWARE: At this point 'vm->def->id' is not cleared yet. Any code that + * requires the id (e.g. to call virDomainDefGetShortName()) must be placed + * between here (after the VM is killed) and the statement clearing the id. + * The code *MUST NOT* unlock vm, otherwise other code might be confused + * about the state of the VM. */ if ((timestamp = virTimeStringNow()) != NULL) { qemuDomainLogAppendMessage(driver, vm, "%s: shutting down, reason=%s\n", @@ -8493,6 +8494,47 @@ void qemuProcessStop(virQEMUDriver *driver, virDomainShutoffReasonTypeToString(reason)); } + /* shut it off for sure */ + ignore_value(qemuProcessKill(vm, + VIR_QEMU_PROCESS_KILL_FORCE| + VIR_QEMU_PROCESS_KILL_NOCHECK)); + + if (priv->agent) { + g_clear_pointer(&priv->agent, qemuAgentClose); + } + priv->agentError = false; + + if (priv->mon) { + g_clear_pointer(&priv->mon, qemuMonitorClose); + } + + qemuProcessBuildDestroyMemoryPaths(driver, vm, NULL, false); + + /* Do this before we delete the tree and remove pidfile. */ + qemuProcessKillManagedPRDaemon(vm); + + qemuDomainCleanupRun(driver, vm); + + outgoingMigration = (flags & VIR_QEMU_PROCESS_STOP_MIGRATED) && + (asyncJob == VIR_ASYNC_JOB_MIGRATION_OUT); + + qemuExtDevicesStop(driver, vm, outgoingMigration); + + qemuDBusStop(driver, vm); + + vm->def->id = -1; + + /* Wake up anything waiting on domain condition */ + virDomainObjBroadcast(vm); + + /* IMPORTANT: qemuDomainObjStopWorker() unlocks @vm in order to prevent + * deadlocks with the per-VM event loop thread. This MUST be done after + * marking the VM as dead */ + qemuDomainObjStopWorker(vm); + + if (!!g_atomic_int_dec_and_test(&driver->nactive) && driver->inhibitCallback) + driver->inhibitCallback(false, driver->inhibitOpaque); + /* Clear network bandwidth */ virDomainClearNetBandwidth(vm->def); @@ -8512,15 +8554,6 @@ void qemuProcessStop(virQEMUDriver *driver, virPortAllocatorRelease(priv->nbdPort); priv->nbdPort = 0; - if (priv->agent) { - g_clear_pointer(&priv->agent, qemuAgentClose); - } - priv->agentError = false; - - if (priv->mon) { - g_clear_pointer(&priv->mon, qemuMonitorClose); - } - if (priv->monConfig) { if (priv->monConfig->type == VIR_DOMAIN_CHR_TYPE_UNIX) unlink(priv->monConfig->data.nix.path); @@ -8530,41 +8563,15 @@ void qemuProcessStop(virQEMUDriver *driver, /* Remove the master key */ qemuDomainMasterKeyRemove(priv); - /* Do this before we delete the tree and remove pidfile. */ - qemuProcessKillManagedPRDaemon(vm); - ignore_value(virDomainChrDefForeach(vm->def, false, qemuProcessCleanupChardevDevice, NULL)); - /* shut it off for sure */ - ignore_value(qemuProcessKill(vm, - VIR_QEMU_PROCESS_KILL_FORCE| - VIR_QEMU_PROCESS_KILL_NOCHECK)); - /* Its namespace is also gone then. */ qemuDomainDestroyNamespace(driver, vm); - qemuDomainCleanupRun(driver, vm); - - outgoingMigration = (flags & VIR_QEMU_PROCESS_STOP_MIGRATED) && - (asyncJob == VIR_ASYNC_JOB_MIGRATION_OUT); - qemuExtDevicesStop(driver, vm, outgoingMigration); - - qemuDBusStop(driver, vm); - - vm->def->id = -1; - - /* Wake up anything waiting on domain condition */ - virDomainObjBroadcast(vm); - - /* IMPORTANT: qemuDomainObjStopWorker() unlocks @vm in order to prevent - * deadlocks with the per-VM event loop thread. This MUST be done after - * marking the VM as dead */ - qemuDomainObjStopWorker(vm); - virFileDeleteTree(priv->libDir); virFileDeleteTree(priv->channelTargetDir); -- 2.45.2