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