#include "bdev.h"
#include "cgroup.h"
+#include "cgroup_utils.h"
#include "commands.h"
#include "log.h"
#include "utils.h"
char *mountpoint;
char *base_cgroup;
char *fullcgpath;
+ bool is_cgroup_v2;
};
/*
}
clonechildrenpath = must_make_path(cgpath, "cgroup.clone_children", NULL);
- if (!file_exists(clonechildrenpath)) { /* unified hierarchy doesn't have clone_children */
+ /* unified hierarchy doesn't have clone_children */
+ if (!file_exists(clonechildrenpath)) {
free(clonechildrenpath);
free(cgpath);
return true;
*/
static char **get_controllers(char **klist, char **nlist, char *line)
{
- // the fourth field is /sys/fs/cgroup/comma-delimited-controller-list
+ /* the fourth field is /sys/fs/cgroup/comma-delimited-controller-list */
int i;
char *p = line, *p2, *tok, *saveptr = NULL;
char **aret = NULL;
+ bool is_cgroup_v2;
+
+ /* handle cgroup v2 */
+ is_cgroup_v2 = is_cgroupfs_v2(line);
for (i = 0; i < 4; i++) {
p = strchr(p, ' ');
return NULL;
}
*p2 = '\0';
+
+ /* cgroup v2 does not have separate mountpoints for controllers */
+ if (is_cgroup_v2) {
+ must_append_controller(klist, nlist, &aret, "cgroup2");
+ return aret;
+ }
+
for (tok = strtok_r(p, ",", &saveptr); tok;
tok = strtok_r(NULL, ",", &saveptr)) {
must_append_controller(klist, nlist, &aret, tok);
return aret;
}
-/* return true if the fstype is cgroup */
-static bool is_cgroupfs(char *line)
-{
- char *p = strstr(line, " - ");
- if (!p)
- return false;
- return strncmp(p, " - cgroup ", 10) == 0;
-}
-
/* Add a controller to our list of hierarchies */
static void add_controller(char **clist, char *mountpoint, char *base_cgroup)
{
new->base_cgroup = base_cgroup;
new->fullcgpath = NULL;
+ /* record if this is the cgroup v2 hierarchy */
+ if (!strcmp(base_cgroup, "cgroup2"))
+ new->is_cgroup_v2 = true;
+ else
+ new->is_cgroup_v2 = false;
+
newentry = append_null_to_list((void ***)&hierarchies);
hierarchies[newentry] = new;
}
static char *get_current_cgroup(char *basecginfo, char *controller)
{
char *p = basecginfo;
+ bool is_cgroup_v2;
+ bool is_cgroup_v2_base_cgroup;
+
+ is_cgroup_v2 = !strcmp(controller, "cgroup2");
+ while (true) {
+ is_cgroup_v2_base_cgroup = false;
+ /* cgroup v2 entry in "/proc/<pid>/cgroup": "0::/some/path" */
+ if (is_cgroup_v2 && (*p == '0'))
+ is_cgroup_v2_base_cgroup = true;
- while (1) {
p = strchr(p, ':');
if (!p)
return NULL;
p++;
- if (controller_in_clist(p, controller)) {
+ if (is_cgroup_v2_base_cgroup || controller_in_clist(p, controller)) {
p = strchr(p, ':');
if (!p)
return NULL;
}
}
-/*
- * Given a hierarchy @mountpoint and base @path, verify that we can create
- * directories underneath it.
- */
-static bool test_writeable(char *mountpoint, char *path)
-{
- char *fullpath = must_make_path(mountpoint, path, NULL);
- int ret;
-
- ret = access(fullpath, W_OK);
- free(fullpath);
- return ret == 0;
-}
-
static void must_append_string(char ***list, char *entry)
{
int newentry = append_null_to_list((void ***)list);
continue;
*p2 = '\0';
- /* If we have a mixture between cgroup v1 and cgroup v2
- * hierarchies, then /proc/self/cgroup contains entries of the
- * form:
+ /* If the kernel has cgroup v2 support, then /proc/self/cgroup
+ * contains an entry of the form:
*
* 0::/some/path
*
- * We need to skip those.
+ * In this case we use "cgroup2" as controller name.
*/
- if ((p2 - p) == 0)
+ if ((p2 - p) == 0) {
+ must_append_string(klist, "cgroup2");
continue;
+ }
for (tok = strtok_r(p, ",", &saveptr); tok;
tok = strtok_r(NULL, ",", &saveptr)) {
while (getline(&line, &len, f) != -1) {
char **controller_list = NULL;
char *mountpoint, *base_cgroup;
+ bool is_cgroup_v2, writeable;
- if (!is_lxcfs(line) && !is_cgroupfs(line))
+ is_cgroup_v2 = is_cgroupfs_v2(line);
+ if (!is_lxcfs(line) && !is_cgroupfs_v1(line) && !is_cgroup_v2)
continue;
controller_list = get_controllers(klist, nlist, line);
free(mountpoint);
continue;
}
+
trim(base_cgroup);
prune_init_scope(base_cgroup);
- if (!test_writeable(mountpoint, base_cgroup)) {
+ if (is_cgroup_v2)
+ writeable = test_writeable_v2(mountpoint, base_cgroup);
+ else
+ writeable = test_writeable_v1(mountpoint, base_cgroup);
+ if (!writeable) {
free_string_list(controller_list);
free(mountpoint);
free(base_cgroup);
--- /dev/null
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2017 Canonical Ltd.
+ *
+ * Authors:
+ * Serge Hallyn <serge.hallyn@ubuntu.com>
+ * Christian Brauner <christian.brauner@ubuntu.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "cgroup_utils.h"
+#include "utils.h"
+
+bool is_cgroupfs_v1(char *line)
+{
+ char *p = strstr(line, " - ");
+ if (!p)
+ return false;
+ return strncmp(p, " - cgroup ", 10) == 0;
+}
+
+bool is_cgroupfs_v2(char *line)
+{
+ char *p = strstr(line, " - ");
+ if (!p)
+ return false;
+
+ return strncmp(p, " - cgroup2 ", 11) == 0;
+}
+
+bool test_writeable_v1(char *mountpoint, char *path)
+{
+ char *fullpath = must_make_path(mountpoint, path, NULL);
+ int ret;
+
+ ret = access(fullpath, W_OK);
+ free(fullpath);
+ return ret == 0;
+}
+
+bool test_writeable_v2(char *mountpoint, char *path)
+{
+ /* In order to move ourselves into an appropriate sub-cgroup we need to
+ * have write access to the parent cgroup's "cgroup.procs" file, i.e. we
+ * need to have write access to the our current cgroups's "cgroup.procs"
+ * file.
+ */
+ int ret;
+ char *cgroup_path, *cgroup_procs_file;
+
+ cgroup_path = must_make_path(mountpoint, path, NULL);
+ cgroup_procs_file = must_make_path(cgroup_path, "cgroup.procs", NULL);
+
+ ret = access(cgroup_path, W_OK);
+ free(cgroup_path);
+ if (ret < 0) {
+ free(cgroup_procs_file);
+ return false;
+ }
+
+ ret = access(cgroup_procs_file, W_OK);
+ free(cgroup_procs_file);
+
+ return ret == 0;
+}
--- /dev/null
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2017 Canonical Ltd.
+ *
+ * Authors:
+ * Serge Hallyn <serge.hallyn@ubuntu.com>
+ * Christian Brauner <christian.brauner@ubuntu.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_CGROUP_UTILS_H
+#define __LXC_CGROUP_UTILS_H
+
+#include <stdbool.h>
+#include <stdio.h>
+
+/* Check if given entry from /proc/<pid>/mountinfo is a cgroupfs v1 mount. */
+extern bool is_cgroupfs_v1(char *line);
+
+/* Check if given entry from /proc/<pid>/mountinfo is a cgroupfs v2 mount. */
+extern bool is_cgroupfs_v2(char *line);
+
+/* Given a v1 hierarchy @mountpoint and base @path, verify that we can create
+ * directories underneath it.
+ */
+extern bool test_writeable_v1(char *mountpoint, char *path);
+
+/* Given a v2 hierarchy @mountpoint and base @path, verify that we can create
+ * directories underneath it and that we have write access to the cgroup's
+ * "cgroup.procs" file.
+ */
+extern bool test_writeable_v2(char *mountpoint, char *path);
+
+#endif /* __LXC_CGROUP_UTILS_H */