[libvirt] [PATCH 4/6] LXC: Wire up the virDomainCreate{XML}WithFiles methods

Daniel P. Berrange berrange at redhat.com
Fri Jul 12 15:38:30 UTC 2013


From: "Daniel P. Berrange" <berrange at redhat.com>

Wire up the new virDomainCreate{XML}WithFiles methods in the
LXC driver, so that FDs get passed down to the init process.

The lxc_container code needs to do a little dance in order
to renumber the file descriptors it receives into linear
order, starting from STDERR_FILENO + 1.

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 src/lxc/lxc_container.c  | 136 +++++++++++++++++++++++++++++++++++++----------
 src/lxc/lxc_container.h  |   6 ++-
 src/lxc/lxc_controller.c |  36 +++++++++++--
 src/lxc/lxc_driver.c     |  45 +++++++++++++---
 src/lxc/lxc_process.c    |  16 +++++-
 src/lxc/lxc_process.h    |   1 +
 6 files changed, 197 insertions(+), 43 deletions(-)

diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 940233b..d59de08 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -103,8 +103,10 @@ struct __lxc_child_argv {
     size_t nveths;
     char **veths;
     int monitor;
-    char **ttyPaths;
+    size_t npassFDs;
+    int *passFDs;
     size_t nttyPaths;
+    char **ttyPaths;
     int handshakefd;
 };
 
@@ -217,20 +219,28 @@ static virCommandPtr lxcContainerBuildInitCmd(virDomainDefPtr vmDef)
 }
 
 /**
- * lxcContainerSetStdio:
+ * lxcContainerSetupFDs:
  * @control: control FD from parent
  * @ttyfd: FD of tty to set as the container console
+ * @npassFDs: number of extra FDs
+ * @passFDs: list of extra FDs
  *
- * Sets the given tty as the primary conosole for the container as well as
- * stdout, stdin and stderr.
+ * Setup file descriptors in the container. @ttyfd is set to be
+ * the container's stdin, stdout & stderr. Any FDs included in
+ * @passFDs, will be dup()'d such that they start from stderr+1
+ * with no gaps.
  *
  * Returns 0 on success or -1 in case of error
  */
