Add support for registering arbitrary callback to be called for a domain
when a connection gets closed.
---
 src/qemu/qemu_conf.c   |  172 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_conf.h   |   27 ++++++++
 src/qemu/qemu_driver.c |    5 ++
 3 files changed, 204 insertions(+), 0 deletions(-)

diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index a709cbf..88a04bc 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -56,6 +56,11 @@
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
+struct _qemuDriverCloseDef {
+    virConnectPtr conn;
+    qemuDriverCloseCallback cb;
+};
+
 void qemuDriverLock(struct qemud_driver *driver)
 {
     virMutexLock(&driver->lock);
@@ -490,3 +495,170 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
     virConfFree (conf);
     return 0;
 }
+
+static void
+qemuDriverCloseCallbackFree(void *payload,
+                            const void *name ATTRIBUTE_UNUSED)
+{
+    VIR_FREE(payload);
+}
+
+int
+qemuDriverCloseCallbackInit(struct qemud_driver *driver)
+{
+    driver->closeCallbacks = virHashCreate(5, qemuDriverCloseCallbackFree);
+    if (!driver->closeCallbacks)
+        return -1;
+
+    return 0;
+}
+
+void
+qemuDriverCloseCallbackShutdown(struct qemud_driver *driver)
+{
+    virHashFree(driver->closeCallbacks);
+}
+
+int
+qemuDriverCloseCallbackSet(struct qemud_driver *driver,
+                           virDomainObjPtr vm,
+                           virConnectPtr conn,
+                           qemuDriverCloseCallback cb)
+{
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    qemuDriverCloseDefPtr closeDef;
+
+    virUUIDFormat(vm->def->uuid, uuidstr);
+    VIR_DEBUG("vm=%s, uuid=%s, conn=%p, cb=%p",
+              vm->def->name, uuidstr, conn, cb);
+
+    closeDef = virHashLookup(driver->closeCallbacks, uuidstr);
+    if (closeDef) {
+        if (closeDef->conn != conn) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("Close callback for domain %s already registered"
+                              " with another connection %p"),
+                            vm->def->name, closeDef->conn);
+            return -1;
+        }
+        if (closeDef->cb && closeDef->cb != cb) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("Another close callback is already defined for"
+                              " domain %s"), vm->def->name);
+            return -1;
+        }
+
+        closeDef->cb = cb;
+    } else {
+        if (VIR_ALLOC(closeDef) < 0) {
+            virReportOOMError();
+            return -1;
+        }
+
+        closeDef->conn = conn;
+        closeDef->cb = cb;
+        if (virHashAddEntry(driver->closeCallbacks, uuidstr, closeDef) < 0) {
+            VIR_FREE(closeDef);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+int
+qemuDriverCloseCallbackUnset(struct qemud_driver *driver,
+                             virDomainObjPtr vm,
+                             qemuDriverCloseCallback cb)
+{
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    qemuDriverCloseDefPtr closeDef;
+
+    virUUIDFormat(vm->def->uuid, uuidstr);
+    VIR_DEBUG("vm=%s, uuid=%s, cb=%p",
+              vm->def->name, uuidstr, cb);
+
+    closeDef = virHashLookup(driver->closeCallbacks, uuidstr);
+    if (!closeDef)
+        return -1;
+
+    if (closeDef->cb && closeDef->cb != cb) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("Trying to remove mismatching close callback for"
+                          " domain %s"), vm->def->name);
+        return -1;
+    }
+
+    return virHashRemoveEntry(driver->closeCallbacks, uuidstr);
+}
+
+qemuDriverCloseCallback
+qemuDriverCloseCallbackGet(struct qemud_driver *driver,
+                           virDomainObjPtr vm,
+                           virConnectPtr conn)
+{
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    qemuDriverCloseDefPtr closeDef;
+    qemuDriverCloseCallback cb = NULL;
+
+    virUUIDFormat(vm->def->uuid, uuidstr);
+    VIR_DEBUG("vm=%s, uuid=%s, conn=%p",
+              vm->def->name, uuidstr, conn);
+
+    closeDef = virHashLookup(driver->closeCallbacks, uuidstr);
+    if (closeDef && (!conn || closeDef->conn == conn))
+        cb = closeDef->cb;
+
+    VIR_DEBUG("cb=%p", cb);
+    return cb;
+}
+
+struct qemuDriverCloseCallbackData {
+    struct qemud_driver *driver;
+    virConnectPtr conn;
+};
+
+static void
+qemuDriverCloseCallbackRun(void *payload,
+                           const void *name,
+                           void *opaque)
+{
+    struct qemuDriverCloseCallbackData *data = opaque;
+    qemuDriverCloseDefPtr closeDef = payload;
+    const char *uuidstr = name;
+    unsigned char uuid[VIR_UUID_BUFLEN];
+    virDomainObjPtr dom;
+
+    VIR_DEBUG("conn=%p, thisconn=%p, uuid=%s, cb=%p",
+              closeDef->conn, data->conn, uuidstr, closeDef->cb);
+
+    if (data->conn != closeDef->conn || !closeDef->cb)
+        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 with UUID %s", uuidstr);
+        return;
+    }
+
+    dom = closeDef->cb(data->driver, dom, data->conn);
+    if (dom)
+        virDomainObjUnlock(dom);
+
+    virHashRemoveEntry(data->driver->closeCallbacks, uuidstr);
+}
+
+void
+qemuDriverCloseCallbackRunAll(struct qemud_driver *driver,
+                              virConnectPtr conn)
+{
+    struct qemuDriverCloseCallbackData data = {
+        driver, conn
+    };
+    VIR_DEBUG("conn=%p", conn);
+
+    virHashForEach(driver->closeCallbacks, qemuDriverCloseCallbackRun, &data);
+}
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 36f1c4c..a22ce0c 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -46,6 +46,8 @@
 
 # define QEMUD_CPUMASK_LEN CPU_SETSIZE
 
