This commit adds cgroup v2 support to cgroup_init(). With these changes, cgget and cgset now work on a cgroup v1 mount, a cgroup v2 mount, or a cgroup v2 unified mount hierarchy.
Signed-off-by: Tom Hromatka <tom.hroma...@oracle.com> --- src/api.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/src/api.c b/src/api.c index 2ced9298a275..bb3a86ef8305 100644 --- a/src/api.c +++ b/src/api.c @@ -63,6 +63,12 @@ static __thread char errtext[MAXLEN]; /* Task command name length */ #define TASK_COMM_LEN 16 +/* cgroup v2 controllers file */ +#define CGV2_CONTROLLERS_FILE "cgroup.controllers" + +/* maximum line length when reading the cgroup.controllers file */ +#define LL_MAX 100 + /* Check if cgroup_init has been called or not. */ static int cgroup_initialized; @@ -1148,6 +1154,96 @@ out: return ret; } +/** + * Process a cgroup v2 mount and add it to cg_mount_table if it's not a + * duplicate. + * + * @param ent File system description of cgroup mount being processed + * @param mnt_tbl_idx cg_mount_table index + */ +static int cgroup_process_v2_mnt(struct mntent *ent, int *mnt_tbl_idx) +{ + char cgroup_controllers_path[FILENAME_MAX]; + char *ret_c = NULL, line[LL_MAX], *stok_buff = NULL; + int ret = 0, i, duplicate; + FILE *fp = NULL; + + /* determine what v2 controllers are available on this mount */ + snprintf(cgroup_controllers_path, FILENAME_MAX, "%s/%s", ent->mnt_dir, + CGV2_CONTROLLERS_FILE); + + fp = fopen(cgroup_controllers_path, "re"); + if (!fp) { + ret = ECGOTHER; + goto out; + } + + ret_c = fgets(line, LL_MAX, fp); + if (ret_c == NULL) { + ret = ECGEOF; + goto out; + } + + /* remove the trailing newline */ + ret_c[strlen(ret_c) - 1] = '\0'; + + /* + * cgroup.controllers returns a list of available controllers in + * the following format: + * cpuset cpu io memory pids rdma + */ + stok_buff = strtok(ret_c, " "); + while (stok_buff) { + /* do not have duplicates in mount table */ + duplicate = 0; + + for (i = 0; i < *mnt_tbl_idx; i++) { + if (strncmp(cg_mount_table[i].name, stok_buff, + FILENAME_MAX) == 0) { + duplicate = 1; + break; + } + } + + if (duplicate) { + cgroup_dbg("controller %s is already mounted on %s\n", + stok_buff, cg_mount_table[i].mount.path); + + ret = cg_add_duplicate_mount(&cg_mount_table[i], + ent->mnt_dir); + if (ret) + goto out; + + /* advance to the next controller */ + stok_buff = strtok(NULL, " "); + continue; + } + + /* this controller is not in the mount table. add it */ + strncpy(cg_mount_table[*mnt_tbl_idx].name, + stok_buff, FILENAME_MAX); + cg_mount_table[*mnt_tbl_idx].name[FILENAME_MAX-1] = '\0'; + strncpy(cg_mount_table[*mnt_tbl_idx].mount.path, + ent->mnt_dir, FILENAME_MAX); + cg_mount_table[*mnt_tbl_idx].mount.path[FILENAME_MAX-1] = + '\0'; + cg_mount_table[*mnt_tbl_idx].version = CGROUP_V2; + cg_mount_table[*mnt_tbl_idx].mount.next = NULL; + cgroup_dbg("Found cgroup option %s, count %d\n", + stok_buff, *mnt_tbl_idx); + (*mnt_tbl_idx)++; + + /* advance to the next controller */ + stok_buff = strtok(NULL, " "); + } + +out: + if (fp) + fclose(fp); + + return ret; +} + /** * cgroup_init(), initializes the MOUNT_POINT. * @@ -1256,6 +1352,16 @@ int cgroup_init(void) if (ret) goto unlock_exit; } + else if (strcmp(ent->mnt_type, "cgroup2") == 0) { + ret = cgroup_process_v2_mnt(ent, &found_mnt); + if (ret == ECGEOF) + /* The controllers file was empty. Ignore and + * move on. + */ + continue; + else if (ret) + goto unlock_exit; + } } free(temp_ent); -- 2.25.3 _______________________________________________ Libcg-devel mailing list Libcg-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libcg-devel