cgroups: handle hybrid cgroup layouts

parent 04ad7ffe
......@@ -19,6 +19,7 @@ noinst_HEADERS = \
bdev/lxczfs.h \
bdev/storage_utils.h \
cgroups/cgroup.h \
cgroups/cgroup_utils.h \
caps.h \
conf.h \
confile.h \
......@@ -90,6 +91,7 @@ liblxc_la_SOURCES = \
bdev/storage_utils.c bdev/storage_utils.h \
cgroups/cgfs.c \
cgroups/cgfsng.c \
cgroups/cgroup_utils.c cgroups/cgroup_utils.h \
cgroups/cgroup.c cgroups/cgroup.h \
commands.c commands.h \
commands_utils.c commands_utils.h \
......
......@@ -49,6 +49,7 @@
#include "bdev.h"
#include "cgroup.h"
#include "cgroup_utils.h"
#include "commands.h"
#include "log.h"
#include "utils.h"
......@@ -72,6 +73,7 @@ struct hierarchy {
char *mountpoint;
char *base_cgroup;
char *fullcgpath;
bool is_cgroup_v2;
};
/*
......@@ -600,7 +602,8 @@ static bool handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
}
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;
......@@ -742,10 +745,14 @@ static bool is_lxcfs(const char *line)
*/
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, ' ');
......@@ -768,6 +775,13 @@ static char **get_controllers(char **klist, char **nlist, char *line)
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);
......@@ -776,15 +790,6 @@ static char **get_controllers(char **klist, char **nlist, char *line)
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)
{
......@@ -797,6 +802,12 @@ 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;
}
......@@ -878,13 +889,21 @@ static bool controller_in_clist(char *cgline, char *c)
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;
......@@ -899,20 +918,6 @@ static char *get_current_cgroup(char *basecginfo, char *controller)
}
}
/*
* 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);
......@@ -941,16 +946,17 @@ static void get_existing_subsystems(char ***klist, char ***nlist)
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)) {
......@@ -1058,8 +1064,10 @@ static bool parse_hierarchies(void)
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);
......@@ -1085,9 +1093,14 @@ static bool parse_hierarchies(void)
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);
......
/*
* 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;
}
/*
* 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 */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment