diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index bf6dcf4275..fa4c607d4a 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -127,6 +127,11 @@ struct qemud_driver { virSysinfoDefPtr hostsysinfo; virLockManagerPluginPtr lockManager; + + /* Mapping of 'char *uuidstr' -> virConnectPtr + * of guests which will be automatically killed + * when the virConnectPtr is closed*/ + virHashTablePtr autodestroy; }; typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 18fa4e0cd8..e73f0d715a 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -603,6 +603,9 @@ qemudStartup(int privileged) { qemu_driver->hugepage_path = mempath; } + if (qemuProcessAutoDestroyInit(qemu_driver) < 0) + goto error; + /* Get all the running persistent or transient configs first */ if (virDomainLoadAllConfigs(qemu_driver->caps, &qemu_driver->domains, @@ -736,6 +739,8 @@ qemudShutdown(void) { virSysinfoDefFree(qemu_driver->hostsysinfo); + qemuProcessAutoDestroyShutdown(qemu_driver); + VIR_FREE(qemu_driver->configDir); VIR_FREE(qemu_driver->autostartDir); VIR_FREE(qemu_driver->logDir); @@ -860,6 +865,7 @@ static int qemudClose(virConnectPtr conn) { qemuDriverLock(driver); virDomainEventCallbackListRemoveConn(conn, driver->domainEventState->callbacks); + qemuProcessAutoDestroyRun(driver, conn); qemuDriverUnlock(driver); conn->privateData = NULL; @@ -1271,6 +1277,7 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml, if (qemuProcessStart(conn, driver, vm, NULL, (flags & VIR_DOMAIN_START_PAUSED) != 0, + false, -1, NULL, VIR_VM_OP_CREATE) < 0) { qemuAuditDomainStart(vm, "booted", false); if (qemuDomainObjEndJob(vm) > 0) @@ -3528,8 +3535,8 @@ qemuDomainSaveImageStartVM(virConnectPtr conn, } /* Set the migration source and start it up. */ - ret = qemuProcessStart(conn, driver, vm, "stdio", true, *fd, path, - VIR_VM_OP_RESTORE); + ret = qemuProcessStart(conn, driver, vm, "stdio", true, + false, *fd, path, VIR_VM_OP_RESTORE); if (intermediatefd != -1) { if (ret < 0) { @@ -3898,8 +3905,8 @@ static int qemudDomainObjStart(virConnectPtr conn, goto cleanup; } - ret = qemuProcessStart(conn, driver, vm, NULL, start_paused, -1, NULL, - VIR_VM_OP_CREATE); + ret = qemuProcessStart(conn, driver, vm, NULL, start_paused, + false, -1, NULL, VIR_VM_OP_CREATE); qemuAuditDomainStart(vm, "booted", ret >= 0); if (ret >= 0) { virDomainEventPtr event = @@ -7854,7 +7861,7 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, goto endjob; rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL, - false, -1, NULL, VIR_VM_OP_CREATE); + false, false, -1, NULL, VIR_VM_OP_CREATE); qemuAuditDomainStart(vm, "from-snapshot", rc >= 0); if (qemuDomainSnapshotSetCurrentInactive(vm, driver->snapshotDir) < 0) goto endjob; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 87e0417120..fbee653834 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1119,8 +1119,9 @@ qemuMigrationPrepareTunnel(struct qemud_driver *driver, /* Start the QEMU daemon, with the same command-line arguments plus * -incoming stdio (which qemu_command might convert to exec:cat or fd:n) */ - internalret = qemuProcessStart(dconn, driver, vm, "stdio", true, dataFD[0], - NULL, VIR_VM_OP_MIGRATE_IN_START); + internalret = qemuProcessStart(dconn, driver, vm, "stdio", true, + false, dataFD[0], NULL, + VIR_VM_OP_MIGRATE_IN_START); if (internalret < 0) { qemuAuditDomainStart(vm, "migrated", false); /* Note that we don't set an error here because qemuProcessStart @@ -1347,7 +1348,7 @@ qemuMigrationPrepareDirect(struct qemud_driver *driver, * -incoming tcp:0.0.0.0:port */ snprintf (migrateFrom, sizeof (migrateFrom), "tcp:0.0.0.0:%d", this_port); - if (qemuProcessStart(dconn, driver, vm, migrateFrom, true, + if (qemuProcessStart(dconn, driver, vm, migrateFrom, true, false, -1, NULL, VIR_VM_OP_MIGRATE_IN_START) < 0) { qemuAuditDomainStart(vm, "migrated", false); /* Note that we don't set an error here because qemuProcessStart diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index f8f95e2db0..b4b745e3c9 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -55,6 +55,7 @@ #include "processinfo.h" #include "domain_nwfilter.h" #include "locking/domain_lock.h" +#include "uuid.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -2408,6 +2409,7 @@ int qemuProcessStart(virConnectPtr conn, virDomainObjPtr vm, const char *migrateFrom, bool start_paused, + bool autodestroy, int stdin_fd, const char *stdin_path, enum virVMOperationType vmop) @@ -2795,6 +2797,10 @@ int qemuProcessStart(virConnectPtr conn, VIR_DOMAIN_PAUSED_USER); } + if (autodestroy && + qemuProcessAutoDestroyAdd(driver, vm, conn) < 0) + goto cleanup; + VIR_DEBUG("Writing domain status to disk"); if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) goto cleanup; @@ -2935,6 +2941,9 @@ void qemuProcessStop(struct qemud_driver *driver, /* shut it off for sure */ qemuProcessKill(vm); + /* Stop autodestroy in case guest is restarted */ + qemuProcessAutoDestroyRemove(driver, vm); + /* now that we know it's stopped call the hook if present */ if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { char *xml = virDomainDefFormat(vm->def, 0); @@ -3037,3 +3046,115 @@ retry: virFreeError(orig_err); } } + + +int qemuProcessAutoDestroyInit(struct qemud_driver *driver) +{ + if (!(driver->autodestroy = virHashCreate(5, NULL))) + return -1; + + return 0; +} + +struct qemuProcessAutoDestroyData { + struct qemud_driver *driver; + virConnectPtr conn; +}; + +static void qemuProcessAutoDestroyDom(void *payload, + const void *name, + void *opaque) +{ + struct qemuProcessAutoDestroyData *data = opaque; + virConnectPtr conn = payload; + const char *uuidstr = name; + unsigned char uuid[VIR_UUID_BUFLEN]; + virDomainObjPtr dom; + qemuDomainObjPrivatePtr priv; + virDomainEventPtr event = NULL; + + VIR_DEBUG("conn=%p uuidstr=%s thisconn=%p", conn, uuidstr, data->conn); + + if (data->conn != conn) + return; + + if (virUUIDParse(uuidstr, uuid) < 0) { + VIR_WARN("Failed to parse %s", uuidstr); + return; + } + + if (!(dom = virDomainFindByUUID(&data->driver->domains, + uuid))) { + VIR_DEBUG("No domain object to kill"); + return; + } + + priv = dom->privateData; + if (priv->jobActive == QEMU_JOB_MIGRATION_IN) { + VIR_DEBUG("vm=%s has incoming migration active, cancelling", + dom->def->name); + priv->jobActive = QEMU_JOB_NONE; + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); + } + + if (qemuDomainObjBeginJobWithDriver(data->driver, dom) < 0) + goto cleanup; + + VIR_DEBUG("Killing domain"); + qemuProcessStop(data->driver, dom, 1, VIR_DOMAIN_SHUTOFF_DESTROYED); + qemuAuditDomainStop(dom, "destroyed"); + event = virDomainEventNewFromObj(dom, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_DESTROYED); + if (qemuDomainObjEndJob(dom) == 0) + dom = NULL; + if (dom && !dom->persistent) + virDomainRemoveInactive(&data->driver->domains, dom); + +cleanup: + if (dom) + virDomainObjUnlock(dom); + if (event) + qemuDomainEventQueue(data->driver, event); + virHashRemoveEntry(data->driver->autodestroy, uuidstr); +} + +/* + * Precondition: driver is locked + */ +void qemuProcessAutoDestroyRun(struct qemud_driver *driver, virConnectPtr conn) +{ + struct qemuProcessAutoDestroyData data = { + driver, conn + }; + VIR_DEBUG("conn=%p", conn); + virHashForEach(driver->autodestroy, qemuProcessAutoDestroyDom, &data); +} + +void qemuProcessAutoDestroyShutdown(struct qemud_driver *driver) +{ + virHashFree(driver->autodestroy); +} + +int qemuProcessAutoDestroyAdd(struct qemud_driver *driver, + virDomainObjPtr vm, + virConnectPtr conn) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(vm->def->uuid, uuidstr); + VIR_DEBUG("vm=%s uuid=%s conn=%p", vm->def->name, uuidstr, conn); + if (virHashAddEntry(driver->autodestroy, uuidstr, conn) < 0) + return -1; + return 0; +} + +int qemuProcessAutoDestroyRemove(struct qemud_driver *driver, + virDomainObjPtr vm) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(vm->def->uuid, uuidstr); + VIR_DEBUG("vm=%s uuid=%s", vm->def->name, uuidstr); + if (virHashRemoveEntry(driver->autodestroy, uuidstr) < 0) + return -1; + return 0; +} diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 7ec9d7d70d..7c5e8e803a 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -46,6 +46,7 @@ int qemuProcessStart(virConnectPtr conn, virDomainObjPtr vm, const char *migrateFrom, bool start_paused, + bool autodestroy, int stdin_fd, const char *stdin_path, enum virVMOperationType vmop); @@ -57,4 +58,15 @@ void qemuProcessStop(struct qemud_driver *driver, void qemuProcessKill(virDomainObjPtr vm); +int qemuProcessAutoDestroyInit(struct qemud_driver *driver); +void qemuProcessAutoDestroyRun(struct qemud_driver *driver, + virConnectPtr conn); +void qemuProcessAutoDestroyShutdown(struct qemud_driver *driver); +int qemuProcessAutoDestroyAdd(struct qemud_driver *driver, + virDomainObjPtr vm, + virConnectPtr conn); +int qemuProcessAutoDestroyRemove(struct qemud_driver *driver, + virDomainObjPtr vm); + + #endif /* __QEMU_PROCESS_H__ */