qemu: Move close callbacks handling into util/virclosecallbacks.c

This commit is contained in:
Michal Privoznik 2013-07-15 16:53:13 +02:00
parent 166db595c3
commit 272769becc
11 changed files with 424 additions and 345 deletions

View File

@ -146,6 +146,7 @@ src/util/viraudit.c
src/util/virauth.c
src/util/virauthconfig.c
src/util/vircgroup.c
src/util/virclosecallbacks.c
src/util/vircommand.c
src/util/virconf.c
src/util/virdbus.c

View File

@ -83,6 +83,7 @@ UTIL_SOURCES = \
util/virbitmap.c util/virbitmap.h \
util/virbuffer.c util/virbuffer.h \
util/vircgroup.c util/vircgroup.h util/vircgrouppriv.h \
util/virclosecallbacks.c util/virclosecallbacks.h \
util/vircommand.c util/vircommand.h \
util/virconf.c util/virconf.h \
util/virdbus.c util/virdbus.h \
@ -882,7 +883,8 @@ libvirt_util_la_SOURCES = \
$(UTIL_SOURCES)
libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) $(YAJL_CFLAGS) $(LIBNL_CFLAGS) \
$(AM_CFLAGS) $(AUDIT_CFLAGS) $(DEVMAPPER_CFLAGS) \
$(DBUS_CFLAGS) $(LDEXP_LIBM) $(NUMACTL_CFLAGS)
$(DBUS_CFLAGS) $(LDEXP_LIBM) $(NUMACTL_CFLAGS) \
-I$(top_srcdir)/src/conf
libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) \
$(THREAD_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_LIBS) \
$(LIB_CLOCK_GETTIME) $(DBUS_LIBS) $(MSCOM_LIBS) $(LIBXML_LIBS) \

View File

@ -1204,6 +1204,13 @@ virCgroupSetMemorySoftLimit;
virCgroupSetMemSwapHardLimit;
# util/virclosecallbacks.h
virCloseCallbacksGet;
virCloseCallbacksNew;
virCloseCallbacksRun;
virCloseCallbacksSet;
virCloseCallbacksUnset;
# util/vircommand.h
virCommandAbort;
virCommandAddArg;

View File

