[lxc-devel] [RFC PATCH 1/1] Handle running on unified hierarchy
Stéphane Graber
stgraber at ubuntu.com
Tue Jun 30 19:23:07 UTC 2015
On Tue, Jun 16, 2015 at 02:34:57PM +0000, Serge Hallyn wrote:
> The unified hierachy has some very different behavior from legacy hierachies.
> Perhaps most intrusively, tasks may only exist in leaf nodes. To deal with
> this, any Create request will create a cgroup with all controllers enabled
> that were enabled in the parent, while MovePid will move a process into a
> child of the requested cgroup with no enabled controllers, called ".cgm_leaf".
>
> We declare the current cgmanager API to be a legacy API which may sit on
> top of either the legacy of unified hierarchy. A new v2 API, designed around
> the unified hierarchy, will be introduced alongside the legacy API later.
>
> If unified hierarchy is mounted, recognize it as such. We also in that case pin
> the controllers into the unified hierarchy (in a .cgpin directory), as we don't
> want the mechanism for dealing with the controller to change mid-way.
>
> When calculating or showing a task's cgroup, drop the ".cgm_leaf" part.
>
> create: copy the parent's list of active controllers into the newly
> created one. Otherwise the controllers cannot be used.
>
> update movepid to handle unified hierarchy. this involves:
> creating the leafdir if it doesn't already exists
> chowning the leafdir contents to match the parent dir contents
> (don't enable any controllers in the leafdir)
>
> ignore error chowning tasks file, since it won't exist in unified hierarchy
>
> chown: also chown leaf dir if it exists
>
> handle leafdir in remove
>
> use NIH_MUST to avoid some null checks
>
> set_value: set cgm_leaf value as well as parent's
>
> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
Seems like a few debug statements have stuck around and show be dropped
or reworked.
> ---
> cgmanager.c | 54 ++++++-
> fs.c | 489 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
> fs.h | 11 +-
> 3 files changed, 518 insertions(+), 36 deletions(-)
>
> diff --git a/cgmanager.c b/cgmanager.c
> index 6219cba..ead4284 100644
> --- a/cgmanager.c
> +++ b/cgmanager.c
> @@ -132,8 +132,13 @@ int per_ctrl_move_pid_main(const char *controller, const char *cgroup, struct uc
> struct ucred r, struct ucred v, bool escape)
> {
> char rcgpath[MAXPATHLEN], path[MAXPATHLEN];
> + bool unified = false;
> FILE *f;
> pid_t query = r.pid;
> + size_t maxlen;
> +
> + if (is_unified_controller(controller))
> + unified = true;
>
> // Get r's current cgroup in rcgpath
> if (escape)
> @@ -150,8 +155,14 @@ int per_ctrl_move_pid_main(const char *controller, const char *cgroup, struct uc
> return -1;
> }
>
> - /* rcgpath + / + cgroup + /tasks + \0 */
> - if (strlen(rcgpath) + strlen(cgroup) > MAXPATHLEN - 8) {
> + if (unified) {
> + /* rcgpath + / + cgroup + "/.cgm_leaf/cgroup.procs" + \0 */
> + maxlen = strlen(rcgpath) + strlen(cgroup) + strlen(U_LEAF "/cgroup.procs") + 2;
> + } else {
> + /* rcgpath + / + cgroup + /tasks + \0 */
> + maxlen = strlen(rcgpath) + strlen(cgroup) + 8;
> + }
> + if (maxlen > MAXPATHLEN) {
> nih_error("%s: Path name too long", __func__);
> return -1;
> }
> @@ -168,8 +179,17 @@ int per_ctrl_move_pid_main(const char *controller, const char *cgroup, struct uc
> r.pid, r.uid, r.gid, path);
> return -1;
> }
> +
> // is r allowed to write to tasks file?
> - strncat(path, "/tasks", MAXPATHLEN-1);
> + if (unified) {
> + if (!ensure_leafdir(controller, path))
> + return -1;
> + strcat(path, U_LEAF);
> + strcat(path, "/cgroup.procs");
> + } else {
> + strncat(path, "/tasks", MAXPATHLEN-1);
> + }
> +
> if (!may_access(r.pid, r.uid, r.gid, path, O_WRONLY)) {
> nih_error("%s: pid %d (uid %u gid %u) may not write to %s", __func__,
> r.pid, r.uid, r.gid, path);
> @@ -266,6 +286,7 @@ int do_create_main(const char *controller, const char *cgroup, struct ucred p,
> size_t cgroup_len;
> char *p1, *p2, oldp2;
>
> +nih_info("%s: controller is %s\n", __func__, controller);
Odd indent ^
> *existed = 1;
> // Get r's current cgroup in rcgpath
> if (!compute_proxy_cgroup(r.pid, controller, "", rcgpath, &depth)) {
> @@ -324,6 +345,12 @@ int do_create_main(const char *controller, const char *cgroup, struct ucred p,
> nih_error("%s: failed to create %s", __func__, path);
> return -2;
> }
> + if (!unified_copy_controllers(controller, path)) {
> + nih_error("%s: Failed to set cg controllers on %s", __func__,
> + path);
> + rmdir(path);
> + return -1;
> + }
> if (!chown_cgroup_path(path, r.uid, r.gid, true)) {
> nih_error("%s: Failed to change ownership on %s to %u:%u", __func__,
> path, r.uid, r.gid);
> @@ -367,10 +394,13 @@ int create_main(const char *controller, const char *cgroup, struct ucred p,
> if (strcmp(controller, "all") == 0) {
> if (!all_controllers)
> return 0;
> +nih_info("%s: all_controllers is %s\n", __func__, all_controllers);
Again ^
> c = NIH_MUST( nih_strdup(NULL, all_controllers) );
> } else {
> c = NIH_MUST( nih_strdup(NULL, controller) );
> +nih_info("c is %s before prune", c);
And again ^
> do_prune_comounts(c);
> +nih_info("c is %s after prune", c);
And again ^
> }
> tok = strtok(c, ",");
> while (tok) {
> @@ -430,6 +460,14 @@ int do_chown_main(const char *controller, const char *cgroup, struct ucred p,
> path, v.uid, v.gid);
> return -2;
> }
> + if (is_unified_controller(controller)) {
> + NIH_MUST( nih_strcat(&path, NULL, U_LEAF) );
> + if (dir_exists(path) && !chown_cgroup_path(path, v.uid, v.gid, false)) {
> + nih_warn("%s: Failed to chown leaf directory for %s to %u:%u",
> + __func__, path, v.uid, v.gid);
> + return -2;
> + }
> + }
>
> return 0;
> }
> @@ -678,7 +716,7 @@ int set_value_main(char *controller, const char *cgroup,
> }
>
> /* read and return the value */
> - if (!set_value(path, value)) {
> + if (!set_value(controller, path, value)) {
> nih_error("%s: Failed to set value %s to %s", __func__, path, value);
> return -1;
> }
> @@ -801,6 +839,14 @@ int do_remove_main(const char *controller, const char *cgroup, struct ucred p,
> return -2;
> }
>
> + if (is_unified_controller(controller)) {
> + nih_local char *fpath = NULL;
> + fpath = NIH_MUST( nih_sprintf(NULL, "%s%s", working, U_LEAF) );
> + if (rmdir(fpath) < 0) {
> + nih_error("%s: Failed to remove %s: %s", __func__, fpath, strerror(errno));
> + return errno == EPERM ? -2 : -1;
> + }
> + }
> if (!recursive) {
> if (rmdir(working) < 0) {
> nih_error("%s: Failed to remove %s: %s", __func__, working, strerror(errno));
> diff --git a/fs.c b/fs.c
> index 231e98e..ddfc48f 100644
> --- a/fs.c
> +++ b/fs.c
> @@ -51,6 +51,7 @@
> #include <nih-dbus/dbus_proxy.h>
>
> #include "frontend.h" // for keys_return_type
> +#include "fs.h" // for #defines
>
> /* defines relating to the release agent */
> #define AGENT SBINDIR "/cgm-release-agent"
> @@ -83,6 +84,7 @@ struct controller_mounts {
> bool premounted;
> bool visited;
> bool skip;
> + bool unified;
> };
>
> static struct controller_mounts *all_mounts;
> @@ -246,19 +248,10 @@ static bool fill_in_controller(struct controller_mounts *m, char *controller,
> nih_local char *dest = NULL;
>
> dest = NIH_MUST( nih_sprintf(NULL, "%s/%s", base_path, src) );
> - m->controller = strdup(controller);
> - if (!m->controller) {
> - nih_fatal("Out of memory mounting controllers");
> - return false;
> - }
> + m->controller = NIH_MUST( strdup(controller) );
> m->options = NULL;
> - m->path = strdup(dest);
> - m->src = strdup(src);
> - if (!m->path ||
> - !m->src) {
> - nih_fatal("Out of memory mounting controllers");
> - return false;
> - }
> + m->path = NIH_MUST( strdup(dest) );
> + m->src = NIH_MUST( strdup(src) );
> nih_info(_("Arranged to mount %s onto %s"), m->controller, m->path);
> return true;
> }
> @@ -295,7 +288,6 @@ static bool save_mount_subsys(char *s)
> insert_pt = find_controller_in_mounts(controller, &found);
> if (found)
> return true;
> -
> tmp = realloc(all_mounts, (num_controllers+1) * sizeof(*all_mounts));
> if (!tmp) {
> nih_fatal("Out of memory mounting controllers");
> @@ -366,6 +358,16 @@ static bool do_mount_subsys(int i)
> nih_fatal("Failed to create %s: %s", dest, strerror(errno));
> return false;
> }
> +
> + if (m->unified) {
> + if (mount(m->controller, dest, "cgroup", 0, "__DEVEL__sane_behavior") < 0) {
> + nih_error("Failed mounting %s: %s\n", m->controller,
> + strerror(errno));
> + return false;
> + }
> + return true;
> + }
> +
> if (m->premounted)
> ret = mount(src, dest, "cgroup", 0, m->options);
> else
> @@ -426,8 +428,11 @@ static bool process_mounted_subsystem(char *options)
> while (tok) {
> if (strncmp(tok, "name=", 5) == 0) {
> i = find_controller_in_mounts(tok+5, &found);
> - if (found) // jinkeys, multiple mounts already
> + if (found) {
> + if (all_mounts[i].unified)
> + return true;
> goto next;
> + }
> if (!save_mount_subsys(tok))
> return false;
> i = find_controller_in_mounts(tok+5, &found);
> @@ -440,8 +445,11 @@ static bool process_mounted_subsystem(char *options)
> NIH_MUST( nih_strcat_sprintf(&cp_opts, NULL, ",%s", tok) );
> } else if (is_kernel_controller(tok)) {
> i = find_controller_in_mounts(tok, &found);
> - if (found) // jinkeys, multiple mounts already
> + if (found) {
> + if (all_mounts[i].unified)
> + return true;
> goto next;
> + }
> if (!save_mount_subsys(tok))
> return false;
> i = find_controller_in_mounts(tok, &found);
> @@ -532,6 +540,8 @@ static bool collate_premounted_subsystems(void)
> first = &all_mounts[i];
> if (!first->premounted)
> continue;
> + if (first->unified)
> + continue;
> if (first->comounted) // already linked
> continue;
> if (!first->options)
> @@ -700,6 +710,7 @@ static void print_debug_controller_info(void)
> nih_debug(" premounted: %s comounted: %s",
> m->premounted ? "yes" : "no",
> m->comounted ? m->comounted->controller : "(none)");
> + nih_debug(" unified: %s", m->unified ? "yes" : "no");
> }
> }
>
> @@ -710,7 +721,7 @@ void do_list_controllers(void *parent, char ***output)
> nih_assert(output);
> *output = NIH_MUST( nih_alloc(parent, (num_controller_mnts+1) * sizeof(char *)) );
> (*output)[num_controller_mnts] = NULL;
> -
> +
> /* XXX
> * This will actually not be right.
> * if we have freezer,devices co-mounted, we'll have two separate
> @@ -818,9 +829,257 @@ static void build_all_controllers(char *skip_mounts)
> do_prune_comounts(all_controllers);
> }
>
> +/*
> + * Check whether the unified hierarchy is available
> + */
> +static bool unified_hierarchy_present(void)
> +{
> + FILE *f;
> + char *line = NULL;
> + size_t len = 0;
> + bool ret = false;
> +
> + if ((f = fopen("/proc/self/cgroup", "r")) == NULL)
> + return false;
> +
> + while (getline(&line, &len, f) != -1) {
> + if (strncmp(line, "0:", 2) == 0) {
> + ret = true;
> + break;
> + }
> + }
> +
> + fclose(f);
> + free(line);
> + return ret;
> +}
> +
> +/*
> + * Mount a transient instance of the unified hierarchy, so that
> + * we can pin the controllers currently enabled there
> + */
> +static bool mount_transient_unified(void)
> +{
> + if (mkdir(UNIFIED_DIR, 0755) < 0 && errno != EEXIST)
> + return false;
> + if (mount("cgroup", UNIFIED_DIR, "cgroup", 0, "__DEVEL__sane_behavior") < 0) {
> + nih_error("Error mounting unified: %s\n", strerror(errno));
> + return false;
> + }
> + return true;
> +}
> +
> +static void mark_unified_controllers_comounted(void)
> +{
> + int i;
> + struct controller_mounts *first = NULL, *last = NULL;
> +
> + for (i = 0; i < num_controllers; i++) {
> + if (!all_mounts[i].unified)
> + continue;
> + if (!first) {
> + first = last = &all_mounts[i];
> + continue;
> + }
> + last->comounted = &all_mounts[i];
> + last = &all_mounts[i];
> + }
> + if (last && last != first)
> + last->comounted = first;
> +}
> +
> +static bool record_unified_controllers(char *ctrl_list)
> +{
> + struct controller_mounts *tmp;
> + int i, insert_pt;
> + bool found;
> + char *tok;
> +
> + tok = strtok(ctrl_list, " ");
> + while (tok) {
> + insert_pt = find_controller_in_mounts(tok, &found);
> + if (found) {
> + /*
> + * Something in the program flow is not right.
> + * We must not know what's actually going on.
> + */
> + nih_error("Impossible: found duplicate in unified (%s)", tok);
> + return false;
> + }
> +
> + tmp = realloc(all_mounts, (num_controllers+1) * sizeof(*all_mounts));
> + if (!tmp) {
> + nih_fatal("Out of memory mounting controllers");
> + return false;
> + }
> + all_mounts = tmp;
> +
> + for (i = num_controllers; i > insert_pt; i--)
> + all_mounts[i] = all_mounts[i-1];
> + zero_out(&all_mounts[insert_pt]);
> +
> + if (!fill_in_controller(&all_mounts[insert_pt], tok, tok))
> + return false;
> + all_mounts[insert_pt].unified = true;
> + num_controllers++;
> + tok = strtok(NULL, " ");
> + }
> +
> + return true;
> +}
> +
> +static inline void drop_newlines(char *s)
> +{
> + int l;
> +
> + for (l=strlen(s); l>0 && s[l-1] == '\n'; l--)
> + s[l-1] = '\0';
> +}
> +
> +static char *read_oneline(const char *from)
> +{
> + char *line = NULL;
> + FILE *f = fopen(from, "r");
> + size_t len = 0;
> + if (!f)
> + return NULL;
> + if (getline(&line, &len, f) == -1) {
> + fclose(f);
> + return NULL;
> + }
> + fclose(f);
> +
> + drop_newlines(line);
> + return line;
> +}
> +
> +static bool write_string(const char *fnam, char *string)
> +{
> + FILE *f;
> + size_t len, ret;
> +
> + if (!(f = fopen(fnam, "w")))
> + return false;
> + len = strlen(string);
> + ret = fwrite(string, 1, len, f);
> + if (ret != len) {
> + nih_error("Error writing to file: %s", strerror(errno));
> + fclose(f);
> + return false;
> + }
> + if (fclose(f) < 0) {
> + nih_error("Error writing to file: %s", strerror(errno));
> + return false;
> + }
> + return true;
> +}
> +
> +static bool pin_and_process_unified(void)
> +{
> + nih_local char *ctrlcopy = NULL,
> + *ctrlline = NULL;
> + char path[MAXPATHLEN];
> + char *line = NULL, *tok;
> + FILE *f;
> +
> + if (mkdir(UNIFIED_PIN, 0755) < 0 && errno != EEXIST)
> + return false;
> +
> + sprintf(path, "%s/cgroup.controllers", UNIFIED_DIR);
> + line = read_oneline(path);
> + if (!line || strlen(line) == 0) {
> + free(line);
> + return true;
> + }
> +
> + ctrlcopy = NIH_MUST( nih_strdup(NULL, line) );
> + tok = strtok(line, " ");
> + while (tok) {
> + NIH_MUST( nih_strcat_sprintf(&ctrlline, NULL, "+%s ", tok) );
> + tok = strtok(NULL, " ");
> + }
> + free(line);
> +
> + sprintf(path, "%s/cgroup.subtree_control", UNIFIED_DIR);
> + if (!write_string(path, ctrlline)) {
> + nih_error("Error pinning unified controllers");
> + return false;
> + }
> +
> + sprintf(path, "%s/cgroup.subtree_control", UNIFIED_PIN);
> + if (!write_string(path, ctrlline)) {
> + nih_error("Error pinning unified controllers");
> + return false;
> + }
> +
> + sprintf(path, "%s/cgroup.procs", UNIFIED_DIR);
> + if (!(f = fopen(path, "w")))
> + return true;
> + fprintf(f, "%d", (int)getpid());
> + fclose(f);
> +
> + nih_debug("pinned the following controllers unified: %s\n", ctrlline);
> +
> + return record_unified_controllers(ctrlcopy);
> +}
> +
> +static bool do_mount_unified(void)
> +{
> + int i;
> + bool found = false;
> + nih_local char *dest = NULL;
> +
> + for (i = 0; i < num_controllers; i++) {
> + if (all_mounts[i].unified) {
> + found = true;
> + break;
> + }
> + }
> + if (!found)
> + return true;
> +
> + dest = NIH_MUST( nih_sprintf(NULL, "%s/%s", base_path, ".cgm_unified") );
> + if (mkdir(dest, 0755) < 0 && errno != EEXIST) {
> + nih_fatal("Failed to create %s: %s", dest, strerror(errno));
> + return false;
> + }
> +
> + if (mount("unified", dest, "cgroup", 0, "__DEVEL__sane_behavior") < 0) {
> + nih_fatal("Failed to mount unified hierarchy: %s\n", strerror(errno));
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static void umount_transient_unified(void)
> +{
> + umount(UNIFIED_DIR);
> + rmdir(UNIFIED_DIR);
> +}
> +
> +static bool process_unified_hierarchy(void)
> +{
> + bool ret = false;
> +
> + if (!unified_hierarchy_present())
> + return true;
> + if (!mount_transient_unified())
> + return false;
> + if (pin_and_process_unified())
> + ret = true;
> +
> + umount_transient_unified();
> + return ret;
> +}
> +
> int collect_subsystems(char *extra_mounts, char *skip_mounts)
> {
> - /* first collect all already-mounted subsystems */
> + /* first mount and pin anything currently in the unified hierarchy */
> + if (!process_unified_hierarchy())
> + return -1;
> +
> + /* next collect all already-mounted subsystems */
> if (!collect_premounted_subsystems())
> return -1;
>
> @@ -841,6 +1100,7 @@ int collect_subsystems(char *extra_mounts, char *skip_mounts)
> if (!collate_premounted_subsystems())
> return -1;
>
> + mark_unified_controllers_comounted();
> build_all_controllers(skip_mounts);
>
> build_controller_mntlist();
> @@ -985,6 +1245,9 @@ int setup_cgroup_mounts(void)
> return -1;
> }
>
> + if (!do_mount_unified())
> + return -1;
> +
> for (i=0; i<num_controllers; i++) {
> if (!do_mount_subsys(i)) {
> nih_fatal("Failed mounting cgroups");
> @@ -1063,14 +1326,6 @@ bool create_agent_symlinks(void)
> return true;
> }
>
> -static inline void drop_newlines(char *s)
> -{
> - int l;
> -
> - for (l=strlen(s); l>0 && s[l-1] == '\n'; l--)
> - s[l-1] = '\0';
> -}
> -
> /*
> * The user will pass in 'cpuset' or 'systemd'. /proc/self/cgroup will
> * show 'cpuset:' or 'name=systemd:'. We have to account for that.
> @@ -1087,6 +1342,26 @@ static bool is_same_controller(const char *cmp, const char *cnt)
> }
>
> /*
> + * In unified hierarchy tasks must be in a leaf node. Cgmanager
> + * creates .cgm_leaf for tasks. Ignore that.
> + */
> +static void chop_leaf(char *path)
> +{
> + size_t len;
> + char *cmp;
> +
> + if (!path)
> + return;
> +
> + len = strlen(path);
> + if (len < strlen(U_LEAF))
> + return;
> + cmp = path + len - strlen(U_LEAF_NAME);
> + if (strcmp(cmp, U_LEAF_NAME) == 0)
> + *cmp = '\0';
> +}
> +
> +/*
> * pid_cgroup: return the cgroup of @pid for @controller.
> * retv must be a (at least) MAXPATHLEN size buffer into
> * which the answer will be copied.
> @@ -1127,6 +1402,8 @@ static inline char *pid_cgroup(pid_t pid, const char *controller, char *retv)
> found:
> fclose(f);
> free(line);
> + if (is_unified_controller(controller))
> + chop_leaf(cgroup);
> return cgroup;
> }
>
> @@ -1277,6 +1554,16 @@ const char *get_controller_path(const char *controller)
> return all_mounts[i].path;
> }
>
> +bool is_unified_controller(const char *controller)
> +{
> + int i;
> + for (i = 0; i < num_controllers; i++)
> + if (strcmp(all_mounts[i].controller, controller) == 0 &&
> + all_mounts[i].unified)
> + return true;
> + return false;
> +}
> +
> int get_path_depth(const char *p)
> {
> int depth = 0;
> @@ -1635,12 +1922,12 @@ bool chown_cgroup_path(const char *path, uid_t uid, gid_t gid, bool all_children
> nih_local char *fpath = NULL;
> fpath = NIH_MUST( nih_sprintf(NULL, "%s/cgroup.procs", path) );
> if (chown(fpath, uid, gid) < 0)
> - nih_error("Failed to chown procs file %s: %s", fpath,
> - strerror(errno));
> + nih_error("%s: Failed to chown procs file %s: %s", __func__,
> + fpath, strerror(errno));
> sprintf(fpath+len, "/tasks");
> if (chown(fpath, uid, gid) < 0)
> - nih_error("Failed to chown tasks file %s: %s", fpath,
> - strerror(errno));
> + nih_warn("%s: Failed to chown the tasks file %s: %s\n",
> + __func__, fpath, strerror(errno));
> }
>
> out:
> @@ -1706,9 +1993,11 @@ bool set_value_trusted(const char *path, const char *value)
> }
> return true;
> }
> -bool set_value(const char *path, const char *value)
> +bool set_value(const char *controller, const char *path, const char *value)
> {
> int i;
> + char *p;
> + nih_local char *upath = NULL, *file = NULL;
>
> nih_assert (path);
>
> @@ -1724,7 +2013,24 @@ bool set_value(const char *path, const char *value)
> }
> }
>
> - return set_value_trusted(path, value);
> + if (!set_value_trusted(path, value))
> + return false;
> +
> + if (!is_unified_controller(controller))
> + return true;
> + upath = NIH_MUST( nih_strdup(NULL, path) );
> + p = strrchr(upath, '/');
> + if (!p)
> + return false; // can't happen
> + file = NIH_MUST( nih_strdup(NULL, p+1) );
> + *p = '\0';
> + NIH_MUST( nih_strcat(&upath, NULL, U_LEAF) );
> + if (!dir_exists(upath))
> + return true;
> + NIH_MUST( nih_strcat(&upath, NULL, "/") );
> + NIH_MUST( nih_strcat(&upath, NULL, file) );
> +
> + return (set_value_trusted(upath, value));
> }
>
> /*
> @@ -1798,6 +2104,8 @@ bool move_self_to_root(void)
> continue;
> if (all_mounts[i].skip)
> continue;
> + if (all_mounts[i].unified)
> + continue;
> path = NIH_MUST( nih_sprintf(NULL, "%s/tasks", all_mounts[i].path) );
> if ((f = fopen(path, "w")) == NULL)
> return false;
> @@ -1843,6 +2151,8 @@ int get_directory_children(void *parent, const char *path, char ***output)
> while (readdir_r(d, &dirent, &direntp) == 0 && direntp) {
> if (!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, ".."))
> continue;
> + if (!strcmp(direntp->d_name, U_LEAF_NAME))
> + continue;
> if (direntp->d_type != DT_DIR)
> continue;
> if (used+1 >= alloced) {
> @@ -1980,3 +2290,120 @@ bool path_is_under_taskcg(pid_t pid, const char *contr,const char *path)
> return true;
> return false;
> }
> +
> +static bool do_copy_controllers(const char *from, const char *to)
> +{
> + nih_local char *src = NULL,
> + *dest = NULL,
> + *ctrlline = NULL;
> + char *line = NULL, *tok, *savetok;
> + src = NIH_MUST( nih_sprintf(NULL, "%s/cgroup.subtree_control", from) );
> + dest = NIH_MUST( nih_sprintf(NULL, "%s/cgroup.subtree_control", to) );
> + line = read_oneline(src);
> + if (!line)
> + return true;
> +
> + tok = strtok_r(line, " ", &savetok);
> + while (tok) {
> + NIH_MUST( nih_strcat_sprintf(&ctrlline, NULL, "+%s ", tok) );
> + tok = strtok_r(NULL, " ", &savetok);
> + }
> + free(line);
> + return write_string(dest, ctrlline);
> +}
> +
> +bool unified_copy_controllers(const char *controller, const char *path)
> +{
> + nih_local char *p = NULL;
> + char *pe;
> +
> + if (!is_unified_controller(controller))
> + return true;
> +
> + p = NIH_MUST( nih_strdup(NULL, path) );
> + pe = strrchr(p, '/');
> + if (pe)
> + *pe = '\0';
> + return do_copy_controllers(p, path);
> +}
> +
> +bool create_leaf(const char *controller, const char *path, uid_t u, gid_t g)
> +{
> + nih_local char *p = NULL;
> +
> + if (!is_unified_controller(controller))
> + return true;
> +
> + NIH_MUST( nih_strcat_sprintf(&p, NULL, "%s%s", path, U_LEAF) );
> + if (mkdir(p, 755) < 0 && errno != EEXIST)
> + return false;
> + if (mkdir(p, 755) < 0 && errno == EEXIST)
> + return true;
> + if (chown(p, u, g) < 0)
> + return false;
> + return true;
> +}
> +
> +static bool copy_owner_perms_from_to(const char *from, const char *to)
> +{
> + struct stat sb;
> + struct dirent dirent, *direntp;
> + bool error = false;
> + DIR *d;
> +
> + if (stat(from, &sb) < 0)
> + return false;
> + if (chown(to, sb.st_uid, sb.st_gid) < 0)
> + return false;
> + if (chmod(to, sb.st_mode) < 0)
> + return false;
> +
> + d = opendir(from);
> + if (!d)
> + return false;
> +
> + while (readdir_r(d, &dirent, &direntp) == 0 && direntp) {
> + nih_local char *srcp = NULL,
> + *dstp = NULL;
> +
> + if (!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, ".."))
> + continue;
> + srcp = NIH_MUST( nih_sprintf(NULL, "%s/%s", from, direntp->d_name) );
> + dstp = NIH_MUST( nih_sprintf(NULL, "%s/%s", to, direntp->d_name) );
> + if (!file_exists(dstp))
> + continue;
> + if (stat(srcp, &sb) < 0)
> + continue;
> + if (chown(dstp, sb.st_uid, sb.st_gid) < 0) {
> + nih_error("Failed to chown file %s to %u:%u",
> + dstp, sb.st_uid, sb.st_gid);
> + error = true;
> + }
> + if (chmod(dstp, sb.st_mode) < 0) {
> + nih_error("Failed to chmod file %s to %o",
> + dstp, sb.st_mode);
> + error = true;
> + }
> + nih_debug("chowned %s to %d %d and chmoded it to %o", dstp, (int)sb.st_uid, (int)sb.st_gid, sb.st_mode);
> + }
> + closedir(d);
> +
> + return !error;
> +}
> +
> +bool ensure_leafdir(const char *controller, const char *path)
> +{
> + nih_local char *p = NIH_MUST( nih_sprintf(NULL, "%s%s", path, U_LEAF) );
> +
> + if (mkdir(p, 0755) < 0) {
> + if (errno != EEXIST)
> + return false;
> + // existed, don't change perms
> + return true;
> + }
> + if (!copy_owner_perms_from_to(path, p)) {
> + rmdir(p);
> + return false;
> + }
> + return true;
> +}
> diff --git a/fs.h b/fs.h
> index cae8213..0643aa1 100644
> --- a/fs.h
> +++ b/fs.h
> @@ -24,6 +24,11 @@
> * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> */
>
> +#define UNIFIED_DIR CGDIR "/.cgm_unified"
> +#define UNIFIED_PIN UNIFIED_DIR "/.cgpin"
> +#define U_LEAF_NAME ".cgm_leaf"
> +#define U_LEAF "/" U_LEAF_NAME
> +
> extern char *all_controllers;
> struct keys_return_type;
>
> @@ -43,7 +48,7 @@ const char *get_controller_path(const char *controller);
> bool hostuid_to_ns(uid_t uid, pid_t pid, uid_t *answer);
> bool chown_cgroup_path(const char *path, uid_t uid, gid_t gid, bool all_children);
> bool chmod_cgroup_path(const char *path, int mode);
> -bool set_value(const char *path, const char *value);
> +bool set_value(const char *controller, const char *path, const char *value);
> bool set_value_trusted(const char *path, const char *value);
> unsigned long read_pid_ns_link(int pid);
> unsigned long read_user_ns_link(int pid);
> @@ -61,3 +66,7 @@ bool prune_verify_comounts(char *controllers);
> void do_list_controllers(void *parent, char ***output);
> void convert_directory_contents(struct keys_return_type **keys, struct ucred r);
> bool path_is_under_taskcg(pid_t pid, const char *contr,const char *path);
> +bool unified_copy_controllers(const char *controller, const char *path);
> +bool is_unified_controller(const char *controller);
> +bool create_leaf(const char *controller, const char *path, uid_t u, gid_t g);
> +bool ensure_leafdir(const char *controller, const char *path);
> --
> 2.1.4
>
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel
--
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20150630/c3c93d25/attachment.sig>
More information about the lxc-devel
mailing list