virnetdaemon: Wait for "daemon-stop" thread to finish before quitting

When the host is shutting down then we get PrepareForShutdown
signal on DBus to which we react by creating a thread which
runs virStateStop() and thus qemuStateStop(). But if scheduling
the thread is delayed just a but it may happen that we receive
SIGTERM (sent by systemd) to which we respond by quitting our
event loop and cleaning up everything (including drivers). And
only after that the thread gets to run only to find qemu_driver
being NULL.

What we can do is to delay exiting event loop and join the thread
that's executing virStateStop(). If the join doesn't happen in
given timeout (currently 30 seconds) then libvirtd shuts down
forcefully anyways (see virNetDaemonRun()).

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1895359
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1739564

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
Michal Privoznik 2020-11-13 10:56:59 +01:00
parent b67080b345
commit a42b46dd7d
4 changed files with 33 additions and 3 deletions

View File

@ -88,6 +88,7 @@ virNetDaemonQuit;
virNetDaemonRemoveShutdownInhibition;
virNetDaemonRun;
virNetDaemonSetShutdownCallbacks;
virNetDaemonSetStateStopWorkerThread;
virNetDaemonUpdateServices;

View File

@ -529,11 +529,20 @@ static void daemonStopWorker(void *opaque)
/* We do this in a thread to not block the main loop */
static void daemonStop(virNetDaemonPtr dmn)
{
virThread thr;
virThreadPtr thr;
virObjectRef(dmn);
if (virThreadCreateFull(&thr, false, daemonStopWorker,
"daemon-stop", false, dmn) < 0)
thr = g_new0(virThread, 1);
if (virThreadCreateFull(thr, true,
daemonStopWorker,
"daemon-stop", false, dmn) < 0) {
virObjectUnref(dmn);
g_free(thr);
return;
}
virNetDaemonSetStateStopWorkerThread(dmn, &thr);
}

View File

@ -71,6 +71,7 @@ struct _virNetDaemon {
virNetDaemonShutdownCallback shutdownPrepareCb;
virNetDaemonShutdownCallback shutdownWaitCb;
virThreadPtr stateStopThread;
int finishTimer;
bool quit;
bool finished;
@ -108,6 +109,7 @@ virNetDaemonDispose(void *obj)
#endif /* !WIN32 */
VIR_FORCE_CLOSE(dmn->autoShutdownInhibitFd);
VIR_FREE(dmn->stateStopThread);
virHashFree(dmn->servers);
@ -773,6 +775,9 @@ daemonShutdownWait(void *opaque)
if (dmn->shutdownWaitCb && dmn->shutdownWaitCb() < 0)
goto finish;
if (dmn->stateStopThread)
virThreadJoin(dmn->stateStopThread);
graceful = true;
finish:
@ -891,6 +896,18 @@ virNetDaemonRun(virNetDaemonPtr dmn)
}
void
virNetDaemonSetStateStopWorkerThread(virNetDaemonPtr dmn,
virThreadPtr *thr)
{
virObjectLock(dmn);
VIR_DEBUG("Setting state stop worker thread on dmn=%p to thr=%p", dmn, thr);
dmn->stateStopThread = g_steal_pointer(thr);
virObjectUnlock(dmn);
}
void
virNetDaemonQuit(virNetDaemonPtr dmn)
{

View File

@ -69,6 +69,9 @@ int virNetDaemonAddSignalHandler(virNetDaemonPtr dmn,
void virNetDaemonUpdateServices(virNetDaemonPtr dmn,
bool enabled);
void virNetDaemonSetStateStopWorkerThread(virNetDaemonPtr dmn,
virThreadPtr *thr);
void virNetDaemonRun(virNetDaemonPtr dmn);
void virNetDaemonQuit(virNetDaemonPtr dmn);