@ -56,25 +56,8 @@
#define VIR_FROM_THIS VIR_FROM_QEMU
typedef struct _qemuDriverCloseDef qemuDriverCloseDef;
typedef qemuDriverCloseDef *qemuDriverCloseDefPtr;
struct _qemuDriverCloseDef {
virConnectPtr conn;
virQEMUCloseCallback cb;
};
struct _virQEMUCloseCallbacks {
virObjectLockable parent;
/* UUID string to qemuDriverCloseDef mapping */
virHashTablePtr list;
};
static virClassPtr virQEMUDriverConfigClass;
static virClassPtr virQEMUCloseCallbacksClass;
static void virQEMUDriverConfigDispose(void *obj);
static void virQEMUCloseCallbacksDispose(void *obj);
static int virQEMUConfigOnceInit(void)
{
@ -83,12 +66,7 @@ static int virQEMUConfigOnceInit(void)
sizeof(virQEMUDriverConfig),
virQEMUDriverConfigDispose);
virQEMUCloseCallbacksClass = virClassNew(virClassForObjectLockable(),
"virQEMUCloseCallbacks",
sizeof(virQEMUCloseCallbacks),
virQEMUCloseCallbacksDispose);
if (!virQEMUDriverConfigClass || !virQEMUCloseCallbacksClass)
if (!virQEMUDriverConfigClass)
return -1;
else
return 0;
@ -662,277 +640,6 @@ virCapsPtr virQEMUDriverGetCapabilities(virQEMUDriverPtr driver,
return ret;
}
static void
virQEMUCloseCallbacksFreeData(void *payload,
const void *name ATTRIBUTE_UNUSED)
{
VIR_FREE(payload);
}
virQEMUCloseCallbacksPtr
virQEMUCloseCallbacksNew(void)
{
virQEMUCloseCallbacksPtr closeCallbacks;
if (virQEMUConfigInitialize() < 0)
return NULL;
if (!(closeCallbacks = virObjectLockableNew(virQEMUCloseCallbacksClass)))
return NULL;
closeCallbacks->list = virHashCreate(5, virQEMUCloseCallbacksFreeData);
if (!closeCallbacks->list) {
virObjectUnref(closeCallbacks);
return NULL;
}
return closeCallbacks;
}
static void
virQEMUCloseCallbacksDispose(void *obj)
{
virQEMUCloseCallbacksPtr closeCallbacks = obj;
virHashFree(closeCallbacks->list);
}
int
virQEMUCloseCallbacksSet(virQEMUCloseCallbacksPtr closeCallbacks,
virDomainObjPtr vm,
virConnectPtr conn,
virQEMUCloseCallback cb)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
qemuDriverCloseDefPtr 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;
}
}
ret = 0;
cleanup:
virObjectUnlock(closeCallbacks);
return ret;
}
int
virQEMUCloseCallbacksUnset(virQEMUCloseCallbacksPtr closeCallbacks,
virDomainObjPtr vm,
virQEMUCloseCallback cb)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
qemuDriverCloseDefPtr 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;
}
ret = virHashRemoveEntry(closeCallbacks->list, uuidstr);
cleanup:
virObjectUnlock(closeCallbacks);
return ret;
}
virQEMUCloseCallback
virQEMUCloseCallbacksGet(virQEMUCloseCallbacksPtr closeCallbacks,
virDomainObjPtr vm,
virConnectPtr conn)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
qemuDriverCloseDefPtr closeDef;
virQEMUCloseCallback 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;
}
typedef struct _virQEMUCloseCallbacksListEntry virQEMUCloseCallbacksListEntry;
typedef virQEMUCloseCallbacksListEntry *virQEMUCloseCallbacksListEntryPtr;
struct _virQEMUCloseCallbacksListEntry {
unsigned char uuid[VIR_UUID_BUFLEN];
virQEMUCloseCallback callback;
};
typedef struct _virQEMUCloseCallbacksList virQEMUCloseCallbacksList;
typedef virQEMUCloseCallbacksList *virQEMUCloseCallbacksListPtr;
struct _virQEMUCloseCallbacksList {
size_t nentries;
virQEMUCloseCallbacksListEntryPtr entries;
};
struct virQEMUCloseCallbacksData {
virConnectPtr conn;
virQEMUCloseCallbacksListPtr list;
bool oom;
};
static void
virQEMUCloseCallbacksGetOne(void *payload,
const void *key,
void *opaque)
{
struct virQEMUCloseCallbacksData *data = opaque;
qemuDriverCloseDefPtr closeDef = payload;
const char *uuidstr = key;
unsigned char uuid[VIR_UUID_BUFLEN];
if (virUUIDParse(uuidstr, uuid) < 0)
return;
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 (VIR_EXPAND_N(data->list->entries,
data->list->nentries, 1) < 0) {
data->oom = true;
return;
}
memcpy(data->list->entries[data->list->nentries - 1].uuid,
uuid, VIR_UUID_BUFLEN);
data->list->entries[data->list->nentries - 1].callback = closeDef->cb;
}
static virQEMUCloseCallbacksListPtr
virQEMUCloseCallbacksGetForConn(virQEMUCloseCallbacksPtr closeCallbacks,
virConnectPtr conn)
{
virQEMUCloseCallbacksListPtr list = NULL;
struct virQEMUCloseCallbacksData data;
if (VIR_ALLOC(list) < 0)
return NULL;
data.conn = conn;
data.list = list;
data.oom = false;
virHashForEach(closeCallbacks->list, virQEMUCloseCallbacksGetOne, &data);
if (data.oom) {
VIR_FREE(list->entries);
VIR_FREE(list);
virReportOOMError();
return NULL;
}
return list;
}
void
virQEMUCloseCallbacksRun(virQEMUCloseCallbacksPtr closeCallbacks,
virConnectPtr conn,
virQEMUDriverPtr driver)
{
virQEMUCloseCallbacksListPtr 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 = virQEMUCloseCallbacksGetForConn(closeCallbacks, conn);
if (!list)
return;
for (i = 0; i < list->nentries; i++) {
virHashRemoveEntry(closeCallbacks->list,
list->entries[i].uuid);
}
virObjectUnlock(closeCallbacks);
for (i = 0; i < list->nentries; i++) {
virDomainObjPtr vm;
if (!(vm = virDomainObjListFindByUUID(driver->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;
}
vm = list->entries[i].callback(driver, vm, conn);
if (vm)
virObjectUnlock(vm);
}
VIR_FREE(list->entries);
VIR_FREE(list);
}
struct _qemuSharedDeviceEntry {
size_t ref;
char **domains; /* array of domain names */

View File

@ -42,6 +42,7 @@
# include "virthreadpool.h"
# include "locking/lock_manager.h"
# include "qemu_capabilities.h"
# include "virclosecallbacks.h"
# ifdef CPU_SETSIZE /* Linux */
# define QEMUD_CPUMASK_LEN CPU_SETSIZE
@ -51,9 +52,6 @@
# error "Port me"
# endif
typedef struct _virQEMUCloseCallbacks virQEMUCloseCallbacks;
typedef virQEMUCloseCallbacks *virQEMUCloseCallbacksPtr;
typedef struct _virQEMUDriver virQEMUDriver;
typedef virQEMUDriver *virQEMUDriverPtr;
@ -229,7 +227,7 @@ struct _virQEMUDriver {
virLockManagerPluginPtr lockManager;
/* Immutable pointer, self-clocking APIs */
virQEMUCloseCallbacksPtr closeCallbacks;
virCloseCallbacksPtr closeCallbacks;
};
typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef;
@ -266,25 +264,6 @@ struct qemuDomainDiskInfo {
int io_status;
};
typedef virDomainObjPtr (*virQEMUCloseCallback)(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virConnectPtr conn);
virQEMUCloseCallbacksPtr virQEMUCloseCallbacksNew(void);
int virQEMUCloseCallbacksSet(virQEMUCloseCallbacksPtr closeCallbacks,
virDomainObjPtr vm,
virConnectPtr conn,
virQEMUCloseCallback cb);
int virQEMUCloseCallbacksUnset(virQEMUCloseCallbacksPtr closeCallbacks,
virDomainObjPtr vm,
virQEMUCloseCallback cb);
virQEMUCloseCallback
virQEMUCloseCallbacksGet(virQEMUCloseCallbacksPtr closeCallbacks,
virDomainObjPtr vm,
virConnectPtr conn);
void virQEMUCloseCallbacksRun(virQEMUCloseCallbacksPtr closeCallbacks,
virConnectPtr conn,
virQEMUDriverPtr driver);
typedef struct _qemuSharedDeviceEntry qemuSharedDeviceEntry;
typedef qemuSharedDeviceEntry *qemuSharedDeviceEntryPtr;

View File

@ -776,7 +776,7 @@ qemuStateInitialize(bool privileged,
cfg->hugepagePath = mempath;
}
if (!(qemu_driver->closeCallbacks = virQEMUCloseCallbacksNew()))
if (!(qemu_driver->closeCallbacks = virCloseCallbacksNew()))
goto error;
/* Get all the running persistent or transient configs first */
@ -1076,7 +1076,7 @@ static int qemuConnectClose(virConnectPtr conn)
virQEMUDriverPtr driver = conn->privateData;
/* Get rid of callbacks registered for this conn */
virQEMUCloseCallbacksRun(driver->closeCallbacks, conn, driver);
virCloseCallbacksRun(driver->closeCallbacks, conn, driver->domains, driver);
conn->privateData = NULL;

View File

@ -1896,11 +1896,12 @@ cleanup:
* qemuDomainMigrateBegin3 and qemuDomainMigratePerform3 or
* qemuDomainMigratePerform3 and qemuDomainMigrateConfirm3.
*/
virDomainObjPtr
qemuMigrationCleanup(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virConnectPtr conn)
static virDomainObjPtr
qemuMigrationCleanup(virDomainObjPtr vm,
virConnectPtr conn,
void *opaque)
{
virQEMUDriverPtr driver = opaque;
qemuDomainObjPrivatePtr priv = vm->privateData;
VIR_DEBUG("vm=%s, conn=%p, asyncJob=%s, phase=%s",
@ -2100,8 +2101,8 @@ qemuMigrationBegin(virConnectPtr conn,
* This prevents any other APIs being invoked while migration is taking
* place.
*/
if (virQEMUCloseCallbacksSet(driver->closeCallbacks, vm, conn,
qemuMigrationCleanup) < 0)
if (virCloseCallbacksSet(driver->closeCallbacks, vm, conn,
qemuMigrationCleanup) < 0)
goto endjob;
if (qemuMigrationJobContinue(vm) == 0) {
vm = NULL;
@ -2750,8 +2751,8 @@ qemuMigrationConfirm(virConnectPtr conn,
phase = QEMU_MIGRATION_PHASE_CONFIRM3;
qemuMigrationJobStartPhase(driver, vm, phase);
virQEMUCloseCallbacksUnset(driver->closeCallbacks, vm,
qemuMigrationCleanup);
virCloseCallbacksUnset(driver->closeCallbacks, vm,
qemuMigrationCleanup);
ret = qemuMigrationConfirmPhase(driver, conn, vm,
cookiein, cookieinlen,
@ -4123,8 +4124,8 @@ qemuMigrationPerformPhase(virQEMUDriverPtr driver,
}
qemuMigrationJobStartPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3);
virQEMUCloseCallbacksUnset(driver->closeCallbacks, vm,
qemuMigrationCleanup);
virCloseCallbacksUnset(driver->closeCallbacks, vm,
qemuMigrationCleanup);
resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen,
@ -4155,8 +4156,8 @@ qemuMigrationPerformPhase(virQEMUDriverPtr driver,
qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3_DONE);
if (virQEMUCloseCallbacksSet(driver->closeCallbacks, vm, conn,
qemuMigrationCleanup) < 0)
if (virCloseCallbacksSet(driver->closeCallbacks, vm, conn,
qemuMigrationCleanup) < 0)
goto endjob;
endjob:

View File

@ -90,10 +90,6 @@ bool qemuMigrationJobFinish(virQEMUDriverPtr driver, virDomainObjPtr obj)
int qemuMigrationSetOffline(virQEMUDriverPtr driver,
virDomainObjPtr vm);
virDomainObjPtr qemuMigrationCleanup(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virConnectPtr conn);
char *qemuMigrationBegin(virConnectPtr conn,
virDomainObjPtr vm,
const char *xmlin,

View File

@ -4470,10 +4470,11 @@ cleanup:
static virDomainObjPtr
qemuProcessAutoDestroy(virQEMUDriverPtr driver,
virDomainObjPtr dom,
virConnectPtr conn)
qemuProcessAutoDestroy(virDomainObjPtr dom,
virConnectPtr conn,
void *opaque)
{
virQEMUDriverPtr driver = opaque;
qemuDomainObjPrivatePtr priv = dom->privateData;
virDomainEventPtr event = NULL;
@ -4517,23 +4518,23 @@ int qemuProcessAutoDestroyAdd(virQEMUDriverPtr driver,
virConnectPtr conn)
{
VIR_DEBUG("vm=%s, conn=%p", vm->def->name, conn);
return virQEMUCloseCallbacksSet(driver->closeCallbacks, vm, conn,
qemuProcessAutoDestroy);
return virCloseCallbacksSet(driver->closeCallbacks, vm, conn,
qemuProcessAutoDestroy);
}
int qemuProcessAutoDestroyRemove(virQEMUDriverPtr driver,
virDomainObjPtr vm)
{
VIR_DEBUG("vm=%s", vm->def->name);
return virQEMUCloseCallbacksUnset(driver->closeCallbacks, vm,
qemuProcessAutoDestroy);
return virCloseCallbacksUnset(driver->closeCallbacks, vm,
qemuProcessAutoDestroy);
}
bool qemuProcessAutoDestroyActive(virQEMUDriverPtr driver,
virDomainObjPtr vm)
{
virQEMUCloseCallback cb;
virCloseCallback cb;
VIR_DEBUG("vm=%s", vm->def->name);
cb = virQEMUCloseCallbacksGet(driver->closeCallbacks, vm, NULL);
cb = virCloseCallbacksGet(driver->closeCallbacks, vm, NULL);
return cb == qemuProcessAutoDestroy;
}

View File

@ -0,0 +1,332 @@
/*
* virclosecallbacks.c: 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/>.
*
* Authors:
* Daniel P. Berrange <berrange@redhat.com>
* Michal Privoznik <mprivozn@redhat.com>
*/
#include <config.h>
#include "viralloc.h"
#include "virclosecallbacks.h"
#include "virlog.h"
#include "virobject.h"
#define VIR_FROM_THIS VIR_FROM_NONE
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)
{
virCloseCallbacksClass = virClassNew(virClassForObjectLockable(),
"virCloseCallbacks",
sizeof(virCloseCallbacks),
virCloseCallbacksDispose);
if (!virCloseCallbacksClass)
return -1;
else
return 0;
}
VIR_ONCE_GLOBAL_INIT(virCloseCallbacks)
static void
virCloseCallbacksFreeData(void *payload,
const void *name ATTRIBUTE_UNUSED)
{
VIR_FREE(payload);
}
virCloseCallbacksPtr
virCloseCallbacksNew(void)
{
virCloseCallbacksPtr closeCallbacks;
if (virCloseCallbacksInitialize() < 0)
return NULL;
if (!(closeCallbacks = virObjectLockableNew(virCloseCallbacksClass)))
return NULL;
closeCallbacks->list = virHashCreate(5, virCloseCallbacksFreeData);
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;
}
}
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;
}
ret = virHashRemoveEntry(closeCallbacks->list, uuidstr);
cleanup:
virObjectUnlock(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;
}
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 void
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;
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 (VIR_EXPAND_N(data->list->entries,
data->list->nentries, 1) < 0) {
data->oom = true;
return;
}
memcpy(data->list->entries[data->list->nentries - 1].uuid,
uuid, VIR_UUID_BUFLEN);
data->list->entries[data->list->nentries - 1].callback = closeDef->cb;
}
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)
return;
for (i = 0; i < list->nentries; i++) {
virHashRemoveEntry(closeCallbacks->list,
list->entries[i].uuid);
}
virObjectUnlock(closeCallbacks);
for (i = 0; i < list->nentries; i++) {
virDomainObjPtr 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;
}
vm = list->entries[i].callback(vm, conn, opaque);
if (vm)
virObjectUnlock(vm);
}
VIR_FREE(list->entries);
VIR_FREE(list);
}

View File

@ -0,0 +1,53 @@
/*
* 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/>.
*
* Authors:
* Daniel P. Berrange <berrange@redhat.com>
* Michal Privoznik <mprivozn@redhat.com>
*/
#ifndef __VIR_CLOSE_CALLBACKS__
# define __VIR_CLOSE_CALLBACKS__
# include "domain_conf.h"
typedef struct _virCloseCallbacks virCloseCallbacks;
typedef virCloseCallbacks *virCloseCallbacksPtr;
typedef virDomainObjPtr (*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);
void
virCloseCallbacksRun(virCloseCallbacksPtr closeCallbacks,
virConnectPtr conn,
virDomainObjListPtr domains,
void *opaque);
#endif /* __VIR_CLOSE_CALLBACKS__ */