]> git.proxmox.com Git - mirror_lxc.git/commitdiff
lxc-attach: unify code for attaching a pid to a cgroup
authorDavid Ward <david.ward@ll.mit.edu>
Thu, 3 May 2012 22:50:15 +0000 (00:50 +0200)
committerDaniel Lezcano <daniel.lezcano@free.fr>
Thu, 3 May 2012 22:50:15 +0000 (00:50 +0200)
To attach a new pid to the cgroups for an existing container, we can use
the same method that we did when we started the container: iterate over
all the mounted cgroup hierarchies; find the cgroup that pid 1 is in for
each hierarchy; add 'lxc/<name>' to the end of it; then write the pid to
the 'tasks' file in that cgroup. (The only difference is that we do not
create the cgroup again.) Note that we follow exactly the same iteration
pattern to delete our cgroups when a container is shutdown.

There may be situations where additional cgroups hierarchies are mounted
after the container is started, or the cgroup for pid 1 gets reassigned.
But we currently don't handle any of these cases in the shutdown code or
anywhere else, so it doesn't make sense to try to handle these cases for
lxc-attach by itself. Aside from simplifying the code, this change makes
it easier to solve a different problem: ignoring hierarchies that are
not bound to any subsystems (like 'systemd').

Signed-off-by: David Ward <david.ward@ll.mit.edu>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
src/lxc/attach.c
src/lxc/attach.h
src/lxc/cgroup.c
src/lxc/cgroup.h
src/lxc/lxc_attach.c

index 0ca8b398ab2a890194b972511767487d4ed89d4a..a95b3d3cce7ab5bb282484662e9f0325ce6af030 100644 (file)
@@ -60,10 +60,9 @@ struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
        struct lxc_proc_context_info *info = calloc(1, sizeof(*info));
        FILE *proc_file;
        char proc_fn[MAXPATHLEN];
-       char *line = NULL, *ptr, *ptr2;
+       char *line = NULL;
        size_t line_bufsz = 0;
-       int ret, found, l;
-       int i;
+       int ret, found;
 
        if (!info) {
                SYSERROR("Could not allocate memory.");
@@ -114,117 +113,14 @@ struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
                goto out_error;
        }
 
-       /* read cgroups */
-       snprintf(proc_fn, MAXPATHLEN, "/proc/%d/cgroup", pid);
-
-       proc_file = fopen(proc_fn, "r");
-       if (!proc_file) {
-               SYSERROR("Could not open %s", proc_fn);
-               goto out_error;
-       }
-
-       /* we don't really know how many cgroup subsystems there are
-        * mounted, so we go through the whole file twice */
-       i = 0;
-       while (getline(&line, &line_bufsz, proc_file) != -1) {
-               /* we assume that all lines containing at least two colons
-                * are valid */
-               ptr = strchr(line, ':');
-               if (ptr && strchr(ptr + 1, ':'))
-                       i++;
-       }
-
-       rewind(proc_file);
-
-       info->cgroups = calloc(i, sizeof(*(info->cgroups)));
-       info->cgroups_count = i;
-
-       i = 0;
-       while (getline(&line, &line_bufsz, proc_file) != -1 && i < info->cgroups_count) {
-               /* format of the lines is:
-                * id:subsystems:path, where subsystems are separated by
-                * commas and each subsystem may also be of the form
-                * name=xxx if it describes a private named hierarchy
-                * we will ignore the id in the following */
-               ptr = strchr(line, ':');
-               ptr2 = ptr ? strchr(ptr + 1, ':') : NULL;
-
-               /* ignore invalid lines */
-               if (!ptr || !ptr2) continue;
-
-               l = strlen(ptr2) - 1;
-               if (ptr2[l] == '\n')
-                       ptr2[l] = '\0';
-
-               info->cgroups[i].subsystems = strndup(ptr + 1, ptr2 - (ptr + 1));
-               info->cgroups[i].cgroup = strdup(ptr2 + 1);
-
-               i++;
-       }
-
-       free(line);
-       fclose(proc_file);
-
        return info;
 
 out_error:
-       lxc_proc_free_context_info(info);
+       free(info);
        free(line);
        return NULL;
 }
 
