mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-07 17:28:15 +00:00
conf: Refactor domain list collection critical section
Until now the virDomainListAllDomains API would lock the domain list and then every single domain object to access and filter it. This would potentially allow a unresponsive VM to block the whole daemon if a *listAllDomains call would get stuck. To avoid this problem this patch collects a list of referenced domain objects first from the list and then unlocks it right away. The expensive operation requiring locking of the domain object is executed after the list lock is dropped. While a single blocked domain will still lock up a listAllDomains call, the domain list won't be held locked and thus other APIs won't be blocked. Additionally this patch also fixes the lookup code, where we'd ignore the vm->removing flag and thus potentially return domain objects that would be deleted very soon so calling any API wouldn't make sense. As other clients also could benefit from operating on a list of domain objects rather than the public domain descriptors a new intermediate API - virDomainObjListCollect - is introduced by this patch. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1181074
This commit is contained in:
parent
7906d5fbbb
commit
cbe7bbf722
@ -23031,98 +23031,132 @@ virDomainObjMatchFilter(virDomainObjPtr vm,
|
|||||||
|
|
||||||
|
|
||||||
struct virDomainListData {
|
struct virDomainListData {
|
||||||
virConnectPtr conn;
|
virDomainObjPtr *vms;
|
||||||
virDomainPtr *domains;
|
size_t nvms;
|
||||||
virDomainObjListACLFilter filter;
|
|
||||||
unsigned int flags;
|
|
||||||
int ndomains;
|
|
||||||
bool error;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
virDomainListPopulate(void *payload,
|
virDomainObjListCollectIterator(void *payload,
|
||||||
const void *name ATTRIBUTE_UNUSED,
|
const void *name ATTRIBUTE_UNUSED,
|
||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
struct virDomainListData *data = opaque;
|
struct virDomainListData *data = opaque;
|
||||||
virDomainObjPtr vm = payload;
|
|
||||||
virDomainPtr dom;
|
|
||||||
|
|
||||||
if (data->error)
|
data->vms[data->nvms++] = virObjectRef(payload);
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
virDomainObjListFilter(virDomainObjPtr **list,
|
||||||
|
size_t *nvms,
|
||||||
|
virConnectPtr conn,
|
||||||
|
virDomainObjListACLFilter filter,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
while (i < *nvms) {
|
||||||
|
virDomainObjPtr vm = (*list)[i];
|
||||||
|
|
||||||
virObjectLock(vm);
|
virObjectLock(vm);
|
||||||
/* check if the domain matches the filter */
|
|
||||||
|
|
||||||
/* filter by the callback function (access control checks) */
|
/* do not list the object if:
|
||||||
if (data->filter != NULL &&
|
* 1) it's being removed.
|
||||||
!data->filter(data->conn, vm->def))
|
* 2) connection does not have ACL to see it
|
||||||
goto cleanup;
|
* 3) it doesn't match the filter
|
||||||
|
*/
|
||||||
if (!virDomainObjMatchFilter(vm, data->flags))
|
if (vm->removing ||
|
||||||
goto cleanup;
|
(filter && !filter(conn, vm->def)) ||
|
||||||
|
!virDomainObjMatchFilter(vm, flags)) {
|
||||||
/* just count the machines */
|
|
||||||
if (!data->domains) {
|
|
||||||
data->ndomains++;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(dom = virGetDomain(data->conn, vm->def->name, vm->def->uuid))) {
|
|
||||||
data->error = true;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
dom->id = vm->def->id;
|
|
||||||
|
|
||||||
data->domains[data->ndomains++] = dom;
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
virObjectUnlock(vm);
|
virObjectUnlock(vm);
|
||||||
return;
|
virObjectUnref(vm);
|
||||||
|
VIR_DELETE_ELEMENT(*list, i, *nvms);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
virObjectUnlock(vm);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
virDomainObjListExport(virDomainObjListPtr doms,
|
virDomainObjListCollect(virDomainObjListPtr domlist,
|
||||||
|
virConnectPtr conn,
|
||||||
|
virDomainObjPtr **vms,
|
||||||
|
size_t *nvms,
|
||||||
|
virDomainObjListACLFilter filter,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
struct virDomainListData data = { NULL, 0 };
|
||||||
|
|
||||||
|
virObjectLock(domlist);
|
||||||
|
if (VIR_ALLOC_N(data.vms, virHashSize(domlist->objs)) < 0) {
|
||||||
|
virObjectUnlock(domlist);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
virHashForEach(domlist->objs, virDomainObjListCollectIterator, &data);
|
||||||
|
virObjectUnlock(domlist);
|
||||||
|
|
||||||
|
virDomainObjListFilter(&data.vms, &data.nvms, conn, filter, flags);
|
||||||
|
|
||||||
|
*nvms = data.nvms;
|
||||||
|
*vms = data.vms;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
virDomainObjListExport(virDomainObjListPtr domlist,
|
||||||
virConnectPtr conn,
|
virConnectPtr conn,
|
||||||
virDomainPtr **domains,
|
virDomainPtr **domains,
|
||||||
virDomainObjListACLFilter filter,
|
virDomainObjListACLFilter filter,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
|
virDomainObjPtr *vms = NULL;
|
||||||
|
virDomainPtr *doms = NULL;
|
||||||
|
size_t nvms = 0;
|
||||||
|
size_t i;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
struct virDomainListData data = {
|
if (virDomainObjListCollect(domlist, conn, &vms, &nvms, filter, flags) < 0)
|
||||||
conn, NULL,
|
return -1;
|
||||||
filter,
|
|
||||||
flags, 0, false
|
|
||||||
};
|
|
||||||
|
|
||||||
virObjectLock(doms);
|
if (domains) {
|
||||||
if (domains &&
|
if (VIR_ALLOC_N(doms, nvms + 1) < 0)
|
||||||
VIR_ALLOC_N(data.domains, virHashSize(doms->objs) + 1) < 0)
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
virHashForEach(doms->objs, virDomainListPopulate, &data);
|
for (i = 0; i < nvms; i++) {
|
||||||
|
virDomainObjPtr vm = vms[i];
|
||||||
|
|
||||||
if (data.error)
|
virObjectLock(vm);
|
||||||
|
|
||||||
|
if (!(doms[i] = virGetDomain(conn, vm->def->name, vm->def->uuid))) {
|
||||||
|
virObjectUnlock(vm);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (data.domains) {
|
|
||||||
/* trim the array to the final size */
|
|
||||||
ignore_value(VIR_REALLOC_N(data.domains, data.ndomains + 1));
|
|
||||||
*domains = data.domains;
|
|
||||||
data.domains = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = data.ndomains;
|
doms[i]->id = vm->def->id;
|
||||||
|
|
||||||
|
virObjectUnlock(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
*domains = doms;
|
||||||
|
doms = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nvms;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
virObjectListFree(data.domains);
|
virObjectListFree(doms);
|
||||||
virObjectUnlock(doms);
|
virObjectListFreeCount(vms, nvms);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virSecurityLabelDefPtr
|
virSecurityLabelDefPtr
|
||||||
virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model)
|
virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model)
|
||||||
{
|
{
|
||||||
|
@ -3051,6 +3051,12 @@ VIR_ENUM_DECL(virDomainStartupPolicy)
|
|||||||
VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART | \
|
VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART | \
|
||||||
VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)
|
VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)
|
||||||
|
|
||||||
|
int virDomainObjListCollect(virDomainObjListPtr doms,
|
||||||
|
virConnectPtr conn,
|
||||||
|
virDomainObjPtr **vms,
|
||||||
|
size_t *nvms,
|
||||||
|
virDomainObjListACLFilter filter,
|
||||||
|
unsigned int flags);
|
||||||
int virDomainObjListExport(virDomainObjListPtr doms,
|
int virDomainObjListExport(virDomainObjListPtr doms,
|
||||||
virConnectPtr conn,
|
virConnectPtr conn,
|
||||||
virDomainPtr **domains,
|
virDomainPtr **domains,
|
||||||
|
@ -385,6 +385,7 @@ virDomainObjGetMetadata;
|
|||||||
virDomainObjGetPersistentDef;
|
virDomainObjGetPersistentDef;
|
||||||
virDomainObjGetState;
|
virDomainObjGetState;
|
||||||
virDomainObjListAdd;
|
virDomainObjListAdd;
|
||||||
|
virDomainObjListCollect;
|
||||||
virDomainObjListExport;
|
virDomainObjListExport;
|
||||||
virDomainObjListFindByID;
|
virDomainObjListFindByID;
|
||||||
virDomainObjListFindByName;
|
virDomainObjListFindByName;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user