From 0089752f7e9777d76196acae5f09d22f5e98dde7 Mon Sep 17 00:00:00 2001 From: Tom Hromatka Date: Tue, 14 Feb 2023 12:58:59 -0700 Subject: [PATCH] api: Add support for "cgroup" controller in cgroup v2 The "cgroup" controller has settings that the user may want to read/write, e.g. cgroup.controllers, cgroup.subtree_control, cgroup.procs, etc. Add support for this controller when the cgroup v2 mount table is parsed by creating a custom controller for the "cgroup" settings. Note that this feature has not been added to cgroup v1 and cgroup v1 will continue to have limited access to the cgroup.* files. Reported-by: Justin Israel Reviewed-by: Kamalesh Babulal Signed-off-by: Tom Hromatka (cherry picked from commit b09f6e750ecdf605f5b9cae97e6b831b6ecf187d) --- src/api.c | 32 +++++++++++++++++++-- tests/gunit/008-cgroup_process_v2_mount.cpp | 8 ++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/api.c b/src/api.c index 210ef165..a944b73a 100644 --- a/src/api.c +++ b/src/api.c @@ -1218,8 +1218,8 @@ out: */ STATIC int cgroup_process_v2_mnt(struct mntent *ent, int *mnt_tbl_idx) { + char *ret_c = NULL, line[LL_MAX], *stok_buff = NULL, *controller, *controllers = NULL; char cgroup_controllers_path[FILENAME_MAX]; - char *ret_c = NULL, line[LL_MAX], *stok_buff = NULL, *controller; int ret = 0, i, duplicate, shared_mnt; FILE *fp = NULL; @@ -1273,12 +1273,25 @@ STATIC int cgroup_process_v2_mnt(struct mntent *ent, int *mnt_tbl_idx) /* Remove the trailing newline */ ret_c[strlen(ret_c) - 1] = '\0'; + /* + * The "cgroup" controller is a pseudo-controller that has settings that a user may + * wish to read/modify. Add it to our cg_mount_table so that it can be manipulated + * like other "normal" controllers + */ + controllers = malloc(strlen(ret_c) + strlen(CGROUP_FILE_PREFIX) + 1); + if (!controllers) { + ret = ECGOTHER; + goto out; + } + + sprintf(controllers, "%s %s", ret_c, CGROUP_FILE_PREFIX); + /* * cgroup.controllers returns a list of available controllers in * the following format: * cpuset cpu io memory pids rdma */ - controller = strtok_r(ret_c, " ", &stok_buff); + controller = strtok_r(controllers, " ", &stok_buff); do { /* Check if controllers share mount points */ shared_mnt = cgroup_set_cg_mnt_tbl_shared_mnt(ent->mnt_dir, mnt_tbl_idx); @@ -1315,6 +1328,9 @@ out: if (fp) fclose(fp); + if (controllers) + free(controllers); + return ret; } @@ -5267,6 +5283,18 @@ int cgroup_get_controller_next(void **handle, struct cgroup_mount_point *info) goto out_unlock; } + if (strncmp(cg_mount_table[*pos].name, CGROUP_FILE_PREFIX, CONTROL_NAMELEN_MAX) == 0) + /* + * For now, hide the "cgroup" pseudo-controller from the user. This may be + * worth revisiting in the future. + */ + (*pos)++; + + if (cg_mount_table[*pos].name[0] == '\0') { + ret = ECGEOF; + goto out_unlock; + } + strncpy(info->name, cg_mount_table[*pos].name, FILENAME_MAX - 1); info->name[FILENAME_MAX - 1] = '\0'; diff --git a/tests/gunit/008-cgroup_process_v2_mount.cpp b/tests/gunit/008-cgroup_process_v2_mount.cpp index 84597893..a68c8ed7 100644 --- a/tests/gunit/008-cgroup_process_v2_mount.cpp +++ b/tests/gunit/008-cgroup_process_v2_mount.cpp @@ -106,13 +106,14 @@ TEST_F(CgroupProcessV2MntTest, AddV2Mount) ret = cgroup_process_v2_mnt(&ent, &mnt_tbl_idx); ASSERT_EQ(ret, 0); - ASSERT_EQ(mnt_tbl_idx, 6); + ASSERT_EQ(mnt_tbl_idx, 7); ASSERT_STREQ(cg_mount_table[0].name, "cpuset"); ASSERT_STREQ(cg_mount_table[1].name, "cpu"); ASSERT_STREQ(cg_mount_table[2].name, "io"); ASSERT_STREQ(cg_mount_table[3].name, "memory"); ASSERT_STREQ(cg_mount_table[4].name, "pids"); ASSERT_STREQ(cg_mount_table[5].name, "rdma"); + ASSERT_STREQ(cg_mount_table[6].name, "cgroup"); ASSERT_STREQ(cg_mount_table[0].mount.path, ent.mnt_dir); ASSERT_STREQ(cg_mount_table[1].mount.path, ent.mnt_dir); @@ -120,6 +121,7 @@ TEST_F(CgroupProcessV2MntTest, AddV2Mount) ASSERT_STREQ(cg_mount_table[3].mount.path, ent.mnt_dir); ASSERT_STREQ(cg_mount_table[4].mount.path, ent.mnt_dir); ASSERT_STREQ(cg_mount_table[5].mount.path, ent.mnt_dir); + ASSERT_STREQ(cg_mount_table[6].mount.path, ent.mnt_dir); } TEST_F(CgroupProcessV2MntTest, AddV2Mount_Duplicate) @@ -136,13 +138,14 @@ TEST_F(CgroupProcessV2MntTest, AddV2Mount_Duplicate) ret = cgroup_process_v2_mnt(&ent, &mnt_tbl_idx); ASSERT_EQ(ret, 0); - ASSERT_EQ(mnt_tbl_idx, 6); + ASSERT_EQ(mnt_tbl_idx, 7); ASSERT_STREQ(cg_mount_table[0].name, "cpuset"); ASSERT_STREQ(cg_mount_table[1].name, "cpu"); ASSERT_STREQ(cg_mount_table[2].name, "io"); ASSERT_STREQ(cg_mount_table[3].name, "memory"); ASSERT_STREQ(cg_mount_table[4].name, "pids"); ASSERT_STREQ(cg_mount_table[5].name, "rdma"); + ASSERT_STREQ(cg_mount_table[6].name, "cgroup"); ASSERT_STREQ(cg_mount_table[0].mount.next->path, ent.mnt_dir); ASSERT_STREQ(cg_mount_table[1].mount.next->path, ent.mnt_dir); @@ -150,6 +153,7 @@ TEST_F(CgroupProcessV2MntTest, AddV2Mount_Duplicate) ASSERT_STREQ(cg_mount_table[3].mount.next->path, ent.mnt_dir); ASSERT_STREQ(cg_mount_table[4].mount.next->path, ent.mnt_dir); ASSERT_STREQ(cg_mount_table[5].mount.next->path, ent.mnt_dir); + ASSERT_STREQ(cg_mount_table[6].mount.next->path, ent.mnt_dir); } /* -- 2.47.2