From 0bd57cdbe10a141325ea326e5e759a454f13792b Mon Sep 17 00:00:00 2001 From: "David L. Leskovec" Date: Thu, 5 Jun 2008 06:03:00 +0000 Subject: [PATCH] Fix a few issues related to restart of libvirtd with containers running. Mon May 12 23:32:21 PST 2008 David L. Leskovec * src/lxc_driver.c: Add sanity of tty pid before kill() Ignore ECHILD errors during VM cleanup Call functions to store tty pid and cleanup tty pid file * src/lxc_conf.h: Add function to verify container process exists Add facilities to manage storing the tty forward process pid * src/lxc_conf.c: Add function to verify container process exists Call function to verify container process during config load Add facilities to manage storing the tty forward process pid Call function to load tty pid during load config --- ChangeLog | 12 +++ src/lxc_conf.c | 224 +++++++++++++++++++++++++++++++++++++++++++++++ src/lxc_conf.h | 7 ++ src/lxc_driver.c | 17 +++- 4 files changed, 258 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 491bc56964..3fd17126b2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +Wed Jun 4 23:02:21 PST 2008 David L. Leskovec + + * src/lxc_driver.c: Add sanity of tty pid before kill() + Ignore ECHILD errors during VM cleanup + Call functions to store tty pid and cleanup tty pid file + * src/lxc_conf.h: Add function to verify container process exists + Add facilities to manage storing the tty forward process pid + * src/lxc_conf.c: Add function to verify container process exists + Call function to verify container process during config load + Add facilities to manage storing the tty forward process pid + Call function to load tty pid during load config + Tue Jun 3 08:58:00 BST 2008 Richard W.M. Jones * src/xm_internal.c: If vcpu cpuset attribute is invalid diff --git a/src/lxc_conf.c b/src/lxc_conf.c index f9bd20ab46..e1138f20a0 100644 --- a/src/lxc_conf.c +++ b/src/lxc_conf.c @@ -348,6 +348,12 @@ static lxc_vm_def_t * lxcParseXML(virConnectPtr conn, xmlDocPtr docPtr) _("invalid domain id")); goto error; } + + /* verify the container process still exists */ + if (1 != lxcCheckContainerProcess(containerDef)) { + containerDef->id = -1; + } + } else { containerDef->id = -1; } @@ -458,6 +464,46 @@ lxc_vm_t * lxcAssignVMDef(virConnectPtr conn, return vm; } +/** + * lxcCheckContainerProcess: + * @def: Ptr to VM definition + * + * Checks if the container process (stored at def->id is running + * + * Returns on success or -1 in case of error + * 0 - no process with id vm->def->id + * 1 - container process exists + * -1 - error + */ +int lxcCheckContainerProcess(lxc_vm_def_t *def) +{ + int rc = -1; + + if (1 < def->id) { + if (-1 == kill(def->id, 0)) { + if (ESRCH == errno) { + rc = 0; + DEBUG("pid %d no longer exists", def->id); + goto done; + } + + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("error checking container process: %d %s"), + def->id, strerror(errno)); + goto done; + } + + DEBUG("pid %d still exists", def->id); + rc = 1; + goto done; + } + + rc = 0; + +done: + return rc; +} + void lxcRemoveInactiveVM(lxc_driver_t *driver, lxc_vm_t *vm) { @@ -602,6 +648,10 @@ static lxc_vm_t * lxcLoadConfig(lxc_driver_t *driver, strncpy(vm->configFileBase, file, PATH_MAX); vm->configFile[PATH_MAX-1] = '\0'; + if (lxcLoadTtyPid(driver, vm) < 0) { + DEBUG0("failed to load tty pid"); + } + return vm; } @@ -614,6 +664,8 @@ int lxcLoadDriverConfig(lxc_driver_t *driver) return -1; } + driver->stateDir = strdup(LOCAL_STATE_DIR "/run/libvirt/lxc"); + return 0; } @@ -835,4 +887,176 @@ int lxcDeleteConfig(virConnectPtr conn, return 0; } +/** + * lxcStoreTtyPid: + * @driver: pointer to driver + * @vm: Ptr to VM + * + * Stores the pid of the tty forward process contained in vm->pid + * LOCAL_STATE_DIR/run/libvirt/lxc/{container_name}.pid + * + * Returns 0 on success or -1 in case of error + */ +int lxcStoreTtyPid(const lxc_driver_t *driver, lxc_vm_t *vm) +{ + int rc = -1; + int fd; + FILE *file = NULL; + + if (vm->ttyPidFile[0] == 0x00) { + if ((rc = virFileMakePath(driver->stateDir))) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot create lxc state directory %s: %s"), + driver->stateDir, strerror(rc)); + goto error_out; + } + + if (virFileBuildPath(driver->stateDir, vm->def->name, ".pid", + vm->ttyPidFile, PATH_MAX) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot construct tty pid file path")); + goto error_out; + } + } + + if ((fd = open(vm->ttyPidFile, + O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR)) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot create tty pid file %s: %s"), + vm->ttyPidFile, strerror(errno)); + goto error_out; + } + + if (!(file = fdopen(fd, "w"))) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot fdopen tty pid file %s: %s"), + vm->ttyPidFile, strerror(errno)); + + if (close(fd) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to close tty pid file %s: %s"), + vm->ttyPidFile, strerror(errno)); + } + + goto error_out; + } + + if (fprintf(file, "%d", vm->pid) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot write tty pid file %s: %s"), + vm->ttyPidFile, strerror(errno)); + + goto fclose_error_out; + } + + rc = 0; + +fclose_error_out: + if (fclose(file) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to close tty pid file %s: %s"), + vm->ttyPidFile, strerror(errno)); + } + +error_out: + return rc; +} + +/** + * lxcLoadTtyPid: + * @driver: pointer to driver + * @vm: Ptr to VM + * + * Loads the pid of the tty forward process from the pid file. + * LOCAL_STATE_DIR/run/libvirt/lxc/{container_name}.pid + * + * Returns + * > 0 - pid of tty process + * 0 - no tty pid file + * -1 - error + */ +int lxcLoadTtyPid(const lxc_driver_t *driver, lxc_vm_t *vm) +{ + int rc = -1; + FILE *file; + + if (vm->ttyPidFile[0] == 0x00) { + if ((rc = virFileMakePath(driver->stateDir))) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot create lxc state directory %s: %s"), + driver->stateDir, strerror(rc)); + goto cleanup; + } + + if (virFileBuildPath(driver->stateDir, vm->def->name, ".pid", + vm->ttyPidFile, PATH_MAX) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot construct tty pid file path")); + goto cleanup; + } + } + + if (!(file = fopen(vm->ttyPidFile, "r"))) { + if (ENOENT == errno) { + rc = 0; + goto cleanup; + } + + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot open tty pid file %s: %s"), + vm->ttyPidFile, strerror(errno)); + goto cleanup; + } + + if (fscanf(file, "%d", &(vm->pid)) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot read tty pid file %s: %s"), + vm->ttyPidFile, strerror(errno)); + goto cleanup; + } + + if (fclose(file) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to close tty pid file %s: %s"), + vm->ttyPidFile, strerror(errno)); + goto cleanup; + } + + rc = vm->pid; + + cleanup: + return rc; +} + +/** + * lxcDeleteTtyPid: + * @vm: Ptr to VM + * + * Unlinks the tty pid file for the vm + * LOCAL_STATE_DIR/run/libvirt/lxc/{container_name}.pid + * + * Returns on 0 success or -1 in case of error + */ +int lxcDeleteTtyPidFile(const lxc_vm_t *vm) +{ + if (vm->ttyPidFile[0] == 0x00) { + goto no_file; + } + + if (unlink(vm->ttyPidFile) < 0) { + if (errno == ENOENT) { + goto no_file; + } + + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot remove ttyPidFile %s: %s"), vm->ttyPidFile, + strerror(errno)); + return -1; + } + +no_file: + return 0; +} + #endif /* WITH_LXC */ diff --git a/src/lxc_conf.h b/src/lxc_conf.h index 92dec390bb..625cd3e373 100644 --- a/src/lxc_conf.h +++ b/src/lxc_conf.h @@ -71,6 +71,8 @@ struct __lxc_vm { char configFile[PATH_MAX]; char configFileBase[PATH_MAX]; + char ttyPidFile[PATH_MAX]; + int parentTty; int containerTtyFd; char *containerTty; @@ -86,6 +88,7 @@ struct __lxc_driver { int nactivevms; int ninactivevms; char* configDir; + char* stateDir; }; /* Types and structs */ @@ -124,6 +127,7 @@ lxc_vm_t *lxcFindVMByUUID(const lxc_driver_t *driver, const unsigned char *uuid); lxc_vm_t *lxcFindVMByName(const lxc_driver_t *driver, const char *name); +int lxcCheckContainerProcess(lxc_vm_def_t *vm); void lxcRemoveInactiveVM(lxc_driver_t *driver, lxc_vm_t *vm); void lxcFreeVMs(lxc_vm_t *vms); @@ -133,6 +137,9 @@ int lxcDeleteConfig(virConnectPtr conn, lxc_driver_t *driver, const char *configFile, const char *name); +int lxcStoreTtyPid(const lxc_driver_t *driver, lxc_vm_t *vm); +int lxcLoadTtyPid(const lxc_driver_t *driver, lxc_vm_t *vm); +int lxcDeleteTtyPidFile(const lxc_vm_t *vm); void lxcError(virConnectPtr conn, virDomainPtr dom, diff --git a/src/lxc_driver.c b/src/lxc_driver.c index e78c718316..ba747327a0 100644 --- a/src/lxc_driver.c +++ b/src/lxc_driver.c @@ -328,6 +328,8 @@ static int lxcDomainUndefine(virDomainPtr dom) vm->configFile[0] = '\0'; + lxcDeleteTtyPidFile(vm); + lxcRemoveInactiveVM(driver, vm); return 0; @@ -798,6 +800,10 @@ static int lxcVmStart(virConnectPtr conn, lxcTtyForward(vm->parentTty, vm->containerTtyFd); } + if (lxcStoreTtyPid(driver, vm)) { + DEBUG0("unable to store tty pid"); + } + close(vm->parentTty); close(vm->containerTtyFd); @@ -943,7 +949,7 @@ static int lxcVMCleanup(lxc_driver_t *driver, lxc_vm_t * vm) while (((waitRc = waitpid(vm->def->id, &childStatus, 0)) == -1) && errno == EINTR); - if (waitRc != vm->def->id) { + if ((waitRc != vm->def->id) && (errno != ECHILD)) { lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("waitpid failed to wait for container %d: %d %s"), vm->def->id, waitRc, strerror(errno)); @@ -958,6 +964,11 @@ static int lxcVMCleanup(lxc_driver_t *driver, lxc_vm_t * vm) } kill_tty: + if (2 > vm->pid) { + DEBUG("not killing tty process with pid %d", vm->pid); + goto tty_error_out; + } + if (0 > (kill(vm->pid, SIGKILL))) { if (ESRCH != errno) { lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, @@ -971,7 +982,7 @@ kill_tty: while (((waitRc = waitpid(vm->pid, &childStatus, 0)) == -1) && errno == EINTR); - if (waitRc != vm->pid) { + if ((waitRc != vm->pid) && (errno != ECHILD)) { lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("waitpid failed to wait for tty %d: %d %s"), vm->pid, waitRc, strerror(errno)); @@ -980,6 +991,7 @@ kill_tty: tty_error_out: vm->state = VIR_DOMAIN_SHUTOFF; vm->pid = -1; + lxcDeleteTtyPidFile(vm); vm->def->id = -1; driver->nactivevms--; driver->ninactivevms++; @@ -1063,6 +1075,7 @@ static int lxcStartup(void) static void lxcFreeDriver(lxc_driver_t *driver) { free(driver->configDir); + free(driver->stateDir); free(driver); }