Originally/discovered proposed by "Wang King <king.wang@xxxxxxxxxx>" When the virCloseCallbacksSet is first called, it increments the refcnt on the domain object to ensure it doesn't get deleted before the callback is called. The refcnt would be decremented in virCloseCallbacksUnset once the entry is removed from the closeCallbacks has table. When (mostly) normal shutdown occurs, the qemuProcessStop will end up calling qemuProcessAutoDestroyRemove and will remove the callback from the list and hash table normally and decrement the refcnt. However, when qemuConnectClose calls virCloseCallbacksRun, it will scan the (locked) closeCallbacks list for matching domain and callback function. If an entry is found, it will be removed from the closeCallbacks list and placed into a lookaside list to be processed when the closeCallbacks lock is dropped. The callback function (e.g. qemuProcessAutoDestroy) is called and will run qemuProcessStop. That code will fail to find the callback in the list when qemuProcessAutoDestroyRemove is called and thus not decrement the domain refcnt. Instead since the entry isn't found the code will just return (mostly) harmlessly. This patch will resolve the issue by taking another ref during the search UUID process during virCloseCallackRun, decrementing the refcnt taken by virCloseCallbacksSet, calling the callback routine and returning overwriting the vm (since it could return NULL). Finally, it will call the virDomainObjEndAPI to lower the refcnt and remove the lock taken during the search UUID processing. This may cause the vm to be destroyed. Signed-off-by: John Ferlan <jferlan@xxxxxxxxxx> --- src/util/virclosecallbacks.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/util/virclosecallbacks.c b/src/util/virclosecallbacks.c index 2f430cf..4db50e8 100644 --- a/src/util/virclosecallbacks.c +++ b/src/util/virclosecallbacks.c @@ -346,17 +346,24 @@ virCloseCallbacksRun(virCloseCallbacksPtr closeCallbacks, for (i = 0; i < list->nentries; i++) { virDomainObjPtr vm; - if (!(vm = virDomainObjListFindByUUID(domains, - list->entries[i].uuid))) { + /* Grab a ref and lock to the vm */ + if (!(vm = virDomainObjListFindByUUIDRef(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); + /* 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). + * + * Call the callback function, ignoring the return since it might be + * NULL. Once we're done with the object, then end the API usage. */ + virObjectUnref(vm); + ignore_value(list->entries[i].callback(vm, conn, opaque)); + virDomainObjEndAPI(&vm); } VIR_FREE(list->entries); VIR_FREE(list); -- 2.7.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list