[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 1/3] Add infrastructure for automatically kill guests with a connection closes



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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]