From 94311de539cdc2daba7452192f5b9d964a4ea17a Mon Sep 17 00:00:00 2001 From: "David L. Leskovec" Date: Tue, 13 May 2008 06:30:58 +0000 Subject: [PATCH] Enable libvirtd drivers to handle signals, in lxc, sigchld triggers vm cleanup Mon May 12 23:32:21 PST 2008 David L. Leskovec * 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 | 14 ++++ qemud/qemud.c | 26 ++++---- src/driver.h | 4 ++ src/internal.h | 2 + src/libvirt.c | 11 ++++ src/libvirt_sym.version | 1 + src/lxc_driver.c | 140 ++++++++++++++++++++++++++++------------ src/qemu_driver.c | 1 + src/remote_internal.c | 1 + src/storage_driver.c | 1 + 10 files changed, 147 insertions(+), 54 deletions(-) diff --git a/ChangeLog b/ChangeLog index cd0409f7cc..1664e1c08f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +Mon May 12 23:32:21 PST 2008 David L. Leskovec + + * 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 * bootstrap: Added verify module diff --git a/qemud/qemud.c b/qemud/qemud.c index a9d825d690..d308dfe2f4 100644 --- a/qemud/qemud.c +++ b/qemud/qemud.c @@ -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); diff --git a/src/driver.h b/src/driver.h index 61f8f38b1e..12073419e1 100644 --- a/src/driver.h +++ b/src/driver.h @@ -11,6 +11,8 @@ #include +#include + #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; }; /* diff --git a/src/internal.h b/src/internal.h index 7df866154e..3327ea13a4 100644 --- a/src/internal.h +++ b/src/internal.h @@ -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); diff --git a/src/libvirt.c b/src/libvirt.c index d4933043b4..7f5f1f148d 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -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; +} + /** diff --git a/src/libvirt_sym.version b/src/libvirt_sym.version index 77f0b5534e..bd2ad1f5df 100644 --- a/src/libvirt_sym.version +++ b/src/libvirt_sym.version @@ -170,6 +170,7 @@ __virStateCleanup; __virStateReload; __virStateActive; + __virStateSigDispatcher; __virDrvSupportsFeature; diff --git a/src/lxc_driver.c b/src/lxc_driver.c index fd51241586..e78c718316 100644 --- a/src/lxc_driver.c +++ b/src/lxc_driver.c @@ -924,6 +924,70 @@ error_out: return rc; } +/** + * lxcVmCleanup: + * @vm: Ptr to VM to clean up + * + * 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 lxcVMCleanup(lxc_driver_t *driver, lxc_vm_t * vm) +{ + int rc = -1; + int waitRc; + int childStatus = -1; + + while (((waitRc = waitpid(vm->def->id, &childStatus, 0)) == -1) && + errno == EINTR); + + if (waitRc != vm->def->id) { + 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 = 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(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("sending SIGKILL to tty process failed: %s"), + strerror(errno)); + + goto tty_error_out; + } + } + + while (((waitRc = waitpid(vm->pid, &childStatus, 0)) == -1) && + errno == EINTR); + + if (waitRc != vm->pid) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("waitpid failed to wait for tty %d: %d %s"), + vm->pid, waitRc, strerror(errno)); + } + +tty_error_out: + vm->state = VIR_DOMAIN_SHUTOFF; + vm->pid = -1; + vm->def->id = -1; + driver->nactivevms--; + driver->ninactivevms++; + lxcSaveConfig(NULL, driver, vm, vm->def); + + return rc; + } + /** * lxcDomainDestroy: * @dom: Ptr to domain to destroy @@ -935,10 +999,8 @@ error_out: static int lxcDomainDestroy(virDomainPtr dom) { 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, @@ -957,47 +1019,7 @@ static int lxcDomainDestroy(virDomainPtr dom) vm->state = VIR_DOMAIN_SHUTDOWN; - while (((waitRc = waitpid(vm->def->id, &childStatus, 0)) == -1) && - errno == EINTR); - - if (waitRc != vm->def->id) { - lxcError(dom->conn, dom, 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); - -kill_tty: - if (0 > (kill(vm->pid, SIGKILL))) { - if (ESRCH != errno) { - lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR, - _("sending SIGKILL to tty process failed: %s"), - strerror(errno)); - - goto tty_error_out; - } - } - - while (((waitRc = waitpid(vm->pid, &childStatus, 0)) == -1) && - errno == EINTR); - - if (waitRc != vm->pid) { - lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR, - _("waitpid failed to wait for tty %d: %d %s"), - vm->pid, waitRc, strerror(errno)); - } - -tty_error_out: - vm->state = VIR_DOMAIN_SHUTOFF; - vm->pid = -1; - vm->def->id = -1; - driver->nactivevms--; - driver->ninactivevms++; - - rc = 0; + 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) diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 10868c1b26..7d52798242 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -3198,6 +3198,7 @@ static virStateDriver qemuStateDriver = { qemudShutdown, qemudReload, qemudActive, + NULL }; int qemudRegister(void) { diff --git a/src/remote_internal.c b/src/remote_internal.c index f3bef3d39e..9474028d1c 100644 --- a/src/remote_internal.c +++ b/src/remote_internal.c @@ -4793,6 +4793,7 @@ static virStateDriver state_driver = { NULL, NULL, NULL, + NULL }; diff --git a/src/storage_driver.c b/src/storage_driver.c index 7f1ce0cdc9..9478c36419 100644 --- a/src/storage_driver.c +++ b/src/storage_driver.c @@ -1245,6 +1245,7 @@ static virStateDriver stateDriver = { storageDriverShutdown, storageDriverReload, storageDriverActive, + NULL }; int storageRegister(void) {