summaryrefslogtreecommitdiff
path: root/src/hypervisor
diff options
context:
space:
mode:
authorJán Tomko <jtomko@redhat.com>2020-02-22 18:16:19 +0100
committerJán Tomko <jtomko@redhat.com>2020-02-24 16:47:21 +0100
commit25c29ac2f5842a7d48d9f9619317f68acf5d9995 (patch)
tree0021cfdc7e9c0345750215df002def5537c4a916 /src/hypervisor
parenta504a3c377109b7950ca61664bc0c9ff5b8096f6 (diff)
downloadlibvirt-25c29ac2f5842a7d48d9f9619317f68acf5d9995.tar.gz
virclosecallbacks: move to src/hypervisor
Just like virhostdev, this depends on domain_conf and it's shared by multiple hypervisor drivers. Signed-off-by: Ján Tomko <jtomko@redhat.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Diffstat (limited to 'src/hypervisor')
-rw-r--r--src/hypervisor/Makefile.inc.am2
-rw-r--r--src/hypervisor/virclosecallbacks.c360
-rw-r--r--src/hypervisor/virclosecallbacks.h50
3 files changed, 412 insertions, 0 deletions
diff --git a/src/hypervisor/Makefile.inc.am b/src/hypervisor/Makefile.inc.am
index 3bd775a4a5..bc48ab1266 100644
--- a/src/hypervisor/Makefile.inc.am
+++ b/src/hypervisor/Makefile.inc.am
@@ -5,6 +5,8 @@ HYPERVISOR_SOURCES = \
hypervisor/domain_cgroup.c \
hypervisor/domain_driver.h \
hypervisor/domain_driver.c \
+ hypervisor/virclosecallbacks.h \
+ hypervisor/virclosecallbacks.c \
hypervisor/virhostdev.h \
hypervisor/virhostdev.c \
$(NULL)
diff --git a/src/hypervisor/virclosecallbacks.c b/src/hypervisor/virclosecallbacks.c
new file mode 100644
index 0000000000..200577e18e
--- /dev/null
+++ b/src/hypervisor/virclosecallbacks.c
@@ -0,0 +1,360 @@
+/*
+ * virclosecallbacks.c: Connection close callbacks routines
+ *
+ * Copyright (C) 2013-2014 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "viralloc.h"
+#include "virclosecallbacks.h"
+#include "virlog.h"
+#include "virobject.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+VIR_LOG_INIT("util.closecallbacks");
+
+typedef struct _virDriverCloseDef virDriverCloseDef;
+typedef virDriverCloseDef *virDriverCloseDefPtr;
+struct _virDriverCloseDef {
+ virConnectPtr conn;
+ virCloseCallback cb;
+};
+
+struct _virCloseCallbacks {
+ virObjectLockable parent;
+
+ /* UUID string to qemuDriverCloseDef mapping */
+ virHashTablePtr list;
+};
+
+
+static virClassPtr virCloseCallbacksClass;
+static void virCloseCallbacksDispose(void *obj);
+
+static int virCloseCallbacksOnceInit(void)
+{
+ if (!VIR_CLASS_NEW(virCloseCallbacks, virClassForObjectLockable()))
+ return -1;
+
+ return 0;
+}
+
+VIR_ONCE_GLOBAL_INIT(virCloseCallbacks);
+
+
+virCloseCallbacksPtr
+virCloseCallbacksNew(void)
+{
+ virCloseCallbacksPtr closeCallbacks;
+
+ if (virCloseCallbacksInitialize() < 0)
+ return NULL;
+
+ if (!(closeCallbacks = virObjectLockableNew(virCloseCallbacksClass)))
+ return NULL;
+
+ closeCallbacks->list = virHashCreate(5, virHashValueFree);
+ if (!closeCallbacks->list) {
+ virObjectUnref(closeCallbacks);
+ return NULL;
+ }
+
+ return closeCallbacks;
+}
+
+static void
+virCloseCallbacksDispose(void *obj)
+{
+ virCloseCallbacksPtr closeCallbacks = obj;
+
+ virHashFree(closeCallbacks->list);
+}
+
+int
+virCloseCallbacksSet(virCloseCallbacksPtr closeCallbacks,
+ virDomainObjPtr vm,
+ virConnectPtr conn,
+ virCloseCallback cb)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virDriverCloseDefPtr closeDef;
+ int ret = -1;
+
+ virUUIDFormat(vm->def->uuid, uuidstr);
+ VIR_DEBUG("vm=%s, uuid=%s, conn=%p, cb=%p",
+ vm->def->name, uuidstr, conn, cb);
+
+ virObjectLock(closeCallbacks);
+
+ closeDef = virHashLookup(closeCallbacks->list, uuidstr);
+ if (closeDef) {
+ if (closeDef->conn != conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Close callback for domain %s already registered"
+ " with another connection %p"),
+ vm->def->name, closeDef->conn);
+ goto cleanup;
+ }
+ if (closeDef->cb && closeDef->cb != cb) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Another close callback is already defined for"
+ " domain %s"), vm->def->name);
+ goto cleanup;
+ }
+
+ closeDef->cb = cb;
+ } else {
+ if (VIR_ALLOC(closeDef) < 0)
+ goto cleanup;
+
+ closeDef->conn = conn;
+ closeDef->cb = cb;
+ if (virHashAddEntry(closeCallbacks->list, uuidstr, closeDef) < 0) {
+ VIR_FREE(closeDef);
+ goto cleanup;
+ }
+ virObjectRef(vm);
+ }
+
+ virObjectRef(closeCallbacks);
+ ret = 0;
+ cleanup:
+ virObjectUnlock(closeCallbacks);
+ return ret;
+}
+
+int
+virCloseCallbacksUnset(virCloseCallbacksPtr closeCallbacks,
+ virDomainObjPtr vm,
+ virCloseCallback cb)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virDriverCloseDefPtr closeDef;
+ int ret = -1;
+
+ virUUIDFormat(vm->def->uuid, uuidstr);
+ VIR_DEBUG("vm=%s, uuid=%s, cb=%p",
+ vm->def->name, uuidstr, cb);
+
+ virObjectLock(closeCallbacks);
+
+ closeDef = virHashLookup(closeCallbacks->list, uuidstr);
+ if (!closeDef)
+ goto cleanup;
+
+ if (closeDef->cb && closeDef->cb != cb) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Trying to remove mismatching close callback for"
+ " domain %s"), vm->def->name);
+ goto cleanup;
+ }
+
+ if (virHashRemoveEntry(closeCallbacks->list, uuidstr) < 0)
+ goto cleanup;
+
+ virObjectUnref(vm);
+ ret = 0;
+ cleanup:
+ virObjectUnlock(closeCallbacks);
+ if (!ret)
+ virObjectUnref(closeCallbacks);
+ return ret;
+}
+
+virCloseCallback
+virCloseCallbacksGet(virCloseCallbacksPtr closeCallbacks,
+ virDomainObjPtr vm,
+ virConnectPtr conn)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virDriverCloseDefPtr closeDef;
+ virCloseCallback cb = NULL;
+
+ virUUIDFormat(vm->def->uuid, uuidstr);
+ VIR_DEBUG("vm=%s, uuid=%s, conn=%p",
+ vm->def->name, uuidstr, conn);
+
+ virObjectLock(closeCallbacks);
+
+ closeDef = virHashLookup(closeCallbacks->list, uuidstr);
+ if (closeDef && (!conn || closeDef->conn == conn))
+ cb = closeDef->cb;
+
+ virObjectUnlock(closeCallbacks);
+
+ VIR_DEBUG("cb=%p", cb);
+ return cb;
+}
+
+virConnectPtr
+virCloseCallbacksGetConn(virCloseCallbacksPtr closeCallbacks,
+ virDomainObjPtr vm)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virDriverCloseDefPtr closeDef;
+ virConnectPtr conn = NULL;
+
+ virUUIDFormat(vm->def->uuid, uuidstr);
+ VIR_DEBUG("vm=%s, uuid=%s", vm->def->name, uuidstr);
+
+ virObjectLock(closeCallbacks);
+
+ closeDef = virHashLookup(closeCallbacks->list, uuidstr);
+ if (closeDef)
+ conn = closeDef->conn;
+
+ virObjectUnlock(closeCallbacks);
+
+ VIR_DEBUG("conn=%p", conn);
+ return conn;
+}
+
+
+typedef struct _virCloseCallbacksListEntry virCloseCallbacksListEntry;
+typedef virCloseCallbacksListEntry *virCloseCallbacksListEntryPtr;
+struct _virCloseCallbacksListEntry {
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ virCloseCallback callback;
+};
+
+typedef struct _virCloseCallbacksList virCloseCallbacksList;
+typedef virCloseCallbacksList *virCloseCallbacksListPtr;
+struct _virCloseCallbacksList {
+ size_t nentries;
+ virCloseCallbacksListEntryPtr entries;
+};
+
+struct virCloseCallbacksData {
+ virConnectPtr conn;
+ virCloseCallbacksListPtr list;
+ bool oom;
+};
+
+static int
+virCloseCallbacksGetOne(void *payload,
+ const void *key,
+ void *opaque)
+{
+ struct virCloseCallbacksData *data = opaque;
+ virDriverCloseDefPtr closeDef = payload;
+ const char *uuidstr = key;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+
+ if (virUUIDParse(uuidstr, uuid) < 0)
+ return 0;
+
+ 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 0;
+
+ if (VIR_EXPAND_N(data->list->entries,
+ data->list->nentries, 1) < 0) {
+ data->oom = true;
+ return 0;
+ }
+
+ memcpy(data->list->entries[data->list->nentries - 1].uuid,
+ uuid, VIR_UUID_BUFLEN);
+ data->list->entries[data->list->nentries - 1].callback = closeDef->cb;
+ return 0;
+}
+
+static virCloseCallbacksListPtr
+virCloseCallbacksGetForConn(virCloseCallbacksPtr closeCallbacks,
+ virConnectPtr conn)
+{
+ virCloseCallbacksListPtr list = NULL;
+ struct virCloseCallbacksData data;
+
+ if (VIR_ALLOC(list) < 0)
+ return NULL;
+
+ data.conn = conn;
+ data.list = list;
+ data.oom = false;
+
+ virHashForEach(closeCallbacks->list, virCloseCallbacksGetOne, &data);
+
+ if (data.oom) {
+ VIR_FREE(list->entries);
+ VIR_FREE(list);
+ virReportOOMError();
+ return NULL;
+ }
+
+ return list;
+}
+
+
+void
+virCloseCallbacksRun(virCloseCallbacksPtr closeCallbacks,
+ virConnectPtr conn,
+ virDomainObjListPtr domains,
+ void *opaque)
+{
+ virCloseCallbacksListPtr list;
+ size_t i;
+
+ VIR_DEBUG("conn=%p", conn);
+
+ /* We must not hold the lock while running the callbacks,
+ * so first we obtain the list of callbacks, then remove
+ * them all from the hash. At that point we can release
+ * the lock and run the callbacks safely. */
+
+ virObjectLock(closeCallbacks);
+ list = virCloseCallbacksGetForConn(closeCallbacks, conn);
+ if (!list) {
+ virObjectUnlock(closeCallbacks);
+ return;
+ }
+
+ for (i = 0; i < list->nentries; i++) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(list->entries[i].uuid, uuidstr);
+ virHashRemoveEntry(closeCallbacks->list, uuidstr);
+ }
+ virObjectUnlock(closeCallbacks);
+
+ for (i = 0; i < list->nentries; i++) {
+ virDomainObjPtr vm;
+
+ /* Grab a ref and lock to the vm */
+ if (!(vm = virDomainObjListFindByUUID(domains,
+ list->entries[i].uuid))) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(list->entries[i].uuid, uuidstr);
+ VIR_DEBUG("No domain object with UUID %s", uuidstr);
+ continue;
+ }
+
+ /* Remove the ref taken out during virCloseCallbacksSet since
+ * we're about to call the callback function and we have another
+ * ref anyway (so it cannot be deleted).
+ *
+ * Call the callback function and end the API usage. */
+ virObjectUnref(vm);
+ list->entries[i].callback(vm, conn, opaque);
+ virDomainObjEndAPI(&vm);
+ }
+ VIR_FREE(list->entries);
+ VIR_FREE(list);
+}
diff --git a/src/hypervisor/virclosecallbacks.h b/src/hypervisor/virclosecallbacks.h
new file mode 100644
index 0000000000..98fc2c4a94
--- /dev/null
+++ b/src/hypervisor/virclosecallbacks.h
@@ -0,0 +1,50 @@
+/*
+ * virclosecallbacks.h: Connection close callbacks routines
+ *
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "conf/virdomainobjlist.h"
+
+typedef struct _virCloseCallbacks virCloseCallbacks;
+typedef virCloseCallbacks *virCloseCallbacksPtr;
+
+typedef void (*virCloseCallback)(virDomainObjPtr vm,
+ virConnectPtr conn,
+ void *opaque);
+virCloseCallbacksPtr virCloseCallbacksNew(void);
+int virCloseCallbacksSet(virCloseCallbacksPtr closeCallbacks,
+ virDomainObjPtr vm,
+ virConnectPtr conn,
+ virCloseCallback cb);
+int virCloseCallbacksUnset(virCloseCallbacksPtr closeCallbacks,
+ virDomainObjPtr vm,
+ virCloseCallback cb);
+virCloseCallback
+virCloseCallbacksGet(virCloseCallbacksPtr closeCallbacks,
+ virDomainObjPtr vm,
+ virConnectPtr conn);
+virConnectPtr
+virCloseCallbacksGetConn(virCloseCallbacksPtr closeCallbacks,
+ virDomainObjPtr vm);
+void
+virCloseCallbacksRun(virCloseCallbacksPtr closeCallbacks,
+ virConnectPtr conn,
+ virDomainObjListPtr domains,
+ void *opaque);