-void lxc_proc_free_context_info(struct lxc_proc_context_info *info)
-{
-       if (!info)
-               return;
-
-       if (info->cgroups) {
-               int i;
-               for (i = 0; i < info->cgroups_count; i++) {
-                       free(info->cgroups[i].subsystems);
-                       free(info->cgroups[i].cgroup);
-               }
-       }
-       free(info->cgroups);
-       free(info);
-}
-
-int lxc_attach_proc_to_cgroups(pid_t pid, struct lxc_proc_context_info *ctx)
-{
-       int i, ret;
-
-       if (!ctx) {
-               ERROR("No valid context supplied when asked to attach "
-                     "process to cgroups.");
-               return -1;
-       }
-
-       for (i = 0; i < ctx->cgroups_count; i++) {
-               char *path;
-
-               /* the kernel should return paths that start with '/' */
-               if (ctx->cgroups[i].cgroup[0] != '/') {
-                       ERROR("For cgroup subsystem(s) %s the path '%s' does "
-                             "not start with a '/'",
-                             ctx->cgroups[i].subsystems,
-                             ctx->cgroups[i].cgroup);
-                       return -1;
-               }
-
-               /* lxc_cgroup_path_get can process multiple subsystems */
-               ret = lxc_cgroup_path_get(&path, ctx->cgroups[i].subsystems,
-                                         &ctx->cgroups[i].cgroup[1]);
-               if (ret)
-                       return -1;
-
-               ret = lxc_cgroup_attach(path, pid);
-               if (ret)
-                       return -1;
-       }
-
-       return 0;
-}
-
 int lxc_attach_to_ns(pid_t pid)
 {
        char path[MAXPATHLEN];
index d2b7533f6200f8845e029c75519f5e5cb2438015..2d46c83dcc014d786210ad6570df4a6c94a9f8a3 100644 (file)
 
 #include <sys/types.h>
 
-struct lxc_proc_cgroup_info {
-       char *subsystems;
-       char *cgroup;
-};
-
 struct lxc_proc_context_info {
        unsigned long personality;
        unsigned long long capability_mask;
-       struct lxc_proc_cgroup_info* cgroups;
-       int cgroups_count;
 };
 
 extern struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid);
-extern void lxc_proc_free_context_info(struct lxc_proc_context_info *info);
 
-extern int lxc_attach_proc_to_cgroups(pid_t pid, struct lxc_proc_context_info *ctx);
 extern int lxc_attach_to_ns(pid_t other_pid);
 extern int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx);
 
index 8d7095107ae0815e2f35ae6035b844822b894205..7d91bbc0ad8e328be6a8ae81724f0e411b99dc42 100644 (file)
@@ -53,35 +53,6 @@ enum {
        CGROUP_CLONE_CHILDREN,
 };
 
