Current daemon shutdown can cause crashes. The problem is that threads
serving client request are joined on daemon dispose after drivers already
cleaned up. But this threads typically uses drivers and thus crashes come.
We need to join threads before virStateCleanup. virNetDaemonClose is
a good candidate.
But it turns out that we can hang on join. The problem is that at this
moment event loop is not functional and for example threads waiting for
qemu response will never finish. Let's introduce extra shutdown step
for drivers so that they can signal any API calls in progress to finish.
---
daemon/libvirtd.c | 2 ++
src/driver-state.h | 4 ++++
src/libvirt.c | 18 ++++++++++++++++++
src/libvirt_internal.h | 1 +
src/libvirt_private.syms | 1 +
src/rpc/virnetserver.c | 5 +++--
6 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 589b321..d2bbe1e 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -1504,6 +1504,8 @@ int main(int argc, char **argv) {
virObjectUnref(lxcProgram);
virObjectUnref(qemuProgram);
virObjectUnref(adminProgram);
+ if (driversInitialized)
+ virStateShutdown();
virNetDaemonClose(dmn);
virObjectUnref(srv);
virObjectUnref(srvAdm);
diff --git a/src/driver-state.h b/src/driver-state.h
index 1cb3e4f..ea549a7 100644
--- a/src/driver-state.h
+++ b/src/driver-state.h
@@ -42,6 +42,9 @@ typedef int
typedef int
(*virDrvStateStop)(void);
+typedef void
+(*virDrvStateShutdown)(void);
+
typedef struct _virStateDriver virStateDriver;
typedef virStateDriver *virStateDriverPtr;
@@ -52,6 +55,7 @@ struct _virStateDriver {
virDrvStateCleanup stateCleanup;
virDrvStateReload stateReload;
virDrvStateStop stateStop;
+ virDrvStateShutdown stateShutdown;
};
diff --git a/src/libvirt.c b/src/libvirt.c
index 6d66fa4..ff41764 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -812,6 +812,24 @@ virStateCleanup(void)
/**
+ * virStateShutdown:
+ *
+ * Run each virtualization driver's shutdown method.
+ *
+ */
+void
+virStateShutdown(void)
+{
+ int r;
+
+ for (r = virStateDriverTabCount - 1; r >= 0; r--) {
+ if (virStateDriverTab[r]->stateShutdown)
+ virStateDriverTab[r]->stateShutdown();
+ }
+}
+
+
+/**
* virStateReload:
*
* Run each virtualization driver's reload method.
diff --git a/src/libvirt_internal.h b/src/libvirt_internal.h
index 62f490a..9863b07 100644
--- a/src/libvirt_internal.h
+++ b/src/libvirt_internal.h
@@ -36,6 +36,7 @@ int virStateInitialize(bool privileged,
int virStateCleanup(void);
int virStateReload(void);
int virStateStop(void);
+void virStateShutdown(void);
/* Feature detection. This is a libvirt-private interface for determining
* what features are supported by the driver.
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 5b1bc5e..59f8207 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1189,6 +1189,7 @@ virSetSharedStorageDriver;
virStateCleanup;
virStateInitialize;
virStateReload;
+virStateShutdown;
virStateStop;
virStreamInData;
diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c
index 2b76daa..7dc8018 100644
--- a/src/rpc/virnetserver.c
+++ b/src/rpc/virnetserver.c
@@ -764,8 +764,6 @@ void virNetServerDispose(void *obj)
for (i = 0; i < srv->nservices; i++)
virNetServerServiceToggle(srv->services[i], false);
- virThreadPoolFree(srv->workers);
-
for (i = 0; i < srv->nservices; i++)
virObjectUnref(srv->services[i]);
VIR_FREE(srv->services);
@@ -796,6 +794,9 @@ void virNetServerClose(virNetServerPtr srv)
for (i = 0; i < srv->nservices; i++)
virNetServerServiceClose(srv->services[i]);
+ virThreadPoolFree(srv->workers);
+ srv->workers = NULL;
+
virObjectUnlock(srv);
}
--
1.8.3.1