-static int lxcContainerSetStdio(int control, int ttyfd, int handshakefd)
+static int lxcContainerSetupFDs(int *ttyfd,
+                                size_t npassFDs, int *passFDs)
 {
     int rc = -1;
     int open_max;
     int fd;
+    int last_fd;
+    size_t i;
+    size_t j;
 
     if (setsid() < 0) {
         virReportSystemError(errno, "%s",
@@ -238,44 +248,99 @@ static int lxcContainerSetStdio(int control, int ttyfd, int handshakefd)
         goto cleanup;
     }
 
-    if (ioctl(ttyfd, TIOCSCTTY, NULL) < 0) {
+    if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0) {
         virReportSystemError(errno, "%s",
                              _("ioctl(TIOCSTTY) failed"));
         goto cleanup;
     }
 
-    /* Just in case someone forget to set FD_CLOEXEC, explicitly
-     * close all FDs before executing the container */
-    open_max = sysconf(_SC_OPEN_MAX);
-    if (open_max < 0) {
+    if (dup2(*ttyfd, STDIN_FILENO) < 0) {
         virReportSystemError(errno, "%s",
-                             _("sysconf(_SC_OPEN_MAX) failed"));
+                             _("dup2(stdin) failed"));
         goto cleanup;
     }
-    for (fd = 0; fd < open_max; fd++)
-        if (fd != ttyfd && fd != control && fd != handshakefd) {
-            int tmpfd = fd;
-            VIR_MASS_CLOSE(tmpfd);
-        }
 
-    if (dup2(ttyfd, 0) < 0) {
+    if (dup2(*ttyfd, STDOUT_FILENO) < 0) {
         virReportSystemError(errno, "%s",
-                             _("dup2(stdin) failed"));
+                             _("dup2(stdout) failed"));
         goto cleanup;
     }
 
-    if (dup2(ttyfd, 1) < 0) {
+    if (dup2(*ttyfd, STDERR_FILENO) < 0) {
         virReportSystemError(errno, "%s",
-                             _("dup2(stdout) failed"));
+                             _("dup2(stderr) failed"));
         goto cleanup;
     }
 
-    if (dup2(ttyfd, 2) < 0) {
+    VIR_FORCE_CLOSE(*ttyfd);
+
+    /* Any FDs in @passFDs need to be moved around so that
+     * they are numbered, without gaps, starting from
+     * STDERR_FILENO + 1
+     */
+    for (i = 0; i < npassFDs; i++) {
+        int wantfd;
+
+        wantfd = STDERR_FILENO + i + 1;
+        VIR_DEBUG("Pass %d onto %d", passFDs[i], wantfd);
+
+        /* If we already have desired FD number, life
+         * is easy. Nothing needs renumbering */
+        if (passFDs[i] == wantfd)
+            continue;
+
+        /*
+         * Lets check to see if any later FDs are occupying
+         * our desired FD number. If so, we must move them
+         * out of the way
+         */
+        for (j = i + 1; j < npassFDs; j++) {
+            if (passFDs[j] == wantfd) {
+                VIR_DEBUG("Clash %zu", j);
+                int newfd = dup(passFDs[j]);
+                if (newfd < 0) {
+                    virReportSystemError(errno,
+                                         _("Cannot move fd %d out of the way"),
+                                         passFDs[j]);
+                    goto cleanup;
+                }
+                /* We're intentionally not closing the
+                 * old value of passFDs[j], because we
+                 * don't want later iterations of the
+                 * loop to take it back. dup2() will
+                 * cause it to be closed shortly anyway
+                 */
+                VIR_DEBUG("Moved clash onto %d", newfd);
+                passFDs[j] = newfd;
+            }
+        }
+
+        /* Finally we can move into our desired FD number */
+        if (dup2(passFDs[i], wantfd) < 0) {
+            virReportSystemError(errno,
+                                 _("Cannot duplicate fd %d onto fd %d"),
+                                 passFDs[i], wantfd);
+            goto cleanup;
+        }
+        VIR_FORCE_CLOSE(passFDs[i]);
+    }
+
+    last_fd = STDERR_FILENO + npassFDs;
+
+    /* Just in case someone forget to set FD_CLOEXEC, explicitly
+     * close all remaining FDs before executing the container */
+    open_max = sysconf(_SC_OPEN_MAX);
+    if (open_max < 0) {
         virReportSystemError(errno, "%s",
-                             _("dup2(stderr) failed"));
+                             _("sysconf(_SC_OPEN_MAX) failed"));
         goto cleanup;
     }
 
+    for (fd = last_fd + 1; fd < open_max; fd++) {
+        int tmpfd = fd;
+        VIR_MASS_CLOSE(tmpfd);
+    }
+
     rc = 0;
 
 cleanup:
@@ -2044,9 +2109,11 @@ static int lxcContainerChild(void *data)
     if (virSecurityManagerSetProcessLabel(argv->securityDriver, vmDef) < 0)
         goto cleanup;
 
-    if (lxcContainerSetStdio(argv->monitor, ttyfd, argv->handshakefd) < 0) {
+    VIR_FORCE_CLOSE(argv->handshakefd);
+    VIR_FORCE_CLOSE(argv->monitor);
+    if (lxcContainerSetupFDs(&ttyfd,
+                             argv->npassFDs, argv->passFDs) < 0)
         goto cleanup;
-    }
 
     ret = 0;
 cleanup:
@@ -2129,18 +2196,29 @@ int lxcContainerStart(virDomainDefPtr def,
                       virSecurityManagerPtr securityDriver,
                       size_t nveths,
                       char **veths,
+                      size_t npassFDs,
+                      int *passFDs,
                       int control,
                       int handshakefd,
-                      char **ttyPaths,
-                      size_t nttyPaths)
+                      size_t nttyPaths,
+                      char **ttyPaths)
 {
     pid_t pid;
     int cflags;
     int stacksize = getpagesize() * 4;
     char *stack, *stacktop;
-    lxc_child_argv_t args = { def, securityDriver,
-                              nveths, veths, control,
-                              ttyPaths, nttyPaths, handshakefd};
+    lxc_child_argv_t args = {
+        .config = def,
+        .securityDriver = securityDriver,
+        .nveths = nveths,
+        .veths = veths,
+        .npassFDs = npassFDs,
+        .passFDs = passFDs,
+        .monitor = control,
+        .nttyPaths = nttyPaths,
+        .ttyPaths = ttyPaths,
+        .handshakefd = handshakefd
+    };
 
     /* allocate a stack for the container */
     if (VIR_ALLOC_N(stack, stacksize) < 0)
diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h
index 6f270d7..538154a 100644
--- a/src/lxc/lxc_container.h
+++ b/src/lxc/lxc_container.h
@@ -56,10 +56,12 @@ int lxcContainerStart(virDomainDefPtr def,
                       virSecurityManagerPtr securityDriver,
                       size_t nveths,
                       char **veths,
+                      size_t npassFDs,
+                      int *passFDs,
                       int control,
                       int handshakefd,
-                      char **ttyPaths,
-                      size_t nttyPaths);
+                      size_t nttyPaths,
+                      char **ttyPaths);
 
 int lxcContainerAvailable(int features);
 
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index 3f3d93b..f2eba33 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -108,6 +108,9 @@ struct _virLXCController {
     size_t nveths;
     char **veths;
 
+    size_t npassFDs;
+    int *passFDs;
+
     size_t nconsoles;
     virLXCControllerConsolePtr consoles;
     char *devptmx;
@@ -253,6 +256,10 @@ static void virLXCControllerFree(virLXCControllerPtr ctrl)
         VIR_FREE(ctrl->veths[i]);
     VIR_FREE(ctrl->veths);
 
+    for (i = 0; i < ctrl->npassFDs; i++)
+        VIR_FORCE_CLOSE(ctrl->passFDs[i]);
+    VIR_FREE(ctrl->passFDs);
+
     for (i = 0; i < ctrl->nconsoles; i++)
         virLXCControllerConsoleClose(&(ctrl->consoles[i]));
     VIR_FREE(ctrl->consoles);
@@ -1737,14 +1744,19 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
                                            ctrl->securityManager,
                                            ctrl->nveths,
                                            ctrl->veths,
+                                           ctrl->npassFDs,
+                                           ctrl->passFDs,
                                            control[1],
                                            containerhandshake[1],
-                                           containerTTYPaths,
-                                           ctrl->nconsoles)) < 0)
+                                           ctrl->nconsoles,
+                                           containerTTYPaths)) < 0)
         goto cleanup;
     VIR_FORCE_CLOSE(control[1]);
     VIR_FORCE_CLOSE(containerhandshake[1]);
 
