Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.4:ARM
libvirt.29527
c7600931-qemu-rework-dom-caps-cache.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File c7600931-qemu-rework-dom-caps-cache.patch of Package libvirt.29527
commit c76009313f8068c848cad6cb517daf42e6716bb9 Author: Michal Prívozník <mprivozn@redhat.com> Date: Fri Jan 24 10:43:29 2020 +0100 qemu_capabilities: Rework domain caps cache Since v5.6.0-48-g270583ed98 we try to cache domain capabilities, i.e. store filled virDomainCaps in a hash table in virQEMUCaps for future use. However, there's a race condition in the way it's implemented. We use virQEMUCapsGetDomainCapsCache() to obtain the pointer to the hash table, then we search the hash table for cached data and if none is found the domcaps is constructed and put into the table. Problem is that this is all done without any locking, so if there are two threads trying to do the same, one will succeed and the other will fail inserting the data into the table. Also, the API looks a bit fishy - obtaining pointer to the hash table is dangerous. The solution is to use a mutex that guards the whole operation with the hash table. Then, the API can be changes to return virDomainCapsPtr directly. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1791790 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Peter Krempa <pkrempa@redhat.com> Index: libvirt-6.0.0/src/qemu/qemu_capabilities.c =================================================================== --- libvirt-6.0.0.orig/src/qemu/qemu_capabilities.c +++ libvirt-6.0.0/src/qemu/qemu_capabilities.c @@ -595,6 +595,26 @@ struct _virQEMUCapsAccel { qemuMonitorCPUDefsPtr cpuModels; }; + +typedef struct _virQEMUDomainCapsCache virQEMUDomainCapsCache; +typedef virQEMUDomainCapsCache *virQEMUDomainCapsCachePtr; +struct _virQEMUDomainCapsCache { + virObjectLockable parent; + + virHashTablePtr cache; +}; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virQEMUDomainCapsCache, virObjectUnref); + +static virClassPtr virQEMUDomainCapsCacheClass; +static void virQEMUDomainCapsCacheDispose(void *obj) +{ + virQEMUDomainCapsCachePtr cache = obj; + + virHashFree(cache->cache); +} + + /* * Update the XML parser/formatter when adding more * information to this struct so that it gets cached @@ -628,7 +648,7 @@ struct _virQEMUCaps { virArch arch; - virHashTablePtr domCapsCache; + virQEMUDomainCapsCachePtr domCapsCache; size_t ngicCapabilities; virGICCapability *gicCapabilities; @@ -654,6 +674,9 @@ static int virQEMUCapsOnceInit(void) if (!VIR_CLASS_NEW(virQEMUCaps, virClassForObject())) return -1; + if (!(VIR_CLASS_NEW(virQEMUDomainCapsCache, virClassForObjectLockable()))) + return -1; + return 0; } @@ -1623,6 +1646,22 @@ int virQEMUCapsGetDefaultVersion(virCaps } +static virQEMUDomainCapsCachePtr +virQEMUDomainCapsCacheNew(void) +{ + g_autoptr(virQEMUDomainCapsCache) cache = NULL; + + if (virQEMUCapsInitialize() < 0) + return NULL; + + if (!(cache = virObjectLockableNew(virQEMUDomainCapsCacheClass))) + return NULL; + + if (!(cache->cache = virHashCreate(5, virObjectFreeHashData))) + return NULL; + + return g_steal_pointer(&cache); +} virQEMUCapsPtr @@ -1640,7 +1679,7 @@ virQEMUCapsNew(void) if (!(qemuCaps->flags = virBitmapNew(QEMU_CAPS_LAST))) goto error; - if (!(qemuCaps->domCapsCache = virHashCreate(5, virObjectFreeHashData))) + if (!(qemuCaps->domCapsCache = virQEMUDomainCapsCacheNew())) goto error; return qemuCaps; @@ -1832,7 +1871,7 @@ void virQEMUCapsDispose(void *obj) { virQEMUCapsPtr qemuCaps = obj; - virHashFree(qemuCaps->domCapsCache); + virObjectUnref(qemuCaps->domCapsCache); virBitmapFree(qemuCaps->flags); VIR_FREE(qemuCaps->package); @@ -1993,9 +2032,82 @@ const char *virQEMUCapsGetPackage(virQEM } -virHashTablePtr virQEMUCapsGetDomainCapsCache(virQEMUCapsPtr qemuCaps) -{ - return qemuCaps->domCapsCache; +struct virQEMUCapsSearchDomcapsData { + const char *path; + const char *machine; + virArch arch; + virDomainVirtType virttype; +}; + + +static int +virQEMUCapsSearchDomcaps(const void *payload, + const void *name G_GNUC_UNUSED, + const void *opaque) +{ + virDomainCapsPtr domCaps = (virDomainCapsPtr) payload; + struct virQEMUCapsSearchDomcapsData *data = (struct virQEMUCapsSearchDomcapsData *) opaque; + + if (STREQ_NULLABLE(data->path, domCaps->path) && + STREQ_NULLABLE(data->machine, domCaps->machine) && + data->arch == domCaps->arch && + data->virttype == domCaps->virttype) + return 1; + + return 0; +} + + +virDomainCapsPtr +virQEMUCapsGetDomainCapsCache(virQEMUCapsPtr qemuCaps, + const char *machine, + virArch arch, + virDomainVirtType virttype, + virArch hostarch, + bool privileged, + virFirmwarePtr *firmwares, + size_t nfirmwares) +{ + virQEMUDomainCapsCachePtr cache = qemuCaps->domCapsCache; + virDomainCapsPtr domCaps = NULL; + const char *path = virQEMUCapsGetBinary(qemuCaps); + struct virQEMUCapsSearchDomcapsData data = { + .path = path, + .machine = machine, + .arch = arch, + .virttype = virttype, + }; + + virObjectLock(cache); + + domCaps = virHashSearch(cache->cache, virQEMUCapsSearchDomcaps, &data, NULL); + + if (!domCaps) { + g_autoptr(virDomainCaps) tempDomCaps = NULL; + g_autofree char *key = NULL; + + /* hash miss, build new domcaps */ + if (!(tempDomCaps = virDomainCapsNew(path, machine, + arch, virttype))) + goto cleanup; + + if (virQEMUCapsFillDomainCaps(qemuCaps, hostarch, tempDomCaps, + privileged, firmwares, nfirmwares) < 0) + goto cleanup; + + key = g_strdup_printf("%d:%d:%s:%s", arch, virttype, + NULLSTR(machine), path); + + if (virHashAddEntry(cache->cache, key, tempDomCaps) < 0) + goto cleanup; + + domCaps = g_steal_pointer(&tempDomCaps); + } + + virObjectRef(domCaps); + cleanup: + virObjectUnlock(cache); + return domCaps; } Index: libvirt-6.0.0/src/qemu/qemu_capabilities.h =================================================================== --- libvirt-6.0.0.orig/src/qemu/qemu_capabilities.h +++ libvirt-6.0.0/src/qemu/qemu_capabilities.h @@ -571,7 +571,17 @@ const char *virQEMUCapsGetBinary(virQEMU virArch virQEMUCapsGetArch(virQEMUCapsPtr qemuCaps); unsigned int virQEMUCapsGetVersion(virQEMUCapsPtr qemuCaps); const char *virQEMUCapsGetPackage(virQEMUCapsPtr qemuCaps); -virHashTablePtr virQEMUCapsGetDomainCapsCache(virQEMUCapsPtr qemuCaps); + +virDomainCapsPtr +virQEMUCapsGetDomainCapsCache(virQEMUCapsPtr qemuCaps, + const char *machine, + virArch arch, + virDomainVirtType virttype, + virArch hostarch, + bool privileged, + virFirmwarePtr *firmwares, + size_t nfirmwares); + unsigned int virQEMUCapsGetKVMVersion(virQEMUCapsPtr qemuCaps); int virQEMUCapsAddCPUDefinitions(virQEMUCapsPtr qemuCaps, virDomainVirtType type, Index: libvirt-6.0.0/src/qemu/qemu_conf.c =================================================================== --- libvirt-6.0.0.orig/src/qemu/qemu_conf.c +++ libvirt-6.0.0/src/qemu/qemu_conf.c @@ -1328,31 +1328,6 @@ virCapsPtr virQEMUDriverGetCapabilities( } -struct virQEMUDriverSearchDomcapsData { - const char *path; - const char *machine; - virArch arch; - virDomainVirtType virttype; -}; - - -static int -virQEMUDriverSearchDomcaps(const void *payload, - const void *name G_GNUC_UNUSED, - const void *opaque) -{ - virDomainCapsPtr domCaps = (virDomainCapsPtr) payload; - struct virQEMUDriverSearchDomcapsData *data = (struct virQEMUDriverSearchDomcapsData *) opaque; - - if (STREQ_NULLABLE(data->path, domCaps->path) && - STREQ_NULLABLE(data->machine, domCaps->machine) && - data->arch == domCaps->arch && - data->virttype == domCaps->virttype) - return 1; - - return 0; -} - /** * virQEMUDriverGetDomainCapabilities: * @@ -1371,40 +1346,16 @@ virQEMUDriverGetDomainCapabilities(virQE virArch arch, virDomainVirtType virttype) { - g_autoptr(virDomainCaps) domCaps = NULL; g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); - virHashTablePtr domCapsCache = virQEMUCapsGetDomainCapsCache(qemuCaps); - struct virQEMUDriverSearchDomcapsData data = { - .path = virQEMUCapsGetBinary(qemuCaps), - .machine = machine, - .arch = arch, - .virttype = virttype, - }; - - domCaps = virHashSearch(domCapsCache, - virQEMUDriverSearchDomcaps, &data, NULL); - if (!domCaps) { - g_autofree char *key = NULL; - - /* hash miss, build new domcaps */ - if (!(domCaps = virDomainCapsNew(data.path, data.machine, - data.arch, data.virttype))) - return NULL; - - if (virQEMUCapsFillDomainCaps(qemuCaps, driver->hostarch, domCaps, - driver->privileged, - cfg->firmwares, cfg->nfirmwares) < 0) - return NULL; - - key = g_strdup_printf("%d:%d:%s:%s", data.arch, data.virttype, - NULLSTR(data.machine), NULLSTR(data.path)); - - if (virHashAddEntry(domCapsCache, key, domCaps) < 0) - return NULL; - } - virObjectRef(domCaps); - return g_steal_pointer(&domCaps); + return virQEMUCapsGetDomainCapsCache(qemuCaps, + machine, + arch, + virttype, + driver->hostarch, + driver->privileged, + cfg->firmwares, + cfg->nfirmwares); }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor