diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 625c59546f..a9469cf4c7 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -232,6 +232,7 @@ static void qemuDomainObjPrivateFree(void *data) VIR_ERROR(_("Unexpected QEMU agent still active during domain deletion")); qemuAgentClose(priv->agent); } + VIR_FREE(priv->cleanupCallbacks); VIR_FREE(priv); } @@ -1769,3 +1770,75 @@ qemuDomainCheckDiskPresence(struct qemud_driver *driver, cleanup: return ret; } + +/* + * The vm must be locked when any of the following cleanup functions is + * called. + */ +int +qemuDomainCleanupAdd(virDomainObjPtr vm, + qemuDomainCleanupCallback cb) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + int i; + + VIR_DEBUG("vm=%s, cb=%p", vm->def->name, cb); + + for (i = 0; i < priv->ncleanupCallbacks; i++) { + if (priv->cleanupCallbacks[i] == cb) + return 0; + } + + if (VIR_RESIZE_N(priv->cleanupCallbacks, + priv->ncleanupCallbacks_max, + priv->ncleanupCallbacks, 1) < 0) { + virReportOOMError(); + return -1; + } + + priv->cleanupCallbacks[priv->ncleanupCallbacks++] = cb; + return 0; +} + +void +qemuDomainCleanupRemove(virDomainObjPtr vm, + qemuDomainCleanupCallback cb) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + int i; + + VIR_DEBUG("vm=%s, cb=%p", vm->def->name, cb); + + for (i = 0; i < priv->ncleanupCallbacks; i++) { + if (priv->cleanupCallbacks[i] == cb) { + memmove(priv->cleanupCallbacks + i, + priv->cleanupCallbacks + i + 1, + priv->ncleanupCallbacks - i - 1); + priv->ncleanupCallbacks--; + } + } + + VIR_SHRINK_N(priv->cleanupCallbacks, + priv->ncleanupCallbacks_max, + priv->ncleanupCallbacks_max - priv->ncleanupCallbacks); +} + +void +qemuDomainCleanupRun(struct qemud_driver *driver, + virDomainObjPtr vm) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + int i; + + VIR_DEBUG("driver=%p, vm=%s", driver, vm->def->name); + + /* run cleanup callbacks in reverse order */ + for (i = priv->ncleanupCallbacks - 1; i >= 0; i--) { + if (priv->cleanupCallbacks[i]) + priv->cleanupCallbacks[i](driver, vm); + } + + VIR_FREE(priv->cleanupCallbacks); + priv->ncleanupCallbacks = 0; + priv->ncleanupCallbacks_max = 0; +} diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index be9e34df6c..4fdec6255f 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -101,6 +101,9 @@ struct qemuDomainJobObj { typedef struct _qemuDomainPCIAddressSet qemuDomainPCIAddressSet; typedef qemuDomainPCIAddressSet *qemuDomainPCIAddressSetPtr; +typedef void (*qemuDomainCleanupCallback)(struct qemud_driver *driver, + virDomainObjPtr vm); + typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate; typedef qemuDomainObjPrivate *qemuDomainObjPrivatePtr; struct _qemuDomainObjPrivate { @@ -137,6 +140,10 @@ struct _qemuDomainObjPrivate { char *origname; virConsolesPtr cons; + + qemuDomainCleanupCallback *cleanupCallbacks; + size_t ncleanupCallbacks; + size_t ncleanupCallbacks_max; }; struct qemuDomainWatchdogEvent @@ -314,4 +321,12 @@ bool qemuDomainJobAllowed(qemuDomainObjPrivatePtr priv, int qemuDomainCheckDiskPresence(struct qemud_driver *driver, virDomainObjPtr vm, bool start_with_state); + +int qemuDomainCleanupAdd(virDomainObjPtr vm, + qemuDomainCleanupCallback cb); +void qemuDomainCleanupRemove(virDomainObjPtr vm, + qemuDomainCleanupCallback cb); +void qemuDomainCleanupRun(struct qemud_driver *driver, + virDomainObjPtr vm); + #endif /* __QEMU_DOMAIN_H__ */ diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 0af3751a6e..19458644f5 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3803,6 +3803,8 @@ void qemuProcessStop(struct qemud_driver *driver, /* shut it off for sure */ ignore_value(qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE)); + qemuDomainCleanupRun(driver, vm); + /* Stop autodestroy in case guest is restarted */ qemuProcessAutoDestroyRemove(driver, vm);