]> xenbits.xensource.com Git - libvirt.git/commitdiff
Enable libvirtd drivers to handle signals, in lxc, sigchld triggers vm cleanup
authorDavid L. Leskovec <dlesko@linux.vnet.ibm.com>
Tue, 13 May 2008 06:30:58 +0000 (06:30 +0000)
committerDavid L. Leskovec <dlesko@linux.vnet.ibm.com>
Tue, 13 May 2008 06:30:58 +0000 (06:30 +0000)
Mon May 12 23:32:21 PST 2008 David L. Leskovec <dlesko@linux.vnet.ibm.com>

* qemud/qemud.c: get siginfo with signals, distribute to drivers that
    register a handler
* src/driver.h: add sighandler function to state driver table
* src/internal.h: define virStateSigDispatcher functions
* src/libvirt.c: add __virStateSigDispatcher function
* src/libvirt_sym.version: add __virStateSigDispatcher
* src/lxc_driver.c: add sig handler function, cleanup vm when sigchld
    received from container process
* src/qemu_driver.c: NULL for sig handler (no handler) in state driver
* src/remote_internal.c: NULL for sig handler (no handler) in state driver
* src/storage_driver.c: NULL for sig handler (no handler) in state driver

ChangeLog
qemud/qemud.c
src/driver.h
src/internal.h
src/libvirt.c
src/libvirt_sym.version
src/lxc_driver.c
src/qemu_driver.c
src/remote_internal.c
src/storage_driver.c

index cd0409f7cc24a112d94848604deccefda173d15c..1664e1c08fbd0086da22f69a9b5687e927604a4a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+Mon May 12 23:32:21 PST 2008 David L. Leskovec <dlesko@linux.vnet.ibm.com>
+
+       * qemud/qemud.c: get siginfo with signals, distribute to drivers that
+    register a handler
+       * src/driver.h: add sighandler function to state driver table
+       * src/internal.h: define virStateSigDispatcher functions
+       * src/libvirt.c: add __virStateSigDispatcher function
+       * src/libvirt_sym.version: add __virStateSigDispatcher
+       * src/lxc_driver.c: add sig handler function, cleanup vm when sigchld
+    received from container process
+       * src/qemu_driver.c: NULL for sig handler (no handler) in state driver
+       * src/remote_internal.c: NULL for sig handler (no handler) in state driver
+       * src/storage_driver.c: NULL for sig handler (no handler) in state driver
+
 Thu May  9 12:40:11 EST 2008 Daniel P. Berrange <berrange@redhat.com>
 
        * bootstrap: Added verify module
index a9d825d69026e8d55a09c17071f5ad1a574d05f1..d308dfe2f4dee2e1da4f0da4fec3ad4554e8f0de 100644 (file)
@@ -109,16 +109,16 @@ static gnutls_dh_params_t dh_params;
 static sig_atomic_t sig_errors = 0;
 static int sig_lasterrno = 0;
 
