2013-07-15 16:53:13 +02:00
|
|
|
/*
|
|
|
|
* virclosecallbacks.c: Connection close callbacks routines
|
|
|
|
*
|
2014-04-04 17:36:25 -06:00
|
|
|
* Copyright (C) 2013-2014 Red Hat, Inc.
|
2013-07-15 16:53:13 +02:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("util.closecallbacks");
|
|
|
|
|
2013-07-15 16:53:13 +02:00
|
|
|
typedef struct _virDriverCloseDef virDriverCloseDef;
|
|
|
|
struct _virDriverCloseDef {
|
|
|
|
virConnectPtr conn;
|
|
|
|
virCloseCallback cb;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _virCloseCallbacks {
|
|
|
|
virObjectLockable parent;
|
|
|
|
|
|
|
|
/* UUID string to qemuDriverCloseDef mapping */
|
2020-10-22 19:04:18 +02:00
|
|
|
GHashTable *list;
|
2013-07-15 16:53:13 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
static virClass *virCloseCallbacksClass;
|
2013-07-15 16:53:13 +02:00
|
|
|
static void virCloseCallbacksDispose(void *obj);
|
|
|
|
|
|
|
|
static int virCloseCallbacksOnceInit(void)
|
|
|
|
{
|
2018-04-17 17:42:33 +02:00
|
|
|
if (!VIR_CLASS_NEW(virCloseCallbacks, virClassForObjectLockable()))
|
2013-07-15 16:53:13 +02:00
|
|
|
return -1;
|
2018-04-17 17:42:33 +02:00
|
|
|
|
|
|
|
return 0;
|
2013-07-15 16:53:13 +02:00
|
|
|
}
|
|
|
|
|
2019-01-20 12:23:29 -05:00
|
|
|
VIR_ONCE_GLOBAL_INIT(virCloseCallbacks);
|
2013-07-15 16:53:13 +02:00
|
|
|
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
virCloseCallbacks *
|
2013-07-15 16:53:13 +02:00
|
|
|
virCloseCallbacksNew(void)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virCloseCallbacks *closeCallbacks;
|
2013-07-15 16:53:13 +02:00
|
|
|
|
|
|
|
if (virCloseCallbacksInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!(closeCallbacks = virObjectLockableNew(virCloseCallbacksClass)))
|
|
|
|
return NULL;
|
|
|
|
|
2020-10-21 12:08:22 +02:00
|
|
|
closeCallbacks->list = virHashNew(g_free);
|
2013-07-15 16:53:13 +02:00
|
|
|
if (!closeCallbacks->list) {
|
|
|
|
virObjectUnref(closeCallbacks);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return closeCallbacks;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
virCloseCallbacksDispose(void *obj)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virCloseCallbacks *closeCallbacks = obj;
|
2013-07-15 16:53:13 +02:00
|
|
|
|
|
|
|
virHashFree(closeCallbacks->list);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virCloseCallbacksSet(virCloseCallbacks *closeCallbacks,
|
|
|
|
virDomainObj *vm,
|
2013-07-15 16:53:13 +02:00
|
|
|
virConnectPtr conn,
|
|
|
|
virCloseCallback cb)
|
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2021-03-11 08:16:13 +01:00
|
|
|
virDriverCloseDef *closeDef;
|
2013-07-15 16:53:13 +02:00
|
|
|
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 {
|
2020-09-23 20:44:29 +02:00
|
|
|
closeDef = g_new0(virDriverCloseDef, 1);
|
2013-07-15 16:53:13 +02:00
|
|
|
closeDef->conn = conn;
|
|
|
|
closeDef->cb = cb;
|
|
|
|
if (virHashAddEntry(closeCallbacks->list, uuidstr, closeDef) < 0) {
|
|
|
|
VIR_FREE(closeDef);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
qemu: completely rework reference counting
There is one problem that causes various errors in the daemon. When
domain is waiting for a job, it is unlocked while waiting on the
condition. However, if that domain is for example transient and being
removed in another API (e.g. cancelling incoming migration), it get's
unref'd. If the first call, that was waiting, fails to get the job, it
unref's the domain object, and because it was the last reference, it
causes clearing of the whole domain object. However, when finishing the
call, the domain must be unlocked, but there is no way for the API to
know whether it was cleaned or not (unless there is some ugly temporary
variable, but let's scratch that).
The root cause is that our APIs don't ref the objects they are using and
all use the implicit reference that the object has when it is in the
domain list. That reference can be removed when the API is waiting for
a job. And because each domain doesn't do its ref'ing, it results in
the ugly checking of the return value of virObjectUnref() that we have
everywhere.
This patch changes qemuDomObjFromDomain() to ref the domain (using
virDomainObjListFindByUUIDRef()) and adds qemuDomObjEndAPI() which
should be the only function in which the return value of
virObjectUnref() is checked. This makes all reference counting
deterministic and makes the code a bit clearer.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2014-12-04 14:41:36 +01:00
|
|
|
virObjectRef(vm);
|
2013-07-15 16:53:13 +02:00
|
|
|
}
|
|
|
|
|
util: fix crash in virClassIsDerivedFrom for CloseCallbacks objects
There is a possibility that qemu driver frees by unreferencing its
closeCallbacks pointer as it has the only reference to the object,
while in fact not all users of CloseCallbacks called thier
virCloseCallbacksUnset.
Backtrace is the following:
Thread #1:
0 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
1 in virCondWait (c=<optimized out>, m=<optimized out>)
at util/virthread.c:154
2 in virThreadPoolFree (pool=0x7f0810110b50)
at util/virthreadpool.c:266
3 in qemuStateCleanup () at qemu/qemu_driver.c:1116
4 in virStateCleanup () at libvirt.c:808
5 in main (argc=<optimized out>, argv=<optimized out>)
at libvirtd.c:1660
Thread #2:
0 in virClassIsDerivedFrom (klass=0xdeadbeef, parent=0x7f0837c694d0) at util/virobject.c:169
1 in virObjectIsClass (anyobj=anyobj@entry=0x7f08101d4760, klass=<optimized out>) at util/virobject.c:365
2 in virObjectLock (anyobj=0x7f08101d4760) at util/virobject.c:317
3 in virCloseCallbacksUnset (closeCallbacks=0x7f08101d4760, vm=vm@entry=0x7f08101d47b0, cb=cb@entry=0x7f081d078fc0 <qemuProcessAutoDestroy>) at util/virclosecallbacks.c:163
4 in qemuProcessAutoDestroyRemove (driver=driver@entry=0x7f081018be50, vm=vm@entry=0x7f08101d47b0) at qemu/qemu_process.c:6368
5 in qemuProcessStop (driver=driver@entry=0x7f081018be50, vm=vm@entry=0x7f08101d47b0, reason=reason@entry=VIR_DOMAIN_SHUTOFF_SHUTDOWN, asyncJob=asyncJob@entry=QEMU_ASYNC_JOB_NONE, flags=flags@entry=0) at qemu/qemu_process.c:5854
6 in processMonitorEOFEvent (vm=0x7f08101d47b0, driver=0x7f081018be50) at qemu/qemu_driver.c:4585
7 qemuProcessEventHandler (data=<optimized out>, opaque=0x7f081018be50) at qemu/qemu_driver.c:4629
8 in virThreadPoolWorker (opaque=opaque@entry=0x7f0837c4f820) at util/virthreadpool.c:145
9 in virThreadHelper (data=<optimized out>) at util/virthread.c:206
10 in start_thread () from /lib64/libpthread.so.0
Let's reference CloseCallbacks object in virCloseCallbacksSet and
unreference in virCloseCallbacksUnset.
Signed-off-by: Maxim Nestratov <mnestratov@virtuozzo.com>
2016-06-06 17:42:16 +03:00
|
|
|
virObjectRef(closeCallbacks);
|
2013-07-15 16:53:13 +02:00
|
|
|
ret = 0;
|
2014-03-25 07:53:22 +01:00
|
|
|
cleanup:
|
2013-07-15 16:53:13 +02:00
|
|
|
virObjectUnlock(closeCallbacks);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virCloseCallbacksUnset(virCloseCallbacks *closeCallbacks,
|
|
|
|
virDomainObj *vm,
|
2013-07-15 16:53:13 +02:00
|
|
|
virCloseCallback cb)
|
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2021-03-11 08:16:13 +01:00
|
|
|
virDriverCloseDef *closeDef;
|
2013-07-15 16:53:13 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
qemu: completely rework reference counting
There is one problem that causes various errors in the daemon. When
domain is waiting for a job, it is unlocked while waiting on the
condition. However, if that domain is for example transient and being
removed in another API (e.g. cancelling incoming migration), it get's
unref'd. If the first call, that was waiting, fails to get the job, it
unref's the domain object, and because it was the last reference, it
causes clearing of the whole domain object. However, when finishing the
call, the domain must be unlocked, but there is no way for the API to
know whether it was cleaned or not (unless there is some ugly temporary
variable, but let's scratch that).
The root cause is that our APIs don't ref the objects they are using and
all use the implicit reference that the object has when it is in the
domain list. That reference can be removed when the API is waiting for
a job. And because each domain doesn't do its ref'ing, it results in
the ugly checking of the return value of virObjectUnref() that we have
everywhere.
This patch changes qemuDomObjFromDomain() to ref the domain (using
virDomainObjListFindByUUIDRef()) and adds qemuDomObjEndAPI() which
should be the only function in which the return value of
virObjectUnref() is checked. This makes all reference counting
deterministic and makes the code a bit clearer.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2014-12-04 14:41:36 +01:00
|
|
|
if (virHashRemoveEntry(closeCallbacks->list, uuidstr) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virObjectUnref(vm);
|
|
|
|
ret = 0;
|
2014-03-25 07:53:22 +01:00
|
|
|
cleanup:
|
2013-07-15 16:53:13 +02:00
|
|
|
virObjectUnlock(closeCallbacks);
|
util: fix crash in virClassIsDerivedFrom for CloseCallbacks objects
There is a possibility that qemu driver frees by unreferencing its
closeCallbacks pointer as it has the only reference to the object,
while in fact not all users of CloseCallbacks called thier
virCloseCallbacksUnset.
Backtrace is the following:
Thread #1:
0 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
1 in virCondWait (c=<optimized out>, m=<optimized out>)
at util/virthread.c:154
2 in virThreadPoolFree (pool=0x7f0810110b50)
at util/virthreadpool.c:266
3 in qemuStateCleanup () at qemu/qemu_driver.c:1116
4 in virStateCleanup () at libvirt.c:808
5 in main (argc=<optimized out>, argv=<optimized out>)
at libvirtd.c:1660
Thread #2:
0 in virClassIsDerivedFrom (klass=0xdeadbeef, parent=0x7f0837c694d0) at util/virobject.c:169
1 in virObjectIsClass (anyobj=anyobj@entry=0x7f08101d4760, klass=<optimized out>) at util/virobject.c:365
2 in virObjectLock (anyobj=0x7f08101d4760) at util/virobject.c:317
3 in virCloseCallbacksUnset (closeCallbacks=0x7f08101d4760, vm=vm@entry=0x7f08101d47b0, cb=cb@entry=0x7f081d078fc0 <qemuProcessAutoDestroy>) at util/virclosecallbacks.c:163
4 in qemuProcessAutoDestroyRemove (driver=driver@entry=0x7f081018be50, vm=vm@entry=0x7f08101d47b0) at qemu/qemu_process.c:6368
5 in qemuProcessStop (driver=driver@entry=0x7f081018be50, vm=vm@entry=0x7f08101d47b0, reason=reason@entry=VIR_DOMAIN_SHUTOFF_SHUTDOWN, asyncJob=asyncJob@entry=QEMU_ASYNC_JOB_NONE, flags=flags@entry=0) at qemu/qemu_process.c:5854
6 in processMonitorEOFEvent (vm=0x7f08101d47b0, driver=0x7f081018be50) at qemu/qemu_driver.c:4585
7 qemuProcessEventHandler (data=<optimized out>, opaque=0x7f081018be50) at qemu/qemu_driver.c:4629
8 in virThreadPoolWorker (opaque=opaque@entry=0x7f0837c4f820) at util/virthreadpool.c:145
9 in virThreadHelper (data=<optimized out>) at util/virthread.c:206
10 in start_thread () from /lib64/libpthread.so.0
Let's reference CloseCallbacks object in virCloseCallbacksSet and
unreference in virCloseCallbacksUnset.
Signed-off-by: Maxim Nestratov <mnestratov@virtuozzo.com>
2016-06-06 17:42:16 +03:00
|
|
|
if (!ret)
|
|
|
|
virObjectUnref(closeCallbacks);
|
2013-07-15 16:53:13 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCloseCallback
|
2021-03-11 08:16:13 +01:00
|
|
|
virCloseCallbacksGet(virCloseCallbacks *closeCallbacks,
|
|
|
|
virDomainObj *vm,
|
2013-07-15 16:53:13 +02:00
|
|
|
virConnectPtr conn)
|
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2021-03-11 08:16:13 +01:00
|
|
|
virDriverCloseDef *closeDef;
|
2013-07-15 16:53:13 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-07-15 19:08:11 +02:00
|
|
|
virConnectPtr
|
2021-03-11 08:16:13 +01:00
|
|
|
virCloseCallbacksGetConn(virCloseCallbacks *closeCallbacks,
|
|
|
|
virDomainObj *vm)
|
2013-07-15 19:08:11 +02:00
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2021-03-11 08:16:13 +01:00
|
|
|
virDriverCloseDef *closeDef;
|
2013-07-15 19:08:11 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-15 16:53:13 +02:00
|
|
|
typedef struct _virCloseCallbacksListEntry virCloseCallbacksListEntry;
|
|
|
|
struct _virCloseCallbacksListEntry {
|
|
|
|
unsigned char uuid[VIR_UUID_BUFLEN];
|
|
|
|
virCloseCallback callback;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct _virCloseCallbacksList virCloseCallbacksList;
|
|
|
|
struct _virCloseCallbacksList {
|
|
|
|
size_t nentries;
|
2021-03-11 08:16:13 +01:00
|
|
|
virCloseCallbacksListEntry *entries;
|
2013-07-15 16:53:13 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct virCloseCallbacksData {
|
|
|
|
virConnectPtr conn;
|
2021-03-11 08:16:13 +01:00
|
|
|
virCloseCallbacksList *list;
|
2013-07-15 16:53:13 +02:00
|
|
|
};
|
|
|
|
|
2016-02-12 10:03:50 +01:00
|
|
|
static int
|
2013-07-15 16:53:13 +02:00
|
|
|
virCloseCallbacksGetOne(void *payload,
|
2020-10-21 13:31:16 +02:00
|
|
|
const char *key,
|
2013-07-15 16:53:13 +02:00
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
struct virCloseCallbacksData *data = opaque;
|
2021-03-11 08:16:13 +01:00
|
|
|
virDriverCloseDef *closeDef = payload;
|
2013-07-15 16:53:13 +02:00
|
|
|
const char *uuidstr = key;
|
|
|
|
unsigned char uuid[VIR_UUID_BUFLEN];
|
|
|
|
|
|
|
|
if (virUUIDParse(uuidstr, uuid) < 0)
|
2016-02-12 10:03:50 +01:00
|
|
|
return 0;
|
2013-07-15 16:53:13 +02:00
|
|
|
|
|
|
|
VIR_DEBUG("conn=%p, thisconn=%p, uuid=%s, cb=%p",
|
|
|
|
closeDef->conn, data->conn, uuidstr, closeDef->cb);
|
|
|
|
|
|
|
|
if (data->conn != closeDef->conn || !closeDef->cb)
|
2016-02-12 10:03:50 +01:00
|
|
|
return 0;
|
2013-07-15 16:53:13 +02:00
|
|
|
|
2021-03-20 00:37:03 +01:00
|
|
|
VIR_EXPAND_N(data->list->entries, data->list->nentries, 1);
|
2013-07-15 16:53:13 +02:00
|
|
|
|
|
|
|
memcpy(data->list->entries[data->list->nentries - 1].uuid,
|
|
|
|
uuid, VIR_UUID_BUFLEN);
|
|
|
|
data->list->entries[data->list->nentries - 1].callback = closeDef->cb;
|
2016-02-12 10:03:50 +01:00
|
|
|
return 0;
|
2013-07-15 16:53:13 +02:00
|
|
|
}
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
static virCloseCallbacksList *
|
|
|
|
virCloseCallbacksGetForConn(virCloseCallbacks *closeCallbacks,
|
2013-07-15 16:53:13 +02:00
|
|
|
virConnectPtr conn)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virCloseCallbacksList *list = NULL;
|
2013-07-15 16:53:13 +02:00
|
|
|
struct virCloseCallbacksData data;
|
|
|
|
|
2020-09-23 20:44:29 +02:00
|
|
|
list = g_new0(virCloseCallbacksList, 1);
|
2013-07-15 16:53:13 +02:00
|
|
|
|
|
|
|
data.conn = conn;
|
|
|
|
data.list = list;
|
|
|
|
|
|
|
|
virHashForEach(closeCallbacks->list, virCloseCallbacksGetOne, &data);
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virCloseCallbacksRun(virCloseCallbacks *closeCallbacks,
|
2013-07-15 16:53:13 +02:00
|
|
|
virConnectPtr conn,
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainObjList *domains,
|
2013-07-15 16:53:13 +02:00
|
|
|
void *opaque)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virCloseCallbacksList *list;
|
2013-07-15 16:53:13 +02:00
|
|
|
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);
|
2017-01-10 14:23:49 +08:00
|
|
|
if (!list) {
|
2017-01-21 12:46:09 -05:00
|
|
|
virObjectUnlock(closeCallbacks);
|
2013-07-15 16:53:13 +02:00
|
|
|
return;
|
2017-01-10 14:23:49 +08:00
|
|
|
}
|
2013-07-15 16:53:13 +02:00
|
|
|
|
|
|
|
for (i = 0; i < list->nentries; i++) {
|
2015-04-08 13:22:39 +10:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(list->entries[i].uuid, uuidstr);
|
|
|
|
virHashRemoveEntry(closeCallbacks->list, uuidstr);
|
2013-07-15 16:53:13 +02:00
|
|
|
}
|
|
|
|
virObjectUnlock(closeCallbacks);
|
|
|
|
|
|
|
|
for (i = 0; i < list->nentries; i++) {
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainObj *vm;
|
2013-07-15 16:53:13 +02:00
|
|
|
|
2017-01-21 12:59:14 -05:00
|
|
|
/* Grab a ref and lock to the vm */
|
2018-03-09 10:47:46 -05:00
|
|
|
if (!(vm = virDomainObjListFindByUUID(domains,
|
|
|
|
list->entries[i].uuid))) {
|
2013-07-15 16:53:13 +02:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(list->entries[i].uuid, uuidstr);
|
|
|
|
VIR_DEBUG("No domain object with UUID %s", uuidstr);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-21 12:59:14 -05:00
|
|
|
/* 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).
|
|
|
|
*
|
2018-03-27 11:39:53 -04:00
|
|
|
* Call the callback function and end the API usage. */
|
2017-01-21 12:59:14 -05:00
|
|
|
virObjectUnref(vm);
|
2018-03-27 11:39:53 -04:00
|
|
|
list->entries[i].callback(vm, conn, opaque);
|
2017-01-21 12:59:14 -05:00
|
|
|
virDomainObjEndAPI(&vm);
|
2013-07-15 16:53:13 +02:00
|
|
|
}
|
|
|
|
VIR_FREE(list->entries);
|
|
|
|
VIR_FREE(list);
|
|
|
|
}
|