]> xenbits.xensource.com Git - libvirt.git/commitdiff
Fix a few issues related to restart of libvirtd with containers running.
authorDavid L. Leskovec <dlesko@linux.vnet.ibm.com>
Thu, 5 Jun 2008 06:03:00 +0000 (06:03 +0000)
committerDavid L. Leskovec <dlesko@linux.vnet.ibm.com>
Thu, 5 Jun 2008 06:03:00 +0000 (06:03 +0000)
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

ChangeLog
src/lxc_conf.c
src/lxc_conf.h
src/lxc_driver.c

index 491bc56964d81a9af1821ec1ae26b0d452740ee1..3fd17126b28c569f69afe28ffc92471c1d83519b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
index f9bd20ab4601b81035de8f17125439990eb95bbc..e1138f20a0a86774983762b35202d42fce51a6cf 100644 (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 */
index 92dec390bbe4118a708581a70d7888186585ad20..625cd3e373d88661ec96a03cb7956c69d38c468c 100644 (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,
index e78c718316ffa47420bb3d6728e7a1c2e5a71055..ba747327a04d24e605d6977fec50355e73ea8eb0 100644 (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);
 }