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:
Daniel P. Berrange 2012-05-21 12:10:53 +01:00
parent 651d712452
commit 2cb0899eec
7 changed files with 0 additions and 76 deletions

View File

@ -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

View File

@ -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)

View File

@ -522,7 +522,6 @@ virDomainEventRebootNewFromDom;
virDomainEventRebootNewFromObj;
virDomainEventStateDeregister;
virDomainEventStateDeregisterID;
virDomainEventStateDeregisterConn;
virDomainEventStateEventID;
virDomainEventStateRegister;
virDomainEventStateRegisterID;

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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);