mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-01 01:15:19 +00: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 (cherry picked from commit 2cb0899eec72376629a0583647dcad39b00c5715)
This commit is contained in:
parent
c82da02253
commit
fc8700e919
@ -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
|
static int
|
||||||
virDomainEventCallbackListMarkDelete(virConnectPtr conn,
|
virDomainEventCallbackListMarkDelete(virConnectPtr conn,
|
||||||
virDomainEventCallbackListPtr cbList,
|
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:
|
* virDomainEventStateEventID:
|
||||||
* @conn: connection associated with the callback
|
* @conn: connection associated with the callback
|
||||||
|
@ -161,10 +161,6 @@ virDomainEventStateDeregisterID(virConnectPtr conn,
|
|||||||
int callbackID)
|
int callbackID)
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||||
int
|
int
|
||||||
virDomainEventStateDeregisterConn(virConnectPtr conn,
|
|
||||||
virDomainEventStatePtr state)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
|
||||||
int
|
|
||||||
virDomainEventStateEventID(virConnectPtr conn,
|
virDomainEventStateEventID(virConnectPtr conn,
|
||||||
virDomainEventStatePtr state,
|
virDomainEventStatePtr state,
|
||||||
int callbackID)
|
int callbackID)
|
||||||
|
@ -520,7 +520,6 @@ virDomainEventRebootNewFromDom;
|
|||||||
virDomainEventRebootNewFromObj;
|
virDomainEventRebootNewFromObj;
|
||||||
virDomainEventStateDeregister;
|
virDomainEventStateDeregister;
|
||||||
virDomainEventStateDeregisterID;
|
virDomainEventStateDeregisterID;
|
||||||
virDomainEventStateDeregisterConn;
|
|
||||||
virDomainEventStateEventID;
|
virDomainEventStateEventID;
|
||||||
virDomainEventStateRegister;
|
virDomainEventStateRegister;
|
||||||
virDomainEventStateRegisterID;
|
virDomainEventStateRegisterID;
|
||||||
|
@ -1081,10 +1081,6 @@ libxlClose(virConnectPtr conn ATTRIBUTE_UNUSED)
|
|||||||
{
|
{
|
||||||
libxlDriverPrivatePtr driver = conn->privateData;
|
libxlDriverPrivatePtr driver = conn->privateData;
|
||||||
|
|
||||||
libxlDriverLock(driver);
|
|
||||||
virDomainEventStateDeregisterConn(conn,
|
|
||||||
driver->domainEventState);
|
|
||||||
libxlDriverUnlock(driver);
|
|
||||||
conn->privateData = NULL;
|
conn->privateData = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -178,8 +178,6 @@ static int lxcClose(virConnectPtr conn)
|
|||||||
lxc_driver_t *driver = conn->privateData;
|
lxc_driver_t *driver = conn->privateData;
|
||||||
|
|
||||||
lxcDriverLock(driver);
|
lxcDriverLock(driver);
|
||||||
virDomainEventStateDeregisterConn(conn,
|
|
||||||
driver->domainEventState);
|
|
||||||
lxcProcessAutoDestroyRun(driver, conn);
|
lxcProcessAutoDestroyRun(driver, conn);
|
||||||
lxcDriverUnlock(driver);
|
lxcDriverUnlock(driver);
|
||||||
|
|
||||||
|
@ -948,8 +948,6 @@ static int qemudClose(virConnectPtr conn) {
|
|||||||
|
|
||||||
/* Get rid of callbacks registered for this conn */
|
/* Get rid of callbacks registered for this conn */
|
||||||
qemuDriverLock(driver);
|
qemuDriverLock(driver);
|
||||||
virDomainEventStateDeregisterConn(conn,
|
|
||||||
driver->domainEventState);
|
|
||||||
qemuDriverCloseCallbackRunAll(driver, conn);
|
qemuDriverCloseCallbackRunAll(driver, conn);
|
||||||
qemuDriverUnlock(driver);
|
qemuDriverUnlock(driver);
|
||||||
|
|
||||||
|
@ -1188,8 +1188,6 @@ static int umlClose(virConnectPtr conn) {
|
|||||||
struct uml_driver *driver = conn->privateData;
|
struct uml_driver *driver = conn->privateData;
|
||||||
|
|
||||||
umlDriverLock(driver);
|
umlDriverLock(driver);
|
||||||
virDomainEventStateDeregisterConn(conn,
|
|
||||||
driver->domainEventState);
|
|
||||||
umlProcessAutoDestroyRun(driver, conn);
|
umlProcessAutoDestroyRun(driver, conn);
|
||||||
umlDriverUnlock(driver);
|
umlDriverUnlock(driver);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user