From: "Daniel P. Berrange" <berrange(a)redhat.com>
Depending on the scenario in which LXC containers exit, it is
possible for the EOF callback of the LXC monitor to deadlock
the driver. When the driver calls virLXCMonitorClose, there
is really no need for the EOF callback to be invoked in this
case, since the caller can easily handle events itself.
In changing this, the monitor needs to take a deep copy of
the callback list, not merely a reference.
Also adds debug statements in various places to aid
troubleshooting
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/lxc/lxc_monitor.c | 32 ++++++++++++++++++++++----------
src/lxc/lxc_process.c | 6 +++++-
2 files changed, 27 insertions(+), 11 deletions(-)
diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c
index 772c613..3e00751 100644
--- a/src/lxc/lxc_monitor.c
+++ b/src/lxc/lxc_monitor.c
@@ -40,7 +40,7 @@ struct _virLXCMonitor {
virMutex lock;
virDomainObjPtr vm;
- virLXCMonitorCallbacksPtr cb;
+ virLXCMonitorCallbacks cb;
virNetClientPtr client;
virNetClientProgramPtr program;
@@ -83,8 +83,8 @@ virLXCMonitorHandleEventExit(virNetClientProgramPtr prog
ATTRIBUTE_UNUSED,
virLXCProtocolExitEventMsg *msg = evdata;
VIR_DEBUG("Event exit %d", msg->status);
- if (mon->cb->exitNotify)
- mon->cb->exitNotify(mon, msg->status, mon->vm);
+ if (mon->cb.exitNotify)
+ mon->cb.exitNotify(mon, msg->status, mon->vm);
}
@@ -96,20 +96,25 @@ static void virLXCMonitorEOFNotify(virNetClientPtr client
ATTRIBUTE_UNUSED,
virLXCMonitorCallbackEOFNotify eofNotify;
virDomainObjPtr vm;
- VIR_DEBUG("EOF notify");
+ VIR_DEBUG("EOF notify mon=%p", mon);
virLXCMonitorLock(mon);
- eofNotify = mon->cb->eofNotify;
+ eofNotify = mon->cb.eofNotify;
vm = mon->vm;
virLXCMonitorUnlock(mon);
- eofNotify(mon, vm);
+ if (eofNotify) {
+ VIR_DEBUG("EOF callback mon=%p vm=%p", mon, vm);
+ eofNotify(mon, vm);
+ } else {
+ VIR_DEBUG("No EOF callback");
+ }
}
static void virLXCMonitorCloseFreeCallback(void *opaque)
{
virLXCMonitorPtr mon = opaque;
- virObjectUnref(mon);;
+ virObjectUnref(mon);
}
@@ -155,7 +160,7 @@ virLXCMonitorPtr virLXCMonitorNew(virDomainObjPtr vm,
goto error;
mon->vm = vm;
- mon->cb = cb;
+ memcpy(&mon->cb, cb, sizeof(mon->cb));
virObjectRef(mon);
virNetClientSetCloseCallback(mon->client, virLXCMonitorEOFNotify, mon,
@@ -179,8 +184,8 @@ static void virLXCMonitorDispose(void *opaque)
virLXCMonitorPtr mon = opaque;
VIR_DEBUG("mon=%p", mon);
- if (mon->cb && mon->cb->destroy)
- (mon->cb->destroy)(mon, mon->vm);
+ if (mon->cb.destroy)
+ (mon->cb.destroy)(mon, mon->vm);
virMutexDestroy(&mon->lock);
virObjectUnref(mon->program);
}
@@ -188,7 +193,14 @@ static void virLXCMonitorDispose(void *opaque)
void virLXCMonitorClose(virLXCMonitorPtr mon)
{
+ VIR_DEBUG("mon=%p", mon);
if (mon->client) {
+ /* When manually closing the monitor, we don't
+ * want to have callbacks back into us, since
+ * the caller is not re-entrant safe
+ */
+ VIR_DEBUG("Clear EOF callback mon=%p", mon);
+ mon->cb.eofNotify = NULL;
virNetClientClose(mon->client);
virObjectUnref(mon->client);
mon->client = NULL;
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index b9cff85..079bc3a 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -169,6 +169,8 @@ virLXCProcessReboot(virLXCDriverPtr driver,
int ret = -1;
virDomainDefPtr savedDef;
+ VIR_DEBUG("Faking reboot");
+
if (conn) {
virConnectRef(conn);
autodestroy = true;
@@ -555,13 +557,15 @@ cleanup:
extern virLXCDriverPtr lxc_driver;
-static void virLXCProcessMonitorEOFNotify(virLXCMonitorPtr mon ATTRIBUTE_UNUSED,
+static void virLXCProcessMonitorEOFNotify(virLXCMonitorPtr mon,
virDomainObjPtr vm)
{
virLXCDriverPtr driver = lxc_driver;
virDomainEventPtr event = NULL;
virLXCDomainObjPrivatePtr priv;
+ VIR_DEBUG("mon=%p vm=%p", mon, vm);
+
lxcDriverLock(driver);
virDomainObjLock(vm);
lxcDriverUnlock(driver);
--
1.7.11.2