-static void sig_handler(int sig) {
-    unsigned char sigc = sig;
+static void sig_handler(int sig, siginfo_t * siginfo,
+                        void* context ATTRIBUTE_UNUSED) {
     int origerrno;
     int r;
 
-    if (sig == SIGCHLD) /* We explicitly waitpid the child later */
-        return;
+    /* set the sig num in the struct */
+    siginfo->si_signo = sig;
 
     origerrno = errno;
-    r = safewrite(sigwrite, &sigc, 1);
+    r = safewrite(sigwrite, siginfo, sizeof(*siginfo));
     if (r == -1) {
         sig_errors++;
         sig_lasterrno = errno;
@@ -232,10 +232,10 @@ static void qemudDispatchSignalEvent(int fd ATTRIBUTE_UNUSED,
                                      int events ATTRIBUTE_UNUSED,
                                      void *opaque) {
     struct qemud_server *server = (struct qemud_server *)opaque;
-    unsigned char sigc;
+    siginfo_t siginfo;
     int ret;
 
-    if (read(server->sigread, &sigc, 1) != 1) {
+    if (saferead(server->sigread, &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
         qemudLog(QEMUD_ERR, _("Failed to read from signal pipe: %s"),
                  strerror(errno));
         return;
@@ -243,7 +243,7 @@ static void qemudDispatchSignalEvent(int fd ATTRIBUTE_UNUSED,
 
     ret = 0;
 
-    switch (sigc) {
+    switch (siginfo.si_signo) {
     case SIGHUP:
         qemudLog(QEMUD_INFO, "%s", _("Reloading configuration on SIGHUP"));
         if (virStateReload() < 0)
@@ -253,11 +253,15 @@ static void qemudDispatchSignalEvent(int fd ATTRIBUTE_UNUSED,
     case SIGINT:
     case SIGQUIT:
     case SIGTERM:
-        qemudLog(QEMUD_WARN, _("Shutting down on signal %d"), sigc);
+        qemudLog(QEMUD_WARN, _("Shutting down on signal %d"),
+                 siginfo.si_signo);
         server->shutdown = 1;
         break;
 
     default:
+        qemudLog(QEMUD_INFO, _("Received signal %d, dispatching to drivers"),
+                 siginfo.si_signo);
+        virStateSigDispatcher(&siginfo);
         break;
     }
 
@@ -2186,8 +2190,8 @@ int main(int argc, char **argv) {
             goto error1;
     }
 
-    sig_action.sa_handler = sig_handler;
-    sig_action.sa_flags = 0;
+    sig_action.sa_sigaction = sig_handler;
+    sig_action.sa_flags = SA_SIGINFO;
     sigemptyset(&sig_action.sa_mask);
 
     sigaction(SIGHUP, &sig_action, NULL);
index 61f8f38b1e2fc93c8806a0bd8b874c110e6b6197..12073419e18abb63f5487877e20c82356efa363e 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <libxml/uri.h>
 
+#include <signal.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -565,6 +567,7 @@ typedef int (*virDrvStateInitialize) (void);
 typedef int (*virDrvStateCleanup) (void);
 typedef int (*virDrvStateReload) (void);
 typedef int (*virDrvStateActive) (void);
+typedef int (*virDrvSigHandler) (siginfo_t *siginfo);
 
 typedef struct _virStateDriver virStateDriver;
 typedef virStateDriver *virStateDriverPtr;
@@ -574,6 +577,7 @@ struct _virStateDriver {
     virDrvStateCleanup     cleanup;
     virDrvStateReload      reload;
     virDrvStateActive      active;
+    virDrvSigHandler       sigHandler;
 };
 
 /*
index 7df866154e8ebba2e05d51aaeac88e7c882b444f..3327ea13a426c9a42304514613a3a34864ce203b 100644 (file)
@@ -344,10 +344,12 @@ int __virStateInitialize(void);
 int __virStateCleanup(void);
 int __virStateReload(void);
 int __virStateActive(void);
+int __virStateSigDispatcher(siginfo_t *siginfo);
 #define virStateInitialize() __virStateInitialize()
 #define virStateCleanup() __virStateCleanup()
 #define virStateReload() __virStateReload()
 #define virStateActive() __virStateActive()
+#define virStateSigDispatcher(s) __virStateSigDispatcher(s)
 
 int __virDrvSupportsFeature (virConnectPtr conn, int feature);
 
index d4933043b414b26d48c367fc407666d9ad9ee8a5..7f5f1f148d1a65fff0697e1b2700fce106246aad 100644 (file)
@@ -607,6 +607,17 @@ int __virStateActive(void) {
     return ret;
 }
 
+int __virStateSigDispatcher(siginfo_t *siginfo) {
+    int i, ret = 0;
+
+    for (i = 0 ; i < virStateDriverTabCount ; i++) {
+        if (virStateDriverTab[i]->sigHandler &&
+            virStateDriverTab[i]->sigHandler(siginfo))
+            ret = 1;
+    }
+    return ret;
+}
+
 
 
 /**
index 77f0b5534e5561758f88a6a6d25588104a68fb31..bd2ad1f5df484bb489fff67231de4efa98de5e44 100644 (file)
        __virStateCleanup;
        __virStateReload;
        __virStateActive;
+       __virStateSigDispatcher;
 
        __virDrvSupportsFeature;
 
index fd5124158647ed902366ca1af95bb5b6c1dedc48..e78c718316ffa47420bb3d6728e7a1c2e5a71055 100644 (file)
@@ -925,55 +925,42 @@ error_out:
 }
 
 /**
- * lxcDomainDestroy:
- * @dom: Ptr to domain to destroy
+ * lxcVmCleanup:
+ * @vm: Ptr to VM to clean up
  *
- * Sends SIGKILL to container root process to terminate the container
+ * waitpid() on the container process.  kill and wait the tty process
+ * This is called by boh lxcDomainDestroy and lxcSigHandler when a
+ * container exits.
  *
  * Returns 0 on success or -1 in case of error
  */
-static int lxcDomainDestroy(virDomainPtr dom)
+static int lxcVMCleanup(lxc_driver_t *driver, lxc_vm_t * vm)
 {
     int rc = -1;
     int waitRc;
-    lxc_driver_t *driver = (lxc_driver_t*)dom->conn->privateData;
-    lxc_vm_t *vm = lxcFindVMByID(driver, dom->id);
-    int childStatus;
-
-    if (!vm) {
-        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
-                 _("no domain with id %d"), dom->id);
-        goto error_out;
-    }
-
-    if (0 > (kill(vm->def->id, SIGKILL))) {
-        if (ESRCH != errno) {
-            lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
-                     _("sending SIGKILL failed: %s"), strerror(errno));
-
-            goto error_out;
-        }
-    }
-
-    vm->state = VIR_DOMAIN_SHUTDOWN;
+    int childStatus = -1;
 
     while (((waitRc = waitpid(vm->def->id, &childStatus, 0)) == -1) &&
            errno == EINTR);
 
     if (waitRc != vm->def->id) {
-        lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                  _("waitpid failed to wait for container %d: %d %s"),
                  vm->def->id, waitRc, strerror(errno));
         goto kill_tty;
     }
 
-    rc = WEXITSTATUS(childStatus);
-    DEBUG("container exited with rc: %d", rc);
+    rc = 0;
+
+    if (WIFEXITED(childStatus)) {
+        rc = WEXITSTATUS(childStatus);
+        DEBUG("container exited with rc: %d", rc);
+    }
 
 kill_tty:
     if (0 > (kill(vm->pid, SIGKILL))) {
         if (ESRCH != errno) {
-            lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                      _("sending SIGKILL to tty process failed: %s"),
                      strerror(errno));
 
@@ -985,7 +972,7 @@ kill_tty:
            errno == EINTR);
 
     if (waitRc != vm->pid) {
-        lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                  _("waitpid failed to wait for tty %d: %d %s"),
                  vm->pid, waitRc, strerror(errno));
     }
@@ -996,8 +983,43 @@ tty_error_out:
     vm->def->id = -1;
     driver->nactivevms--;
     driver->ninactivevms++;
+    lxcSaveConfig(NULL, driver, vm, vm->def);
 
-    rc = 0;
+    return rc;
+ }
+
+/**
+ * lxcDomainDestroy:
+ * @dom: Ptr to domain to destroy
+ *
+ * Sends SIGKILL to container root process to terminate the container
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcDomainDestroy(virDomainPtr dom)
+{
+    int rc = -1;
+    lxc_driver_t *driver = (lxc_driver_t*)dom->conn->privateData;
+    lxc_vm_t *vm = lxcFindVMByID(driver, dom->id);
+
+    if (!vm) {
+        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
+                 _("no domain with id %d"), dom->id);
+        goto error_out;
+    }
+
+    if (0 > (kill(vm->def->id, SIGKILL))) {
+        if (ESRCH != errno) {
+            lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+                     _("sending SIGKILL failed: %s"), strerror(errno));
+
+            goto error_out;
+        }
+    }
+
+    vm->state = VIR_DOMAIN_SHUTDOWN;
+
+    rc = lxcVMCleanup(driver, vm);
 
 error_out:
     return rc;
@@ -1077,6 +1099,37 @@ lxcActive(void) {
     return 0;
 }
 
+/**
+ * lxcSigHandler:
+ * @siginfo: Pointer to siginfo_t structure
+ *
+ * Handles signals received by libvirtd.  Currently this is used to
+ * catch SIGCHLD from an exiting container.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcSigHandler(siginfo_t *siginfo)
+{
+    int rc = -1;
+    lxc_vm_t *vm;
+
+    if (siginfo->si_signo == SIGCHLD) {
+        vm = lxcFindVMByID(lxc_driver, siginfo->si_pid);
+
+        if (NULL == vm) {
+            DEBUG("Ignoring SIGCHLD from non-container process %d\n",
+                  siginfo->si_pid);
+            goto cleanup;
+        }
+
+        rc = lxcVMCleanup(lxc_driver, vm);
+
+    }
+
+cleanup:
+    return rc;
+}
+
 
 /* Function Tables */
 static virDriver lxcDriver = {
@@ -1145,6 +1198,7 @@ static virStateDriver lxcStateDriver = {
     lxcShutdown,
     NULL, /* reload */
     lxcActive,
+    lxcSigHandler
 };
 
 int lxcRegister(void)
index 10868c1b268b00ade02ef4076092fe3211cc5bd5..7d527982425d61e0e872735ad40557b94fa8b10e 100644 (file)
@@ -3198,6 +3198,7 @@ static virStateDriver qemuStateDriver = {
     qemudShutdown,
     qemudReload,
     qemudActive,
+    NULL
 };
 
 int qemudRegister(void) {
index f3bef3d39ef46ec0743e77787ed5e7267fdb92ae..9474028d1cb59b415c2432c7e843e4707744f32b 100644 (file)
@@ -4793,6 +4793,7 @@ static virStateDriver state_driver = {
     NULL,
     NULL,
     NULL,
+    NULL
 };
 
 
index 7f1ce0cdc99041ca6fa2ea84aaa9dc5f7764083d..9478c3641983dce1285e58420467281a4ba84365 100644 (file)
@@ -1245,6 +1245,7 @@ static virStateDriver stateDriver = {
     storageDriverShutdown,
     storageDriverReload,
     storageDriverActive,
+    NULL
 };
 
 int storageRegister(void) {