[libvirt] [PATCH 1/2] qemu: Turn closeCallbacks into virObjectLockable
Daniel P. Berrange
berrange at redhat.com
Tue Feb 19 14:26:37 UTC 2013
On Mon, Feb 18, 2013 at 05:07:44PM +0100, Jiri Denemark wrote:
> To avoid having to hold the qemu driver lock while iterating through
> close callbacks and calling them. This fixes a real deadlock when a
> domain which is being migrated from another host gets autodestoyed as a
> result of broken connection to the other host.
Since you're turning this into a full object, I think it would be
nice to move it to a standalone file, so it can be reused by the
LXC driver, which currently re-invents this same kind of code.
> ---
> src/qemu/qemu_conf.c | 155 ++++++++++++++++++++++++++++++----------------
> src/qemu/qemu_conf.h | 39 ++++++------
> src/qemu/qemu_driver.c | 12 ++--
> src/qemu/qemu_migration.c | 6 +-
> src/qemu/qemu_process.c | 10 +--
> 5 files changed, 136 insertions(+), 86 deletions(-)
>
> diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
> index 4ff912d..edadf36 100644
> --- a/src/qemu/qemu_conf.c
> +++ b/src/qemu/qemu_conf.c
> @@ -57,8 +57,25 @@
>
> #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)
> {
> @@ -71,13 +88,21 @@ static int virQEMUConfigOnceInit(void)
> return 0;
> }
>
> -VIR_ONCE_GLOBAL_INIT(virQEMUConfig)
> +static int
> +virQEMUCloseCallbacksOnceInit(void)
> +{
> + virQEMUCloseCallbacksClass = virClassNew(virClassForObjectLockable(),
> + "virQEMUCloseCallbacks",
> + sizeof(virQEMUCloseCallbacks),
> + virQEMUCloseCallbacksDispose);
> + if (!virQEMUCloseCallbacksClass)
> + return -1;
> + return 0;
> +}
>
> +VIR_ONCE_GLOBAL_INIT(virQEMUConfig)
> +VIR_ONCE_GLOBAL_INIT(virQEMUCloseCallbacks)
No need for two initializers, just make the virQEMUConfigOnceInit
method create both classes.
> @@ -639,44 +664,59 @@ virCapsPtr virQEMUDriverGetCapabilities(virQEMUDriverPtr driver,
>
>
> static void
> -qemuDriverCloseCallbackFree(void *payload,
> - const void *name ATTRIBUTE_UNUSED)
> +virQEMUCloseCallbacksFreeData(void *payload,
> + const void *name ATTRIBUTE_UNUSED)
> {
> VIR_FREE(payload);
> }
>
> -int
> -qemuDriverCloseCallbackInit(virQEMUDriverPtr driver)
> +virQEMUCloseCallbacksPtr
> +virQEMUCloseCallbacksNew(void)
> {
> - driver->closeCallbacks = virHashCreate(5, qemuDriverCloseCallbackFree);
> - if (!driver->closeCallbacks)
> - return -1;
> + virQEMUCloseCallbacksPtr closeCallbacks;
>
> - return 0;
> + if (virQEMUCloseCallbacksInitialize() < 0)
> + return NULL;
> +
> + if (!(closeCallbacks = virObjectLockableNew(virQEMUCloseCallbacksClass)))
> + return NULL;
> +
> + closeCallbacks->list = virHashCreate(5, virQEMUCloseCallbacksFreeData);
> + if (!closeCallbacks->list) {
> + virObjectUnref(closeCallbacks);
> + return NULL;
> + }
> +
> + return closeCallbacks;
> }
>
> -void
> -qemuDriverCloseCallbackShutdown(virQEMUDriverPtr driver)
> +static void
> +virQEMUCloseCallbacksDispose(void *obj)
> {
> - virHashFree(driver->closeCallbacks);
> + virQEMUCloseCallbacksPtr closeCallbacks = obj;
> +
> + virHashFree(closeCallbacks->list);
> }
>
> int
> -qemuDriverCloseCallbackSet(virQEMUDriverPtr driver,
> - virDomainObjPtr vm,
> - virConnectPtr conn,
> - qemuDriverCloseCallback cb)
> +virQEMUCloseCallbacksSet(virQEMUDriverPtr driver,
> + virDomainObjPtr vm,
> + virConnectPtr conn,
> + virQEMUCloseCallback cb)
> {
> char uuidstr[VIR_UUID_STRING_BUFLEN];
> qemuDriverCloseDefPtr closeDef;
> + virHashTablePtr list;
> int ret = -1;
>
> - qemuDriverLock(driver);
> 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);
> + virObjectLock(driver->closeCallbacks);
> +
> + list = driver->closeCallbacks->list;
> + closeDef = virHashLookup(list, uuidstr);
> if (closeDef) {
> if (closeDef->conn != conn) {
> virReportError(VIR_ERR_INTERNAL_ERROR,
> @@ -701,7 +741,7 @@ qemuDriverCloseCallbackSet(virQEMUDriverPtr driver,
>
> closeDef->conn = conn;
> closeDef->cb = cb;
> - if (virHashAddEntry(driver->closeCallbacks, uuidstr, closeDef) < 0) {
> + if (virHashAddEntry(list, uuidstr, closeDef) < 0) {
> VIR_FREE(closeDef);
> goto cleanup;
> }
> @@ -709,25 +749,28 @@ qemuDriverCloseCallbackSet(virQEMUDriverPtr driver,
>
> ret = 0;
> cleanup:
> - qemuDriverUnlock(driver);
> + virObjectUnlock(driver->closeCallbacks);
> return ret;
> }
>
> int
> -qemuDriverCloseCallbackUnset(virQEMUDriverPtr driver,
> - virDomainObjPtr vm,
> - qemuDriverCloseCallback cb)
> +virQEMUCloseCallbacksUnset(virQEMUDriverPtr driver,
> + virDomainObjPtr vm,
> + virQEMUCloseCallback cb)
> {
> char uuidstr[VIR_UUID_STRING_BUFLEN];
> qemuDriverCloseDefPtr closeDef;
> + virHashTablePtr list;
> int ret = -1;
>
> - qemuDriverLock(driver);
> virUUIDFormat(vm->def->uuid, uuidstr);
> VIR_DEBUG("vm=%s, uuid=%s, cb=%p",
> vm->def->name, uuidstr, cb);
>
> - closeDef = virHashLookup(driver->closeCallbacks, uuidstr);
> + virObjectLock(driver->closeCallbacks);
> +
> + list = driver->closeCallbacks->list;
> + closeDef = virHashLookup(list, uuidstr);
> if (!closeDef)
> goto cleanup;
>
> @@ -738,46 +781,49 @@ qemuDriverCloseCallbackUnset(virQEMUDriverPtr driver,
> goto cleanup;
> }
>
> - ret = virHashRemoveEntry(driver->closeCallbacks, uuidstr);
> + ret = virHashRemoveEntry(list, uuidstr);
> cleanup:
> - qemuDriverUnlock(driver);
> + virObjectUnlock(driver->closeCallbacks);
> return ret;
> }
>
> -qemuDriverCloseCallback
> -qemuDriverCloseCallbackGet(virQEMUDriverPtr driver,
> - virDomainObjPtr vm,
> - virConnectPtr conn)
> +virQEMUCloseCallback
> +virQEMUCloseCallbacksGet(virQEMUDriverPtr driver,
> + virDomainObjPtr vm,
> + virConnectPtr conn)
> {
> char uuidstr[VIR_UUID_STRING_BUFLEN];
> qemuDriverCloseDefPtr closeDef;
> - qemuDriverCloseCallback cb = NULL;
> + virQEMUCloseCallback cb = NULL;
>
> - qemuDriverLock(driver);
> virUUIDFormat(vm->def->uuid, uuidstr);
> VIR_DEBUG("vm=%s, uuid=%s, conn=%p",
> vm->def->name, uuidstr, conn);
>
> - closeDef = virHashLookup(driver->closeCallbacks, uuidstr);
> + virObjectLock(driver->closeCallbacks);
> +
> + closeDef = virHashLookup(driver->closeCallbacks->list, uuidstr);
> if (closeDef && (!conn || closeDef->conn == conn))
> cb = closeDef->cb;
>
> + virObjectUnlock(driver->closeCallbacks);
> +
> VIR_DEBUG("cb=%p", cb);
> - qemuDriverUnlock(driver);
> return cb;
> }
>
> -struct qemuDriverCloseCallbackData {
> +struct virQEMUCloseCallbacksData {
> + virHashTablePtr list;
> virQEMUDriverPtr driver;
> virConnectPtr conn;
> };
>
> static void
> -qemuDriverCloseCallbackRun(void *payload,
> - const void *name,
> - void *opaque)
> +virQEMUCloseCallbacksRunOne(void *payload,
> + const void *name,
> + void *opaque)
> {
> - struct qemuDriverCloseCallbackData *data = opaque;
> + struct virQEMUCloseCallbacksData *data = opaque;
> qemuDriverCloseDefPtr closeDef = payload;
> unsigned char uuid[VIR_UUID_BUFLEN];
> char uuidstr[VIR_UUID_STRING_BUFLEN];
> @@ -808,20 +854,25 @@ qemuDriverCloseCallbackRun(void *payload,
> if (dom)
> virObjectUnlock(dom);
>
> - virHashRemoveEntry(data->driver->closeCallbacks, uuidstr);
> + virHashRemoveEntry(data->list, uuidstr);
> }
>
> void
> -qemuDriverCloseCallbackRunAll(virQEMUDriverPtr driver,
> - virConnectPtr conn)
> +virQEMUCloseCallbacksRun(virQEMUDriverPtr driver,
> + virConnectPtr conn)
> {
> - struct qemuDriverCloseCallbackData data = {
> - driver, conn
> + struct virQEMUCloseCallbacksData data = {
> + .driver = driver,
> + .conn = conn
> };
> +
> VIR_DEBUG("conn=%p", conn);
> - qemuDriverLock(driver);
> - virHashForEach(driver->closeCallbacks, qemuDriverCloseCallbackRun, &data);
> - qemuDriverUnlock(driver);
> + virObjectLock(driver->closeCallbacks);
> +
> + data.list = driver->closeCallbacks->list;
> + virHashForEach(data.list, virQEMUCloseCallbacksRunOne, &data);
> +
> + virObjectUnlock(driver->closeCallbacks);
> }
>
> /* Construct the hash key for sharedDisks as "major:minor" */
> diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
> index 14f1427..72380dc 100644
> --- a/src/qemu/qemu_conf.h
> +++ b/src/qemu/qemu_conf.h
> @@ -47,8 +47,8 @@
>
> # define QEMUD_CPUMASK_LEN CPU_SETSIZE
>
> -typedef struct _qemuDriverCloseDef qemuDriverCloseDef;
> -typedef qemuDriverCloseDef *qemuDriverCloseDefPtr;
> +typedef struct _virQEMUCloseCallbacks virQEMUCloseCallbacks;
> +typedef virQEMUCloseCallbacks *virQEMUCloseCallbacksPtr;
>
> typedef struct _virQEMUDriver virQEMUDriver;
> typedef virQEMUDriver *virQEMUDriverPtr;
> @@ -216,8 +216,8 @@ struct _virQEMUDriver {
> /* Immutable pointer. lockless access */
> virLockManagerPluginPtr lockManager;
>
> - /* Immutable pointer. Unsafe APIs. XXX */
> - virHashTablePtr closeCallbacks;
> + /* Immutable pointer, self-clocking APIs */
> + virQEMUCloseCallbacksPtr closeCallbacks;
> };
>
> typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef;
> @@ -254,23 +254,22 @@ struct qemuDomainDiskInfo {
> int io_status;
> };
>
> -typedef virDomainObjPtr (*qemuDriverCloseCallback)(virQEMUDriverPtr driver,
> - virDomainObjPtr vm,
> - virConnectPtr conn);
> -int qemuDriverCloseCallbackInit(virQEMUDriverPtr driver);
> -void qemuDriverCloseCallbackShutdown(virQEMUDriverPtr driver);
> -int qemuDriverCloseCallbackSet(virQEMUDriverPtr driver,
> +typedef virDomainObjPtr (*virQEMUCloseCallback)(virQEMUDriverPtr driver,
> + virDomainObjPtr vm,
> + virConnectPtr conn);
> +virQEMUCloseCallbacksPtr virQEMUCloseCallbacksNew(void);
> +int virQEMUCloseCallbacksSet(virQEMUDriverPtr driver,
I was rather expecting to see the virQEMUDriverPtr replacd
with a virQEMUCloseCallbacksPtr in all the methods now it
becomes a full object.
> + virDomainObjPtr vm,
> + virConnectPtr conn,
> + virQEMUCloseCallback cb);
> +int virQEMUCloseCallbacksUnset(virQEMUDriverPtr driver,
> virDomainObjPtr vm,
> - virConnectPtr conn,
> - qemuDriverCloseCallback cb);
> -int qemuDriverCloseCallbackUnset(virQEMUDriverPtr driver,
> - virDomainObjPtr vm,
> - qemuDriverCloseCallback cb);
> -qemuDriverCloseCallback qemuDriverCloseCallbackGet(virQEMUDriverPtr driver,
> - virDomainObjPtr vm,
> - virConnectPtr conn);
> -void qemuDriverCloseCallbackRunAll(virQEMUDriverPtr driver,
> - virConnectPtr conn);
> + virQEMUCloseCallback cb);
> +virQEMUCloseCallback virQEMUCloseCallbacksGet(virQEMUDriverPtr driver,
> + virDomainObjPtr vm,
> + virConnectPtr conn);
> +void virQEMUCloseCallbacksRun(virQEMUDriverPtr driver,
> + virConnectPtr conn);
>
> int qemuAddSharedDisk(virQEMUDriverPtr driver,
> const char *disk_path)
ACK to the general approach, but I think there's a few tweaks needed
still.
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
More information about the libvir-list
mailing list