Fix a few issues related to restart of libvirtd with containers running.

Mon May 12 23:32:21 PST 2008 David L. Leskovec <dlesko@linux.vnet.ibm.com>

	* 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
This commit is contained in:
David L. Leskovec 2008-06-05 06:03:00 +00:00
parent eeb224b812
commit 0bd57cdbe1
4 changed files with 258 additions and 2 deletions

View File

@ -1,3 +1,15 @@
Wed Jun 4 23:02:21 PST 2008 David L. Leskovec <dlesko@linux.vnet.ibm.com>
* 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 <rjones@redhat.com>
* src/xm_internal.c: If vcpu cpuset attribute is invalid

View File

@ -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 */

View File

@ -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,

View File

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