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); }