Sometimes it is useful to be able to automatically kill a guest when a connection is closed. For example, kill an incoming migration if the client managing the migration dies. This introduces a map between guest 'uuid' strings and virConnectPtr objects. When a connection is closed, any associated guests are killed off * src/qemu/qemu_conf.h: Add autokill hash table to qemu driver * src/qemu/qemu_process.c, src/qemu/qemu_process.h: Add APIs for performing autokill of guests associated with a connection * src/qemu/qemu_driver.c: Initialize autokill map --- src/qemu/qemu_conf.h | 5 ++ src/qemu/qemu_driver.c | 17 +++++-- src/qemu/qemu_migration.c | 7 ++- src/qemu/qemu_process.c | 118 +++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_process.h | 12 +++++ 5 files changed, 151 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index bf6dcf4..1f5027d 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 autokill; }; typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 01587e8..44e1fba 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 (qemuProcessAutokillInit(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); + qemuProcessAutokillShutdown(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); + qemuProcessAutokillRun(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) @@ -3465,8 +3472,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) { @@ -3835,8 +3842,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 = @@ -7791,7 +7798,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 87e0417..fbee653 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 b441137..f820ad2 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 @@ -2313,6 +2314,7 @@ int qemuProcessStart(virConnectPtr conn, virDomainObjPtr vm, const char *migrateFrom, bool start_paused, + bool autokill, int stdin_fd, const char *stdin_path, enum virVMOperationType vmop) @@ -2699,6 +2701,10 @@ int qemuProcessStart(virConnectPtr conn, VIR_DOMAIN_PAUSED_USER); } + if (autokill && + qemuProcessAutokillAdd(driver, vm, conn) < 0) + goto cleanup; + VIR_DEBUG("Writing domain status to disk"); if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) goto cleanup; @@ -2839,6 +2845,9 @@ void qemuProcessStop(struct qemud_driver *driver, /* shut it off for sure */ qemuProcessKill(vm); + /* Stop autokill in case guest is restarted */ + qemuProcessAutokillRemove(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); @@ -2941,3 +2950,112 @@ retry: virFreeError(orig_err); } } + + +int qemuProcessAutokillInit(struct qemud_driver *driver) +{ + if (!(driver->autokill = virHashCreate(5, NULL))) + return -1; + + return 0; +} + +struct qemuProcessAutokillData { + struct qemud_driver *driver; + virConnectPtr conn; +}; + +static void qemuProcessAutokillDom(void *payload, const void *name, void *opaque) +{ + struct qemuProcessAutokillData *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->autokill, uuidstr); +} + +/* + * Precondition: driver is locked + */ +void qemuProcessAutokillRun(struct qemud_driver *driver, virConnectPtr conn) +{ + struct qemuProcessAutokillData data = { + driver, conn + }; + VIR_DEBUG("conn=%p", conn); + virHashForEach(driver->autokill, qemuProcessAutokillDom, &data); +} + +void qemuProcessAutokillShutdown(struct qemud_driver *driver) +{ + virHashFree(driver->autokill); +} + +int qemuProcessAutokillAdd(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->autokill, uuidstr, conn) < 0) + return -1; + return 0; +} + +int qemuProcessAutokillRemove(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->autokill, uuidstr) < 0) + return -1; + return 0; +} diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 7ec9d7d..a5478f1 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 autokill, 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 qemuProcessAutokillInit(struct qemud_driver *driver); +void qemuProcessAutokillRun(struct qemud_driver *driver, + virConnectPtr conn); +void qemuProcessAutokillShutdown(struct qemud_driver *driver); +int qemuProcessAutokillAdd(struct qemud_driver *driver, + virDomainObjPtr vm, + virConnectPtr conn); +int qemuProcessAutokillRemove(struct qemud_driver *driver, + virDomainObjPtr vm); + + #endif /* __QEMU_PROCESS_H__ */ -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list