]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
api: Support specifying controllers in cgroup_get_cgroup()
authorTom Hromatka <tom.hromatka@oracle.com>
Tue, 14 Feb 2023 19:53:03 +0000 (12:53 -0700)
committerTom Hromatka <tom.hromatka@oracle.com>
Wed, 22 Feb 2023 16:35:44 +0000 (09:35 -0700)
Add support for the user to explicitly specify controllers of interest
when calling cgroup_get_cgroup().  Controllers not specified will not
be added to the struct cgroup.  Also, this allows users to view cgroup
v2 controllers that aren't enabled.  This may be useful for seeing
settings like cpuset.cpus.effective even when the cpuset controller
isn't enabled.

If no controllers are specified, then the previous behavior should be
utilized.  All controllers that are enabled for that cgroup will be
added to the struct cgroup.

Here is a simple example python program that exercises these changes:
#!/usr/bin/env python3
from libcgroup import Cgroup, Version

cg = Cgroup('user.slice', Version.CGROUP_V2)
cg.add_controller('cpuset')
cg.get()

print(cg)

Reported-by: Justin Israel <justinisrael@gmail.com>
Reviewed-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>
(cherry picked from commit 6bb000d2dc90eb0e9966bba0aaf70c0daa655e09)

src/api.c

index ff79b344ce782af77b933c979d7e22c388499d31..210ef16500ef4a82eee3162c4f6d71313d20fb12 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -3535,6 +3535,7 @@ fill_error:
 int cgroup_get_cgroup(struct cgroup *cgroup)
 {
        struct dirent *ctrl_dir = NULL;
+       int initial_controller_cnt;
        char *control_path = NULL;
        char path[FILENAME_MAX];
        DIR *dir = NULL;
@@ -3552,12 +3553,31 @@ int cgroup_get_cgroup(struct cgroup *cgroup)
                return ECGROUPNOTALLOWED;
        }
 
+       initial_controller_cnt = cgroup->index;
+
        pthread_rwlock_rdlock(&cg_mount_table_lock);
        for (i = 0; i < CG_CONTROLLER_MAX && cg_mount_table[i].name[0] != '\0'; i++) {
                struct cgroup_controller *cgc;
                struct stat stat_buffer;
                int path_len;
 
+               if (initial_controller_cnt > 0) {
+                       bool skip_this_controller = true;
+
+                       /*
+                        * The user has specified a list of controllers they are interested
+                        * in.  Only operate on the specified controllers
+                        */
+                       for (j = 0; j < cgroup->index; j++) {
+                               if (strncmp(cg_mount_table[i].name, cgroup->controller[j]->name,
+                                           CONTROL_NAMELEN_MAX) == 0)
+                                       skip_this_controller = false;
+                       }
+
+                       if (skip_this_controller)
+                               continue;
+               }
+
                if (!cg_build_path_locked(NULL, path, cg_mount_table[i].name))
                        continue;
 
@@ -3599,16 +3619,26 @@ int cgroup_get_cgroup(struct cgroup *cgroup)
 
                        error = cgroupv2_get_subtree_control(path, cg_mount_table[i].name,
                                                             &enabled);
-                       if (error == ECGROUPNOTMOUNTED)
-                               continue;
-                       if (error)
+                       if (error == ECGROUPNOTMOUNTED) {
+                               /*
+                                * This controller isn't enabled.  Only hide it from the
+                                * user if they've chosen to view all enabled controllers.
+                                *
+                                * If they've specified the controllers they're interested in
+                                * and we've made it this far, then they are explicitly
+                                * interested in this controller and we should not remove it.
+                                */
+                               if (initial_controller_cnt == 0)
+                                       continue;
+                       } else if (error) {
                                goto unlock_error;
-
-                       if (!enabled)
-                               continue;
+                       }
                }
 
-               cgc = cgroup_add_controller(cgroup, cg_mount_table[i].name);
+               if (initial_controller_cnt)
+                       cgc = cgroup_get_controller(cgroup, cg_mount_table[i].name);
+               else
+                       cgc = cgroup_add_controller(cgroup, cg_mount_table[i].name);
                if (!cgc) {
                        error = ECGINVAL;
                        goto unlock_error;