From: Joachim Falk <joachim.falk@gmx.de>
Date: Thu, 2 Dec 2021 19:56:07 +0100
Subject: Fix reboot command for LXC containers (Closes: #991773)

The virNetDaemonQuit(dmn) command in virLXCControllerSignalChildIO triggers an
early close of all clients of lxc_controller. Here, libvirtd itself is a client
of this controller, and the client connection is used to notify libvirtd if a
reboot of the container is required. However, the client connection was closed
before such a status could be sent to libvirtd. To fix this bug, we will
immediately send the reboot or shutdown status of the container to libvirtd, and
only after client disconnect will we trigger virNetDaemonQuit (Closes: #991773).

Fixes: https://gitlab.com/libvirt/libvirt/-/issues/237
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=991773
Signed-off-by: Joachim Falk <joachim.falk@gmx.de>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>

(cherry picked from commit 93c47e2c39521aba760486f0238458ef1a37490c)

In order to cleanly apply to libvirt 7.0.0, this patch needed some minor
adjustments, e.g., "virNetDaemon *dmn" vs "virNetDaemonPtr dmn" in libvirt 7.0.0.
---
 src/lxc/lxc_controller.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

Index: libvirt/src/lxc/lxc_controller.c
===================================================================
--- libvirt.orig/src/lxc/lxc_controller.c
+++ libvirt/src/lxc/lxc_controller.c
@@ -897,8 +897,10 @@ static void virLXCControllerClientCloseH
     virLXCControllerPtr ctrl = virNetServerClientGetPrivateData(client);
 
     VIR_DEBUG("Client %p has closed", client);
-    if (ctrl->client == client)
+    if (ctrl->client == client) {
         ctrl->client = NULL;
+        VIR_DEBUG("Client has gone away");
+    }
     if (ctrl->inShutdown) {
         VIR_DEBUG("Arm timer to quit event loop");
         virEventUpdateTimeout(ctrl->timerShutdown, 0);
@@ -1009,8 +1011,11 @@ static int lxcControllerClearCapabilitie
 static bool wantReboot;
 static virMutex lock = VIR_MUTEX_INITIALIZER;
 
+static int
+virLXCControllerEventSendExit(virLXCController *ctrl,
+                              int exitstatus);
 
-static void virLXCControllerSignalChildIO(virNetDaemonPtr dmn,
+static void virLXCControllerSignalChildIO(virNetDaemonPtr dmn G_GNUC_UNUSED,
                                           siginfo_t *info G_GNUC_UNUSED,
                                           void *opaque)
 {
@@ -1021,7 +1026,6 @@ static void virLXCControllerSignalChildI
     ret = waitpid(-1, &status, WNOHANG);
     VIR_DEBUG("Got sig child %d vs %lld", ret, (long long)ctrl->initpid);
     if (ret == ctrl->initpid) {
-        virNetDaemonQuit(dmn);
         virMutexLock(&lock);
         if (WIFSIGNALED(status) &&
             WTERMSIG(status) == SIGHUP) {
@@ -1029,6 +1033,7 @@ static void virLXCControllerSignalChildI
             wantReboot = true;
         }
         virMutexUnlock(&lock);
+        virLXCControllerEventSendExit(ctrl, wantReboot ? 1 : 0);
     }
 }
 
@@ -2279,9 +2284,10 @@ virLXCControllerEventSendExit(virLXCCont
         VIR_DEBUG("Waiting for client to complete dispatch");
         ctrl->inShutdown = true;
         virNetServerClientDelayedClose(ctrl->client);
-        virNetDaemonRun(ctrl->daemon);
+    } else {
+        VIR_DEBUG("Arm timer to quit event loop");
+        virEventUpdateTimeout(ctrl->timerShutdown, 0);
     }
-    VIR_DEBUG("Client has gone away");
     return 0;
 }
 
@@ -2423,8 +2429,6 @@ virLXCControllerRun(virLXCControllerPtr
 
     rc = virLXCControllerMain(ctrl);
 
-    virLXCControllerEventSendExit(ctrl, rc);
-
  cleanup:
     VIR_FORCE_CLOSE(control[0]);
     VIR_FORCE_CLOSE(control[1]);
