From: Tom Hromatka Date: Wed, 23 Sep 2020 16:41:32 +0000 (-0600) Subject: api.c: Verify if a controller is enabled for a v2 cgroup X-Git-Tag: v2.0.rc1~21^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9fe521f7f084615b3355cb4e10c8288959d50daa;p=thirdparty%2Flibcgroup.git api.c: Verify if a controller is enabled for a v2 cgroup Add a function, cgroupv2_controller_enabled(), that checks if the requested cgroup v2 controller can be used for the specified path. Again, in cgroup v2, to use a controller, it must be added to the parent cgroup's cgroup.subtree_control file. This check is required to ensure that the cgexec and cgclassify operations will succeed. And with this commit, cgexec and cgclassify work on both cgroup v1 and cgroup v2 hierarchies. Signed-off-by: Tom Hromatka --- diff --git a/src/api.c b/src/api.c index 88042f95..13778989 100644 --- a/src/api.c +++ b/src/api.c @@ -127,6 +127,10 @@ static const char * const cgroup_ignored_tasks_files[] = { "tasks", NULL }; static int cg_get_cgroups_from_proc_cgroups(pid_t pid, char *cgroup_list[], char *controller_list[], int list_len); + +static int cgroupv2_get_subtree_control(const char *path, + const char *ctrl_name, + bool * const enabled); #endif static int cg_chown(const char *filename, uid_t owner, gid_t group) @@ -1541,6 +1545,53 @@ error: return err; } +STATIC int cgroupv2_controller_enabled(const char * const cg_name, + const char * const ctrl_name) +{ + char path[FILENAME_MAX] = {0}; + char *parent = NULL, *dname; + enum cg_version_t version; + bool enabled; + int error; + + error = cgroup_get_controller_version(ctrl_name, &version); + if (error) + return error; + + if (version != CGROUP_V2) + return 0; + + if (strncmp(cg_name, "/", strlen(cg_name)) == 0) + /* + * The root cgroup has been requested. All version 2 + * controllers are enabled on the root cgroup + */ + return 0; + + if (!cg_build_path(cg_name, path, ctrl_name)) + goto err; + + parent = strdup(path); + if (!parent) { + error = ECGOTHER; + goto err; + } + + dname = dirname(parent); + + error = cgroupv2_get_subtree_control(dname, ctrl_name, &enabled); + if (error) + goto err; + + if (enabled) + error = 0; +err: + if (parent) + free(parent); + + return error; +} + static int __cgroup_attach_task_pid(char *path, pid_t tid) { int ret = 0; @@ -1592,7 +1643,7 @@ err: */ int cgroup_attach_task_pid(struct cgroup *cgroup, pid_t tid) { - char path[FILENAME_MAX]; + char path[FILENAME_MAX] = {0}; int i, ret = 0; if (!cgroup_initialized) { @@ -1603,6 +1654,11 @@ int cgroup_attach_task_pid(struct cgroup *cgroup, pid_t tid) pthread_rwlock_rdlock(&cg_mount_table_lock); for (i = 0; i < CG_CONTROLLER_MAX && cg_mount_table[i].name[0] != '\0'; i++) { + ret = cgroupv2_controller_enabled(cgroup->name, + cgroup->controller[i]->name); + if (ret) + return ret; + ret = cgroup_build_tasks_procs_path(path, sizeof(path), cgroup->name, cgroup->controller[i]->name); @@ -1626,6 +1682,11 @@ int cgroup_attach_task_pid(struct cgroup *cgroup, pid_t tid) } for (i = 0; i < cgroup->index; i++) { + ret = cgroupv2_controller_enabled(cgroup->name, + cgroup->controller[i]->name); + if (ret) + return ret; + ret = cgroup_build_tasks_procs_path(path, sizeof(path), cgroup->name, cgroup->controller[i]->name); diff --git a/src/libcgroup-internal.h b/src/libcgroup-internal.h index b834202d..5dcf7ee0 100644 --- a/src/libcgroup-internal.h +++ b/src/libcgroup-internal.h @@ -350,6 +350,10 @@ int cgroup_build_tasks_procs_path(char * const path, int cgroupv2_get_subtree_control(const char *path, const char *ctrl_name, bool * const enabled); + +int cgroupv2_controller_enabled(const char * const cg_name, + const char * const ctrl_name); + #endif /* UNIT_TEST */ __END_DECLS