mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-26 18:41:17 +00:00
Enable libvirtd drivers to handle signals, in lxc, sigchld triggers vm cleanup
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
This commit is contained in:
parent
098ba1a433
commit
94311de539
14
ChangeLog
14
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>
|
Thu May 9 12:40:11 EST 2008 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
* bootstrap: Added verify module
|
* bootstrap: Added verify module
|
||||||
|
@ -109,16 +109,16 @@ static gnutls_dh_params_t dh_params;
|
|||||||
static sig_atomic_t sig_errors = 0;
|
static sig_atomic_t sig_errors = 0;
|
||||||
static int sig_lasterrno = 0;
|
static int sig_lasterrno = 0;
|
||||||
|
|
||||||
static void sig_handler(int sig) {
|
static void sig_handler(int sig, siginfo_t * siginfo,
|
||||||
unsigned char sigc = sig;
|
void* context ATTRIBUTE_UNUSED) {
|
||||||
int origerrno;
|
int origerrno;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (sig == SIGCHLD) /* We explicitly waitpid the child later */
|
/* set the sig num in the struct */
|
||||||
return;
|
siginfo->si_signo = sig;
|
||||||
|
|
||||||
origerrno = errno;
|
origerrno = errno;
|
||||||
r = safewrite(sigwrite, &sigc, 1);
|
r = safewrite(sigwrite, siginfo, sizeof(*siginfo));
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
sig_errors++;
|
sig_errors++;
|
||||||
sig_lasterrno = errno;
|
sig_lasterrno = errno;
|
||||||
@ -232,10 +232,10 @@ static void qemudDispatchSignalEvent(int fd ATTRIBUTE_UNUSED,
|
|||||||
int events ATTRIBUTE_UNUSED,
|
int events ATTRIBUTE_UNUSED,
|
||||||
void *opaque) {
|
void *opaque) {
|
||||||
struct qemud_server *server = (struct qemud_server *)opaque;
|
struct qemud_server *server = (struct qemud_server *)opaque;
|
||||||
unsigned char sigc;
|
siginfo_t siginfo;
|
||||||
int ret;
|
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"),
|
qemudLog(QEMUD_ERR, _("Failed to read from signal pipe: %s"),
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return;
|
return;
|
||||||
@ -243,7 +243,7 @@ static void qemudDispatchSignalEvent(int fd ATTRIBUTE_UNUSED,
|
|||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
switch (sigc) {
|
switch (siginfo.si_signo) {
|
||||||
case SIGHUP:
|
case SIGHUP:
|
||||||
qemudLog(QEMUD_INFO, "%s", _("Reloading configuration on SIGHUP"));
|
qemudLog(QEMUD_INFO, "%s", _("Reloading configuration on SIGHUP"));
|
||||||
if (virStateReload() < 0)
|
if (virStateReload() < 0)
|
||||||
@ -253,11 +253,15 @@ static void qemudDispatchSignalEvent(int fd ATTRIBUTE_UNUSED,
|
|||||||
case SIGINT:
|
case SIGINT:
|
||||||
case SIGQUIT:
|
case SIGQUIT:
|
||||||
case SIGTERM:
|
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;
|
server->shutdown = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
qemudLog(QEMUD_INFO, _("Received signal %d, dispatching to drivers"),
|
||||||
|
siginfo.si_signo);
|
||||||
|
virStateSigDispatcher(&siginfo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2186,8 +2190,8 @@ int main(int argc, char **argv) {
|
|||||||
goto error1;
|
goto error1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sig_action.sa_handler = sig_handler;
|
sig_action.sa_sigaction = sig_handler;
|
||||||
sig_action.sa_flags = 0;
|
sig_action.sa_flags = SA_SIGINFO;
|
||||||
sigemptyset(&sig_action.sa_mask);
|
sigemptyset(&sig_action.sa_mask);
|
||||||
|
|
||||||
sigaction(SIGHUP, &sig_action, NULL);
|
sigaction(SIGHUP, &sig_action, NULL);
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include <libxml/uri.h>
|
#include <libxml/uri.h>
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -565,6 +567,7 @@ typedef int (*virDrvStateInitialize) (void);
|
|||||||
typedef int (*virDrvStateCleanup) (void);
|
typedef int (*virDrvStateCleanup) (void);
|
||||||
typedef int (*virDrvStateReload) (void);
|
typedef int (*virDrvStateReload) (void);
|
||||||
typedef int (*virDrvStateActive) (void);
|
typedef int (*virDrvStateActive) (void);
|
||||||
|
typedef int (*virDrvSigHandler) (siginfo_t *siginfo);
|
||||||
|
|
||||||
typedef struct _virStateDriver virStateDriver;
|
typedef struct _virStateDriver virStateDriver;
|
||||||
typedef virStateDriver *virStateDriverPtr;
|
typedef virStateDriver *virStateDriverPtr;
|
||||||
@ -574,6 +577,7 @@ struct _virStateDriver {
|
|||||||
virDrvStateCleanup cleanup;
|
virDrvStateCleanup cleanup;
|
||||||
virDrvStateReload reload;
|
virDrvStateReload reload;
|
||||||
virDrvStateActive active;
|
virDrvStateActive active;
|
||||||
|
virDrvSigHandler sigHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -344,10 +344,12 @@ int __virStateInitialize(void);
|
|||||||
int __virStateCleanup(void);
|
int __virStateCleanup(void);
|
||||||
int __virStateReload(void);
|
int __virStateReload(void);
|
||||||
int __virStateActive(void);
|
int __virStateActive(void);
|
||||||
|
int __virStateSigDispatcher(siginfo_t *siginfo);
|
||||||
#define virStateInitialize() __virStateInitialize()
|
#define virStateInitialize() __virStateInitialize()
|
||||||
#define virStateCleanup() __virStateCleanup()
|
#define virStateCleanup() __virStateCleanup()
|
||||||
#define virStateReload() __virStateReload()
|
#define virStateReload() __virStateReload()
|
||||||
#define virStateActive() __virStateActive()
|
#define virStateActive() __virStateActive()
|
||||||
|
#define virStateSigDispatcher(s) __virStateSigDispatcher(s)
|
||||||
|
|
||||||
int __virDrvSupportsFeature (virConnectPtr conn, int feature);
|
int __virDrvSupportsFeature (virConnectPtr conn, int feature);
|
||||||
|
|
||||||
|
@ -607,6 +607,17 @@ int __virStateActive(void) {
|
|||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -170,6 +170,7 @@
|
|||||||
__virStateCleanup;
|
__virStateCleanup;
|
||||||
__virStateReload;
|
__virStateReload;
|
||||||
__virStateActive;
|
__virStateActive;
|
||||||
|
__virStateSigDispatcher;
|
||||||
|
|
||||||
__virDrvSupportsFeature;
|
__virDrvSupportsFeature;
|
||||||
|
|
||||||
|
140
src/lxc_driver.c
140
src/lxc_driver.c
@ -924,6 +924,70 @@ error_out:
|
|||||||
return rc;
|
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:
|
* lxcDomainDestroy:
|
||||||
* @dom: Ptr to domain to destroy
|
* @dom: Ptr to domain to destroy
|
||||||
@ -935,10 +999,8 @@ error_out:
|
|||||||
static int lxcDomainDestroy(virDomainPtr dom)
|
static int lxcDomainDestroy(virDomainPtr dom)
|
||||||
{
|
{
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
int waitRc;
|
|
||||||
lxc_driver_t *driver = (lxc_driver_t*)dom->conn->privateData;
|
lxc_driver_t *driver = (lxc_driver_t*)dom->conn->privateData;
|
||||||
lxc_vm_t *vm = lxcFindVMByID(driver, dom->id);
|
lxc_vm_t *vm = lxcFindVMByID(driver, dom->id);
|
||||||
int childStatus;
|
|
||||||
|
|
||||||
if (!vm) {
|
if (!vm) {
|
||||||
lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
|
lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
|
||||||
@ -957,47 +1019,7 @@ static int lxcDomainDestroy(virDomainPtr dom)
|
|||||||
|
|
||||||
vm->state = VIR_DOMAIN_SHUTDOWN;
|
vm->state = VIR_DOMAIN_SHUTDOWN;
|
||||||
|
|
||||||
while (((waitRc = waitpid(vm->def->id, &childStatus, 0)) == -1) &&
|
rc = lxcVMCleanup(driver, vm);
|
||||||
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;
|
|
||||||
|
|
||||||
error_out:
|
error_out:
|
||||||
return rc;
|
return rc;
|
||||||
@ -1077,6 +1099,37 @@ lxcActive(void) {
|
|||||||
return 0;
|
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 */
|
/* Function Tables */
|
||||||
static virDriver lxcDriver = {
|
static virDriver lxcDriver = {
|
||||||
@ -1145,6 +1198,7 @@ static virStateDriver lxcStateDriver = {
|
|||||||
lxcShutdown,
|
lxcShutdown,
|
||||||
NULL, /* reload */
|
NULL, /* reload */
|
||||||
lxcActive,
|
lxcActive,
|
||||||
|
lxcSigHandler
|
||||||
};
|
};
|
||||||
|
|
||||||
int lxcRegister(void)
|
int lxcRegister(void)
|
||||||
|
@ -3198,6 +3198,7 @@ static virStateDriver qemuStateDriver = {
|
|||||||
qemudShutdown,
|
qemudShutdown,
|
||||||
qemudReload,
|
qemudReload,
|
||||||
qemudActive,
|
qemudActive,
|
||||||
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
int qemudRegister(void) {
|
int qemudRegister(void) {
|
||||||
|
@ -4793,6 +4793,7 @@ static virStateDriver state_driver = {
|
|||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1245,6 +1245,7 @@ static virStateDriver stateDriver = {
|
|||||||
storageDriverShutdown,
|
storageDriverShutdown,
|
||||||
storageDriverReload,
|
storageDriverReload,
|
||||||
storageDriverActive,
|
storageDriverActive,
|
||||||
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
int storageRegister(void) {
|
int storageRegister(void) {
|
||||||
|
Loading…
Reference in New Issue
Block a user