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