-static char *hasmntopt_multiple(struct mntent *mntent, const char *options)
-{
-       const char *ptr = options;
-       const char *ptr2 = strchr(options, ',');
-       char *result;
-
-       while (ptr2 != NULL) {
-               char *option = strndup(ptr, ptr2 - ptr);
-               if (!option) {
-                       SYSERROR("Temporary memory allocation error");
-                       return NULL;
-               }
-
-               result = hasmntopt(mntent, option);
-               free(option);
-
-               if (!result) {
-                       return NULL;
-               }
-
-               ptr = ptr2 + 1;
-               ptr2 = strchr(ptr, ',');
-       }
-
-       /* for multiple mount options, the return value is basically NULL
-        * or non-NULL, so this should suffice for our purposes */
-       return hasmntopt(mntent, ptr);
-}
-
 /*
  * get_init_cgroup: get the cgroup init is in.
  *  dsg: preallocated buffer to put the output in
@@ -168,7 +139,7 @@ static int get_cgroup_mount(const char *subsystem, char *mnt)
        while ((mntent = getmntent(file))) {
                if (strcmp(mntent->mnt_type, "cgroup"))
                        continue;
-               if (subsystem && !hasmntopt_multiple(mntent, subsystem))
+               if (subsystem && !hasmntopt(mntent, subsystem))
                        continue;
 
                flags = get_cgroup_flags(mntent);
@@ -243,13 +214,20 @@ static int cgroup_enable_clone_children(const char *path)
        return ret;
 }
 
-int lxc_cgroup_attach(const char *path, pid_t pid)
+static int lxc_one_cgroup_attach(const char *name,
+                                struct mntent *mntent, pid_t pid)
 {
        FILE *f;
-       char tasks[MAXPATHLEN];
-       int ret = 0;
+       char tasks[MAXPATHLEN], initcgroup[MAXPATHLEN];
+       char *cgmnt = mntent->mnt_dir;
+       int flags, ret = 0;
+
+       flags = get_cgroup_flags(mntent);
 
-       snprintf(tasks, MAXPATHLEN, "%s/tasks", path);
+       snprintf(tasks, MAXPATHLEN, "%s%s%s/%s/tasks", cgmnt,
+                get_init_cgroup(NULL, mntent, initcgroup),
+                (flags & CGROUP_NS_CGROUP) ? "" : "/lxc",
+                name);
 
        f = fopen(tasks, "w");
        if (!f) {
@@ -267,6 +245,44 @@ int lxc_cgroup_attach(const char *path, pid_t pid)
        return ret;
 }
 
+/*
+ * for each mounted cgroup, attach a pid to the cgroup for the container
+ */
+int lxc_cgroup_attach(const char *name, pid_t pid)
+{
+       struct mntent *mntent;
+       FILE *file = NULL;
+       int err = -1;
+       int found = 0;
+
+       file = setmntent(MTAB, "r");
+       if (!file) {
+               SYSERROR("failed to open %s", MTAB);
+               return -1;
+       }
+
+       while ((mntent = getmntent(file))) {
+               DEBUG("checking '%s' (%s)", mntent->mnt_dir, mntent->mnt_type);
+
+               if (strcmp(mntent->mnt_type, "cgroup"))
+                       continue;
+
+               INFO("[%d] found cgroup mounted at '%s',opts='%s'",
+                    ++found, mntent->mnt_dir, mntent->mnt_opts);
+
+               err = lxc_one_cgroup_attach(name, mntent, pid);
+               if (err)
+                       goto out;
+       };
+
+       if (!found)
+               ERROR("No cgroup mounted on the system");
+
+out:
+       endmntent(file);
+       return err;
+}
+
 /*
  * rename cgname, which is under cgparent, to a new name starting
  * with 'cgparent/dead'.  That way cgname can be reused.  Return
@@ -378,20 +394,13 @@ static int lxc_one_cgroup_create(const char *name,
                return -1;
        }
 
-       /* Let's add the pid to the 'tasks' file */
-       if (lxc_cgroup_attach(cgname, pid)) {
-               SYSERROR("failed to attach pid '%d' to '%s'", pid, cgname);
-               rmdir(cgname);
-               return -1;
-       }
-
        INFO("created cgroup '%s'", cgname);
 
        return 0;
 }
 
 /*
- * for each mounted cgroup, create a cgroup for the container
+ * for each mounted cgroup, create a cgroup for the container and attach a pid
  */
 int lxc_cgroup_create(const char *name, pid_t pid)
 {
@@ -418,6 +427,10 @@ int lxc_cgroup_create(const char *name, pid_t pid)
                err = lxc_one_cgroup_create(name, mntent, pid);
                if (err)
                        goto out;
+
+               err = lxc_one_cgroup_attach(name, mntent, pid);
+               if (err)
+                       goto out;
        };
 
        if (!found)
index 611d9f4a59b95b5d5d93b68bf7bcd9a34a576b00..3c90696dc16d45b98302e1c7335146a10672330e 100644 (file)
@@ -30,6 +30,6 @@ extern int lxc_cgroup_create(const char *name, pid_t pid);
 extern int lxc_cgroup_destroy(const char *name);
 extern int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name);
 extern int lxc_cgroup_nrtasks(const char *name);
-extern int lxc_cgroup_attach(const char *path, pid_t pid);
+extern int lxc_cgroup_attach(const char *name, pid_t pid);
 extern int lxc_ns_is_mounted(void);
 #endif
index 4883327bd41293e30aa027b6aed78474b0372a7f..955e9f445b359b9d94e6c9097e42dd254d4b951f 100644 (file)
@@ -35,7 +35,7 @@
 #include "commands.h"
 #include "arguments.h"
 #include "caps.h"
-#include "attach.h"
+#include "cgroup.h"
 #include "confile.h"
 #include "start.h"
 #include "sync.h"
@@ -150,7 +150,7 @@ int main(int argc, char *argv[])
                if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE))
                        return -1;
 
-               if (!elevated_privileges && lxc_attach_proc_to_cgroups(pid, init_ctx))
+               if (!elevated_privileges && lxc_cgroup_attach(my_args.name, pid))
                        return -1;
 
                /* tell the child we are done initializing */