/* Task command name length */
#define TASK_COMM_LEN 16
-/* cgroup v2 files */
-#define CGV2_CONTROLLERS_FILE "cgroup.controllers"
-#define CGV2_SUBTREE_CTRL_FILE "cgroup.subtree_control"
-
-/* 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;
static pthread_rwlock_t rl_lock = PTHREAD_RWLOCK_INITIALIZER;
/* Cgroup v2 mount path. Null if v2 isn't mounted */
-static char cg_cgroup_v2_mount_path[FILENAME_MAX];
+char cg_cgroup_v2_mount_path[FILENAME_MAX];
/* Namespace */
__thread char *cg_namespace_table[CG_CONTROLLER_MAX];
*/
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 *ret_c = NULL, line[CGV2_CONTROLLERS_LL_MAX], *stok_buff = NULL;
+ char *controller = NULL, *controllers = NULL;
char cgroup_controllers_path[FILENAME_MAX];
int ret = 0, i, duplicate, shared_mnt;
FILE *fp = NULL;
goto out;
}
- ret_c = fgets(line, LL_MAX, fp);
+ ret_c = fgets(line, CGV2_CONTROLLERS_LL_MAX, fp);
if (ret_c == NULL) {
struct cg_mount_point *tmp, *t;
* The first line of the file has stuff we are not interested in.
* So just read it and discard the information.
*/
- buf = malloc(LL_MAX);
+ buf = malloc(CGV2_CONTROLLERS_LL_MAX);
if (!buf) {
last_errno = errno;
ret = ECGOTHER;
goto err;
}
- if (!fgets(buf, LL_MAX, proc_cgroup)) {
+ if (!fgets(buf, CGV2_CONTROLLERS_LL_MAX, proc_cgroup)) {
cgroup_err("cannot read /proc/cgroups: %s\n", strerror(errno));
last_errno = errno;
ret = ECGOTHER;
size_t type_sz)
{
char cg_type_path[FILENAME_MAX];
- char cg_type[LL_MAX];
+ char cg_type[CGV2_CONTROLLERS_LL_MAX];
int len, err = 0;
FILE *fp = NULL;
}
}
- if (fgets(cg_type, LL_MAX, fp) == NULL) {
+ if (fgets(cg_type, CGV2_CONTROLLERS_LL_MAX, fp) == NULL) {
cgroup_warn("failed to read file %s: %s\n", cg_type_path, strerror(errno));
err = ECGOTHER;
goto out;
const char * const ctrl_name)
{
enum cg_version_t version;
- char cg_type[LL_MAX];
+ char cg_type[CGV2_CONTROLLERS_LL_MAX];
int err = ECGOTHER;
if (!cg_build_path(cg_name, path, ctrl_name))
#define CGROUP_FILE_PREFIX "cgroup"
+/* cgroup v2 files */
+#define CGV2_CONTROLLERS_FILE "cgroup.controllers"
+#define CGV2_SUBTREE_CTRL_FILE "cgroup.subtree_control"
+
+/* maximum line length when reading the cgroup.controllers file */
+#define CGV2_CONTROLLERS_LL_MAX 100
+
#define cgroup_err(x...) cgroup_log(CGROUP_LOG_ERROR, "Error: " x)
#define cgroup_warn(x...) cgroup_log(CGROUP_LOG_WARNING, "Warning: " x)
#define cgroup_info(x...) cgroup_log(CGROUP_LOG_INFO, "Info: " x)
/*
* Main mounting structures
+ *
+ * cg_mount_table_lock must be held to access:
+ * cg_mount_table
+ * cg_cgroup_v2_mount_path
*/
extern struct cg_mount_table_s cg_mount_table[CG_CONTROLLER_MAX];
+extern char cg_cgroup_v2_mount_path[FILENAME_MAX];
extern pthread_rwlock_t cg_mount_table_lock;
/*
{
struct cgroup_controller *cgc;
struct controller_data info;
+ enum cg_setup_mode_t mode;
void *handle;
- int ret;
+ int ret = 0;
- /* go through the controller list */
- ret = cgroup_get_all_controller_begin(&handle, &info);
- if ((ret != 0) && (ret != ECGEOF)) {
- fprintf(stderr, "cannot read controller data: %s\n", cgroup_strerror(ret));
- return ret;
- }
+ if (!cgroup)
+ return ECGINVAL;
+
+ mode = cgroup_setup_mode();
+
+ /*
+ * Per kernel documentation, cgroup-v2.rst, /proc/cgroups is "meaningless" for cgroup v2.
+ * Use the cgroup's cgroup.controllers file instead
+ */
+ if (mode == CGROUP_MODE_UNIFIED) {
+ char *ret_c, *controller, *stok_buff = NULL, line[CGV2_CONTROLLERS_LL_MAX];
+ /*
+ * cg_cgroup_v2_mount_path (FILENAME_MAX) + cgroup->name (FILENAME_MAX) +
+ * strlen("cgroup.controllers") (18) + 2 forward slashes + 1 NULL terminator
+ */
+ char cgroup_controllers_path[FILENAME_MAX * 2 + 18 + 2 + 1];
+ FILE *fp;
- while (ret == 0) {
- if (info.hierarchy == 0) {
- /*
- * the controller is not attached to any
- * hierarchy skip it.
- */
- goto next;
+ pthread_rwlock_rdlock(&cg_mount_table_lock);
+ if (strlen(cg_cgroup_v2_mount_path) == 0) {
+ ret = ECGOTHER;
+ goto out;
}
- /* add mounted controller to cgroup structure */
- cgc = cgroup_add_controller(cgroup, info.name);
- if (!cgc) {
- ret = ECGINVAL;
- fprintf(stderr, "controller %s can't be added\n", info.name);
- goto end;
+ snprintf(cgroup_controllers_path, sizeof(cgroup_controllers_path), "%s/%s/%s",
+ cg_cgroup_v2_mount_path, cgroup->name, CGV2_CONTROLLERS_FILE);
+ pthread_rwlock_unlock(&cg_mount_table_lock);
+
+ fp = fopen(cgroup_controllers_path, "re");
+ if (!fp) {
+ ret = ECGOTHER;
+ goto out;
+ }
+
+ ret_c = fgets(line, CGV2_CONTROLLERS_LL_MAX, fp);
+ fclose(fp);
+ if (ret_c == NULL) {
+ /* no controllers are enabled */
+ 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
+ */
+ controller = strtok_r(ret_c, " ", &stok_buff);
+ do {
+ cgc = cgroup_add_controller(cgroup, controller);
+ if (!cgc) {
+ ret = ECGINVAL;
+ fprintf(stderr, "controller %s can't be added\n", info.name);
+ goto end;
+ }
+ } while ((controller = strtok_r(NULL, " ", &stok_buff)));
+ } else {
+ /* go through the controller list */
+ ret = cgroup_get_all_controller_begin(&handle, &info);
+ if ((ret != 0) && (ret != ECGEOF)) {
+ fprintf(stderr, "cannot read controller data: %s\n", cgroup_strerror(ret));
+ return ret;
}
+ while (ret == 0) {
+ if (info.hierarchy == 0) {
+ /*
+ * the controller is not attached to any
+ * hierarchy skip it.
+ */
+ goto next;
+ }
+
+ /* add mounted controller to cgroup structure */
+ cgc = cgroup_add_controller(cgroup, info.name);
+ if (!cgc) {
+ ret = ECGINVAL;
+ fprintf(stderr, "controller %s can't be added\n", info.name);
+ goto end;
+ }
+
next:
- ret = cgroup_get_all_controller_next(&handle, &info);
- if (ret && ret != ECGEOF)
- goto end;
- }
+ ret = cgroup_get_all_controller_next(&handle, &info);
+ if (ret && ret != ECGEOF)
+ goto end;
+ }
end:
- cgroup_get_all_controller_end(&handle);
- if (ret == ECGEOF)
- ret = 0;
- if (ret)
- fprintf(stderr, "cgroup_get_controller_begin/next failed (%s)\n",
- cgroup_strerror(ret));
+ cgroup_get_all_controller_end(&handle);
+ if (ret == ECGEOF)
+ ret = 0;
+ if (ret)
+ fprintf(stderr, "cgroup_get_controller_begin/next failed (%s)\n",
+ cgroup_strerror(ret));
+ }
+out:
return ret;
}