+typedef struct _qemuDriverCloseDef qemuDriverCloseDef;
+typedef qemuDriverCloseDef *qemuDriverCloseDefPtr;
 
 /* Main driver state */
 struct qemud_driver {
@@ -144,6 +146,13 @@ struct qemud_driver {
      * when the virConnectPtr is closed*/
     virHashTablePtr autodestroy;
 
+    /* Mapping of 'char *uuidstr' -> qemuDriverCloseDefPtr of domains
+     * which want a specific cleanup to be done when a connection is
+     * closed. Such cleanup may be to automatically destroy  the
+     * domain or abort a particular job running on it.
+     */
+    virHashTablePtr closeCallbacks;
+
     int keepAliveInterval;
     unsigned int keepAliveCount;
 };
@@ -180,4 +189,22 @@ struct qemuDomainDiskInfo {
     int io_status;
 };
 
+typedef virDomainObjPtr (*qemuDriverCloseCallback)(struct qemud_driver *driver,
+                                                   virDomainObjPtr vm,
+                                                   virConnectPtr conn);
+int qemuDriverCloseCallbackInit(struct qemud_driver *driver);
+void qemuDriverCloseCallbackShutdown(struct qemud_driver *driver);
+int qemuDriverCloseCallbackSet(struct qemud_driver *driver,
+                               virDomainObjPtr vm,
+                               virConnectPtr conn,
+                               qemuDriverCloseCallback cb);
+int qemuDriverCloseCallbackUnset(struct qemud_driver *driver,
+                                 virDomainObjPtr vm,
+                                 qemuDriverCloseCallback cb);
+qemuDriverCloseCallback qemuDriverCloseCallbackGet(struct qemud_driver *driver,
+                                                   virDomainObjPtr vm,
+                                                   virConnectPtr conn);
+void qemuDriverCloseCallbackRunAll(struct qemud_driver *driver,
+                                   virConnectPtr conn);
+
 #endif /* __QEMUD_CONF_H */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 2c467ab..ce82535 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -662,6 +662,9 @@ qemudStartup(int privileged) {
     if (qemuProcessAutoDestroyInit(qemu_driver) < 0)
         goto error;
 
+    if (qemuDriverCloseCallbackInit(qemu_driver) < 0)
+        goto error;
+
     /* Get all the running persistent or transient configs first */
     if (virDomainLoadAllConfigs(qemu_driver->caps,
                                 &qemu_driver->domains,
@@ -801,6 +804,7 @@ qemudShutdown(void) {
     virSysinfoDefFree(qemu_driver->hostsysinfo);
 
     qemuProcessAutoDestroyShutdown(qemu_driver);
+    qemuDriverCloseCallbackShutdown(qemu_driver);
 
     VIR_FREE(qemu_driver->configDir);
     VIR_FREE(qemu_driver->autostartDir);
@@ -922,6 +926,7 @@ static int qemudClose(virConnectPtr conn) {
     virDomainEventStateDeregisterConn(conn,
                                       driver->domainEventState);
     qemuProcessAutoDestroyRun(driver, conn);
+    qemuDriverCloseCallbackRunAll(driver, conn);
     qemuDriverUnlock(driver);
 
     conn->privateData = NULL;
-- 
1.7.8.5

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to