mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-11 09:17:52 +03:00
Fix potential events deadlock when unref'ing virConnectPtr
When the last reference to a virConnectPtr is released by libvirtd, it was possible for a deadlock to occur in the virDomainEventState functions. The virDomainEventStatePtr holds a reference on virConnectPtr for each registered callback. When removing a callback, the virUnrefConnect function is run. If this causes the last reference on the virConnectPtr to be released, then virReleaseConnect can be run, which in turns calls qemudClose. This function has a call to virDomainEventStateDeregisterConn which is intended to remove all callbacks associated with the virConnectPtr instance. This will try to grab a lock on virDomainEventState but this lock is already held. Deadlock ensues Thread 1 (Thread 0x7fcbb526a840 (LWP 23185)): Since each callback associated with a virConnectPtr holds a reference on virConnectPtr, it is impossible for the qemudClose method to be invoked while any callbacks are still registered. Thus the call to virDomainEventStateDeregisterConn must in fact be a no-op. Thus it is possible to just remove all trace of virDomainEventStateDeregisterConn and avoid the deadlock. * src/conf/domain_event.c, src/conf/domain_event.h, src/libvirt_private.syms: Delete virDomainEventStateDeregisterConn * src/libxl/libxl_driver.c, src/lxc/lxc_driver.c, src/qemu/qemu_driver.c, src/uml/uml_driver.c: Remove calls to virDomainEventStateDeregisterConn
This commit is contained in:
parent
651d712452
commit
2cb0899eec
@ -248,45 +248,6 @@ virDomainEventCallbackListRemoveID(virConnectPtr conn,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* virDomainEventCallbackListRemoveConn:
|
||||
* @conn: pointer to the connection
|
||||
* @cbList: the list
|
||||
*
|
||||
* Internal function to remove all of a given connection's callback
|
||||
* from a virDomainEventCallbackListPtr
|
||||
*/
|
||||
static int
|
||||
virDomainEventCallbackListRemoveConn(virConnectPtr conn,
|
||||
virDomainEventCallbackListPtr cbList)
|
||||
{
|
||||
int old_count = cbList->count;
|
||||
int i;
|
||||
for (i = 0 ; i < cbList->count ; i++) {
|
||||
if (cbList->callbacks[i]->conn == conn) {
|
||||
virFreeCallback freecb = cbList->callbacks[i]->freecb;
|
||||
if (freecb)
|
||||
(*freecb)(cbList->callbacks[i]->opaque);
|
||||
virUnrefConnect(cbList->callbacks[i]->conn);
|
||||
VIR_FREE(cbList->callbacks[i]);
|
||||
|
||||
if (i < (cbList->count - 1))
|
||||
memmove(cbList->callbacks + i,
|
||||
cbList->callbacks + i + 1,
|
||||
sizeof(*(cbList->callbacks)) *
|
||||
(cbList->count - (i + 1)));
|
||||
cbList->count--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (cbList->count < old_count &&
|
||||
VIR_REALLOC_N(cbList->callbacks, cbList->count) < 0) {
|
||||
; /* Failure to reduce memory allocation isn't fatal */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virDomainEventCallbackListMarkDelete(virConnectPtr conn,
|
||||
virDomainEventCallbackListPtr cbList,
|
||||
@ -1607,28 +1568,6 @@ virDomainEventStateDeregisterID(virConnectPtr conn,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* virDomainEventStateDeregisterConn:
|
||||
* @conn: connection to associate with callbacks
|
||||
* @state: domain event state
|
||||
*
|
||||
* Remove all callbacks from @state associated with the
|
||||
* connection @conn
|
||||
*
|
||||
* Returns 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
virDomainEventStateDeregisterConn(virConnectPtr conn,
|
||||
virDomainEventStatePtr state)
|
||||
{
|
||||
int ret;
|
||||
virDomainEventStateLock(state);
|
||||
ret = virDomainEventCallbackListRemoveConn(conn, state->callbacks);
|
||||
virDomainEventStateUnlock(state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* virDomainEventStateEventID:
|
||||
* @conn: connection associated with the callback
|
||||
|
@ -161,10 +161,6 @@ virDomainEventStateDeregisterID(virConnectPtr conn,
|
||||
int callbackID)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
int
|
||||
virDomainEventStateDeregisterConn(virConnectPtr conn,
|
||||
virDomainEventStatePtr state)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
int
|
||||
virDomainEventStateEventID(virConnectPtr conn,
|
||||
virDomainEventStatePtr state,
|
||||
int callbackID)
|
||||
|
@ -522,7 +522,6 @@ virDomainEventRebootNewFromDom;
|
||||
virDomainEventRebootNewFromObj;
|
||||
virDomainEventStateDeregister;
|
||||
virDomainEventStateDeregisterID;
|
||||
virDomainEventStateDeregisterConn;
|
||||
virDomainEventStateEventID;
|
||||
virDomainEventStateRegister;
|
||||
virDomainEventStateRegisterID;
|
||||
|
@ -1081,10 +1081,6 @@ libxlClose(virConnectPtr conn ATTRIBUTE_UNUSED)
|
||||
{
|
||||
libxlDriverPrivatePtr driver = conn->privateData;
|
||||
|
||||
libxlDriverLock(driver);
|
||||
virDomainEventStateDeregisterConn(conn,
|
||||
driver->domainEventState);
|
||||
libxlDriverUnlock(driver);
|
||||
conn->privateData = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
@ -178,8 +178,6 @@ static int lxcClose(virConnectPtr conn)
|
||||
lxc_driver_t *driver = conn->privateData;
|
||||
|
||||
lxcDriverLock(driver);
|
||||
virDomainEventStateDeregisterConn(conn,
|
||||
driver->domainEventState);
|
||||
lxcProcessAutoDestroyRun(driver, conn);
|
||||
lxcDriverUnlock(driver);
|
||||
|
||||
|
@ -962,8 +962,6 @@ static int qemudClose(virConnectPtr conn) {
|
||||
|
||||
/* Get rid of callbacks registered for this conn */
|
||||
qemuDriverLock(driver);
|
||||
virDomainEventStateDeregisterConn(conn,
|
||||
driver->domainEventState);
|
||||
qemuDriverCloseCallbackRunAll(driver, conn);
|
||||
qemuDriverUnlock(driver);
|
||||
|
||||
|
@ -1188,8 +1188,6 @@ static int umlClose(virConnectPtr conn) {
|
||||
struct uml_driver *driver = conn->privateData;
|
||||
|
||||
umlDriverLock(driver);
|
||||
virDomainEventStateDeregisterConn(conn,
|
||||
driver->domainEventState);
|
||||
umlProcessAutoDestroyRun(driver, conn);
|
||||
umlDriverUnlock(driver);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user