mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-12 07:42:56 +00:00
Fix reference handling leak on qemuMonitor
The current code pattern requires that callers of qemuMonitorClose check for the return value == 0, and if so, set priv->mon = NULL and release the reference held on the associated virDomainObjPtr The change d84bb6d6a3bd2fdd530184cc9743249ebddbee71 violated that requirement, meaning that priv->mon never gets set to NULL, and a reference count is leaked on virDomainObjPtr. This design was a bad one, so remove the need to check the return valueof qemuMonitorClose(). Instead allow registration of a callback that's invoked just when the last reference on qemuMonitorPtr is released. Finally there was a potential reference leak in qemuConnectMonitor in the failure path. * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add a destroy callback invoked from qemuMonitorFree * src/qemu/qemu_driver.c: Use the destroy callback to release the reference on virDomainObjPtr when the monitor is freed. Fix other potential reference count leak in connecting to monitor
This commit is contained in:
parent
8d616decc5
commit
c212160260
@ -1173,7 +1173,17 @@ no_memory:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void qemuHandleMonitorDestroy(qemuMonitorPtr mon,
|
||||||
|
virDomainObjPtr vm)
|
||||||
|
{
|
||||||
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
|
if (priv->mon == mon)
|
||||||
|
priv->mon = NULL;
|
||||||
|
virDomainObjUnref(vm);
|
||||||
|
}
|
||||||
|
|
||||||
static qemuMonitorCallbacks monitorCallbacks = {
|
static qemuMonitorCallbacks monitorCallbacks = {
|
||||||
|
.destroy = qemuHandleMonitorDestroy,
|
||||||
.eofNotify = qemuHandleMonitorEOF,
|
.eofNotify = qemuHandleMonitorEOF,
|
||||||
.diskSecretLookup = findVolumeQcowPassphrase,
|
.diskSecretLookup = findVolumeQcowPassphrase,
|
||||||
.domainStop = qemuHandleDomainStop,
|
.domainStop = qemuHandleDomainStop,
|
||||||
@ -1190,10 +1200,6 @@ qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm)
|
|||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
/* Hold an extra reference because we can't allow 'vm' to be
|
|
||||||
* deleted while the monitor is active */
|
|
||||||
virDomainObjRef(vm);
|
|
||||||
|
|
||||||
if ((driver->securityDriver &&
|
if ((driver->securityDriver &&
|
||||||
driver->securityDriver->domainSetSecuritySocketLabel &&
|
driver->securityDriver->domainSetSecuritySocketLabel &&
|
||||||
driver->securityDriver->domainSetSecuritySocketLabel(driver->securityDriver,vm)) < 0) {
|
driver->securityDriver->domainSetSecuritySocketLabel(driver->securityDriver,vm)) < 0) {
|
||||||
@ -1201,13 +1207,17 @@ qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((priv->mon = qemuMonitorOpen(vm,
|
/* Hold an extra reference because we can't allow 'vm' to be
|
||||||
priv->monConfig,
|
* deleted while the monitor is active */
|
||||||
priv->monJSON,
|
virDomainObjRef(vm);
|
||||||
&monitorCallbacks)) == NULL) {
|
|
||||||
VIR_ERROR(_("Failed to connect monitor for %s"), vm->def->name);
|
priv->mon = qemuMonitorOpen(vm,
|
||||||
goto error;
|
priv->monConfig,
|
||||||
}
|
priv->monJSON,
|
||||||
|
&monitorCallbacks);
|
||||||
|
|
||||||
|
if (priv->mon == NULL)
|
||||||
|
virDomainObjUnref(vm);
|
||||||
|
|
||||||
if ((driver->securityDriver &&
|
if ((driver->securityDriver &&
|
||||||
driver->securityDriver->domainClearSecuritySocketLabel &&
|
driver->securityDriver->domainClearSecuritySocketLabel &&
|
||||||
@ -1216,17 +1226,20 @@ qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (priv->mon == NULL) {
|
||||||
|
VIR_INFO("Failed to connect monitor for %s", vm->def->name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
||||||
ret = qemuMonitorSetCapabilities(priv->mon);
|
ret = qemuMonitorSetCapabilities(priv->mon);
|
||||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
error:
|
error:
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
qemuMonitorClose(priv->mon);
|
qemuMonitorClose(priv->mon);
|
||||||
priv->mon = NULL;
|
|
||||||
virDomainObjUnref(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -3693,11 +3706,8 @@ static void qemudShutdownVMDaemon(struct qemud_driver *driver,
|
|||||||
_("Failed to send SIGTERM to %s (%d)"),
|
_("Failed to send SIGTERM to %s (%d)"),
|
||||||
vm->def->name, vm->pid);
|
vm->def->name, vm->pid);
|
||||||
|
|
||||||
if (priv->mon &&
|
if (priv->mon)
|
||||||
qemuMonitorClose(priv->mon) == 0) {
|
qemuMonitorClose(priv->mon);
|
||||||
virDomainObjUnref(vm);
|
|
||||||
priv->mon = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->monConfig) {
|
if (priv->monConfig) {
|
||||||
if (priv->monConfig->type == VIR_DOMAIN_CHR_TYPE_UNIX)
|
if (priv->monConfig->type == VIR_DOMAIN_CHR_TYPE_UNIX)
|
||||||
|
@ -198,6 +198,8 @@ void qemuMonitorUnlock(qemuMonitorPtr mon)
|
|||||||
static void qemuMonitorFree(qemuMonitorPtr mon)
|
static void qemuMonitorFree(qemuMonitorPtr mon)
|
||||||
{
|
{
|
||||||
VIR_DEBUG("mon=%p", mon);
|
VIR_DEBUG("mon=%p", mon);
|
||||||
|
if (mon->cb->destroy)
|
||||||
|
(mon->cb->destroy)(mon, mon->vm);
|
||||||
if (virCondDestroy(&mon->notify) < 0)
|
if (virCondDestroy(&mon->notify) < 0)
|
||||||
{}
|
{}
|
||||||
virMutexDestroy(&mon->lock);
|
virMutexDestroy(&mon->lock);
|
||||||
@ -675,12 +677,12 @@ cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int qemuMonitorClose(qemuMonitorPtr mon)
|
void qemuMonitorClose(qemuMonitorPtr mon)
|
||||||
{
|
{
|
||||||
int refs;
|
int refs;
|
||||||
|
|
||||||
if (!mon)
|
if (!mon)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
VIR_DEBUG("mon=%p", mon);
|
VIR_DEBUG("mon=%p", mon);
|
||||||
|
|
||||||
@ -700,7 +702,6 @@ int qemuMonitorClose(qemuMonitorPtr mon)
|
|||||||
|
|
||||||
if ((refs = qemuMonitorUnref(mon)) > 0)
|
if ((refs = qemuMonitorUnref(mon)) > 0)
|
||||||
qemuMonitorUnlock(mon);
|
qemuMonitorUnlock(mon);
|
||||||
return refs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,6 +63,9 @@ struct _qemuMonitorMessage {
|
|||||||
typedef struct _qemuMonitorCallbacks qemuMonitorCallbacks;
|
typedef struct _qemuMonitorCallbacks qemuMonitorCallbacks;
|
||||||
typedef qemuMonitorCallbacks *qemuMonitorCallbacksPtr;
|
typedef qemuMonitorCallbacks *qemuMonitorCallbacksPtr;
|
||||||
struct _qemuMonitorCallbacks {
|
struct _qemuMonitorCallbacks {
|
||||||
|
void (*destroy)(qemuMonitorPtr mon,
|
||||||
|
virDomainObjPtr vm);
|
||||||
|
|
||||||
void (*eofNotify)(qemuMonitorPtr mon,
|
void (*eofNotify)(qemuMonitorPtr mon,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
int withError);
|
int withError);
|
||||||
@ -120,7 +123,7 @@ qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm,
|
|||||||
int json,
|
int json,
|
||||||
qemuMonitorCallbacksPtr cb);
|
qemuMonitorCallbacksPtr cb);
|
||||||
|
|
||||||
int qemuMonitorClose(qemuMonitorPtr mon);
|
void qemuMonitorClose(qemuMonitorPtr mon);
|
||||||
|
|
||||||
int qemuMonitorSetCapabilities(qemuMonitorPtr mon);
|
int qemuMonitorSetCapabilities(qemuMonitorPtr mon);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user