diff options
author | Ján Tomko <jtomko@redhat.com> | 2020-02-22 18:16:19 +0100 |
---|---|---|
committer | Ján Tomko <jtomko@redhat.com> | 2020-02-24 16:47:21 +0100 |
commit | 25c29ac2f5842a7d48d9f9619317f68acf5d9995 (patch) | |
tree | 0021cfdc7e9c0345750215df002def5537c4a916 /src/hypervisor | |
parent | a504a3c377109b7950ca61664bc0c9ff5b8096f6 (diff) | |
download | libvirt-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.am | 2 | ||||
-rw-r--r-- | src/hypervisor/virclosecallbacks.c | 360 | ||||
-rw-r--r-- | src/hypervisor/virclosecallbacks.h | 50 |
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); |