+    for (i = 0; i < ctrl->npassFDs; i++)
+        VIR_FORCE_CLOSE(ctrl->passFDs[i]);
+
     if (virLXCControllerSetupUserns(ctrl) < 0)
         goto cleanup;
 
@@ -1811,6 +1823,7 @@ int main(int argc, char *argv[])
         { "name",   1, NULL, 'n' },
         { "veth",   1, NULL, 'v' },
         { "console", 1, NULL, 'c' },
+        { "passfd", 1, NULL, 'p' },
         { "handshakefd", 1, NULL, 's' },
         { "security", 1, NULL, 'S' },
         { "help", 0, NULL, 'h' },
@@ -1818,6 +1831,8 @@ int main(int argc, char *argv[])
     };
     int *ttyFDs = NULL;
     size_t nttyFDs = 0;
+    int *passFDs = NULL;
+    size_t npassFDs = 0;
     virLXCControllerPtr ctrl = NULL;
     size_t i;
     const char *securityDriver = "none";
@@ -1835,7 +1850,7 @@ int main(int argc, char *argv[])
     while (1) {
         int c;
 
-        c = getopt_long(argc, argv, "dn:v:m:c:s:h:S:",
+        c = getopt_long(argc, argv, "dn:v:p:m:c:s:h:S:",
                        options, NULL);
 
         if (c == -1)
@@ -1867,6 +1882,15 @@ int main(int argc, char *argv[])
             }
             break;
 
+        case 'p':
+            if (VIR_REALLOC_N(passFDs, npassFDs + 1) < 0)
+                goto cleanup;
+            if (virStrToLong_i(optarg, NULL, 10, &passFDs[npassFDs++]) < 0) {
+                fprintf(stderr, "malformed --passfd argument '%s'", optarg);
+                goto cleanup;
+            }
+            break;
+
         case 's':
             if (virStrToLong_i(optarg, NULL, 10, &handshakeFd) < 0) {
                 fprintf(stderr, "malformed --handshakefd argument '%s'",
@@ -1939,6 +1963,9 @@ int main(int argc, char *argv[])
     ctrl->veths = veths;
     ctrl->nveths = nveths;
 
+    ctrl->passFDs = passFDs;
+    ctrl->npassFDs = npassFDs;
+
     for (i = 0; i < nttyFDs; i++) {
         if (virLXCControllerAddConsole(ctrl, ttyFDs[i]) < 0)
             goto cleanup;
@@ -2004,6 +2031,9 @@ cleanup:
     for (i = 0; i < nttyFDs; i++)
         VIR_FORCE_CLOSE(ttyFDs[i]);
     VIR_FREE(ttyFDs);
+    for (i = 0; i < npassFDs; i++)
+        VIR_FORCE_CLOSE(passFDs[i]);
+    VIR_FREE(passFDs);
 
     virLXCControllerFree(ctrl);
 
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 1279edf..6d71f6a 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -1021,7 +1021,10 @@ cleanup:
  *
  * Returns 0 on success or -1 in case of error
  */
-static int lxcDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
+static int lxcDomainCreateWithFiles(virDomainPtr dom,
+                                    unsigned int nfiles,
+                                    int *files,
+                                    unsigned int flags)
 {
     virLXCDriverPtr driver = dom->conn->privateData;
     virDomainObjPtr vm;
@@ -1040,7 +1043,7 @@ static int lxcDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
         goto cleanup;
     }
 
-    if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
+    if (virDomainCreateWithFilesEnsureACL(dom->conn, vm->def) < 0)
         goto cleanup;
 
     if ((vm->def->nets != NULL) && !(driver->have_netns)) {
@@ -1056,6 +1059,7 @@ static int lxcDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
     }
 
     ret = virLXCProcessStart(dom->conn, driver, vm,
+                             nfiles, files,
                              (flags & VIR_DOMAIN_START_AUTODESTROY),
                              VIR_DOMAIN_RUNNING_BOOTED);
 
@@ -1087,7 +1091,21 @@ cleanup:
  */
 static int lxcDomainCreate(virDomainPtr dom)
 {
-    return lxcDomainCreateWithFlags(dom, 0);
+    return lxcDomainCreateWithFiles(dom, 0, NULL, 0);
+}
+
+/**
+ * lxcDomainCreateWithFlags:
+ * @dom: domain to start
+ *
+ * Looks up domain and starts it.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcDomainCreateWithFlags(virDomainPtr dom,
+                                    unsigned int flags)
+{
+    return lxcDomainCreateWithFiles(dom, 0, NULL, flags);
 }
 
 /**
@@ -1101,9 +1119,11 @@ static int lxcDomainCreate(virDomainPtr dom)
  * Returns 0 on success or -1 in case of error
  */
 static virDomainPtr
-lxcDomainCreateXML(virConnectPtr conn,
-                   const char *xml,
-                   unsigned int flags) {
+lxcDomainCreateXMLWithFiles(virConnectPtr conn,
+                            const char *xml,
+                            unsigned int nfiles,
+                            int *files,
+                            unsigned int flags) {
     virLXCDriverPtr driver = conn->privateData;
     virDomainObjPtr vm = NULL;
     virDomainDefPtr def;
@@ -1118,7 +1138,7 @@ lxcDomainCreateXML(virConnectPtr conn,
                                         VIR_DOMAIN_XML_INACTIVE)))
         goto cleanup;
 
-    if (virDomainCreateXMLEnsureACL(conn, def) < 0)
+    if (virDomainCreateXMLWithFilesEnsureACL(conn, def) < 0)
         goto cleanup;
 
     if (virSecurityManagerVerify(driver->securityManager, def) < 0)
@@ -1139,6 +1159,7 @@ lxcDomainCreateXML(virConnectPtr conn,
     def = NULL;
 
     if (virLXCProcessStart(conn, driver, vm,
+                           nfiles, files,
                            (flags & VIR_DOMAIN_START_AUTODESTROY),
                            VIR_DOMAIN_RUNNING_BOOTED) < 0) {
         virDomainAuditStart(vm, "booted", false);
@@ -1167,6 +1188,14 @@ cleanup:
 }
 
 
+static virDomainPtr
+lxcDomainCreateXML(virConnectPtr conn,
+                   const char *xml,
+                   unsigned int flags) {
+    return lxcDomainCreateXMLWithFiles(conn, xml, 0, NULL,  flags);
+}
+
+
 static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
 {
     virLXCDriverPtr driver = dom->conn->privateData;
@@ -4836,6 +4865,7 @@ static virDriver lxcDriver = {
     .connectNumOfDomains = lxcConnectNumOfDomains, /* 0.4.2 */
     .connectListAllDomains = lxcConnectListAllDomains, /* 0.9.13 */
     .domainCreateXML = lxcDomainCreateXML, /* 0.4.4 */
+    .domainCreateXMLWithFiles = lxcDomainCreateXMLWithFiles, /* 1.1.1 */
     .domainLookupByID = lxcDomainLookupByID, /* 0.4.2 */
     .domainLookupByUUID = lxcDomainLookupByUUID, /* 0.4.2 */
     .domainLookupByName = lxcDomainLookupByName, /* 0.4.2 */
@@ -4860,6 +4890,7 @@ static virDriver lxcDriver = {
     .connectNumOfDefinedDomains = lxcConnectNumOfDefinedDomains, /* 0.4.2 */
     .domainCreate = lxcDomainCreate, /* 0.4.4 */
     .domainCreateWithFlags = lxcDomainCreateWithFlags, /* 0.8.2 */
+    .domainCreateWithFiles = lxcDomainCreateWithFiles, /* 1.1.1 */
     .domainDefineXML = lxcDomainDefineXML, /* 0.4.2 */
     .domainUndefine = lxcDomainUndefine, /* 0.4.2 */
     .domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index 396e0eb..dd908b8 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -192,7 +192,8 @@ virLXCProcessReboot(virLXCDriverPtr driver,
     vm->newDef = NULL;
     virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
     vm->newDef = savedDef;
-    if (virLXCProcessStart(conn, driver, vm, autodestroy, reason) < 0) {
+    if (virLXCProcessStart(conn, driver, vm,
+                           0, NULL, autodestroy, reason) < 0) {
         VIR_WARN("Unable to handle reboot of vm %s",
                  vm->def->name);
         goto cleanup;
@@ -803,6 +804,8 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver,
                                 char **veths,
                                 int *ttyFDs,
                                 size_t nttyFDs,
+                                int *files,
+                                size_t nfiles,
                                 int handshakefd)
 {
     size_t i;
@@ -853,6 +856,12 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver,
         virCommandPreserveFD(cmd, ttyFDs[i]);
     }
 
+    for (i = 0; i < nfiles; i++) {
+        virCommandAddArg(cmd, "--passfd");
+        virCommandAddArgFormat(cmd, "%d", files[i]);
+        virCommandPreserveFD(cmd, files[i], 0);
+    }
+
     virCommandAddArgPair(cmd, "--security",
                          virSecurityManagerGetModel(driver->securityManager));
 
@@ -1024,6 +1033,7 @@ error:
 int virLXCProcessStart(virConnectPtr conn,
                        virLXCDriverPtr  driver,
                        virDomainObjPtr vm,
+                       unsigned int nfiles, int *files,
                        bool autoDestroy,
                        virDomainRunningReason reason)
 {
@@ -1189,6 +1199,7 @@ int virLXCProcessStart(virConnectPtr conn,
                                                 vm,
                                                 nveths, veths,
                                                 ttyFDs, nttyFDs,
+                                                files, nfiles,
                                                 handshakefds[1])))
         goto cleanup;
     virCommandSetOutputFD(cmd, &logfd);
@@ -1382,7 +1393,8 @@ virLXCProcessAutostartDomain(virDomainObjPtr vm,
     virObjectLock(vm);
     if (vm->autostart &&
         !virDomainObjIsActive(vm)) {
-        ret = virLXCProcessStart(data->conn, data->driver, vm, false,
+        ret = virLXCProcessStart(data->conn, data->driver, vm,
+                                 0, NULL, false,
                                  VIR_DOMAIN_RUNNING_BOOTED);
         virDomainAuditStart(vm, "booted", ret >= 0);
         if (ret < 0) {
diff --git a/src/lxc/lxc_process.h b/src/lxc/lxc_process.h
index 779cc5f..9eb06f5 100644
--- a/src/lxc/lxc_process.h
+++ b/src/lxc/lxc_process.h
@@ -27,6 +27,7 @@
 int virLXCProcessStart(virConnectPtr conn,
                        virLXCDriverPtr  driver,
                        virDomainObjPtr vm,
+                       unsigned int nfiles, int *files,
                        bool autoDestroy,
                        virDomainRunningReason reason);
 int virLXCProcessStop(virLXCDriverPtr driver,
-- 
1.8.1.4




More information about the libvir-list mailing list