]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
api.c: add cgroup v2 support to cgroup_get_current_controller_path()
authorKamalesh Babulal <kamalesh.babulal@oracle.com>
Sun, 23 Apr 2023 11:16:48 +0000 (16:46 +0530)
committerTom Hromatka <tom.hromatka@oracle.com>
Thu, 27 Apr 2023 14:22:38 +0000 (08:22 -0600)
Add support to read/parse cgroup v2 format /proc/<pid>/cgroup to
cgroup_get_current_controller_path(). The format of /proc/<pid>/cgroup
remains the same:
hierarchy-ID:controller-list:cgroup-path

the difference is that in cgroup v2 mode:
- hierarchy-ID is always 0 (one hierarchy allowed)
- controller-list is empty

there can also be a mix of both legacy and unified controllers for a
given task if the cgroup mode is hybrid mode.  This patch, add support
for the mixed cgroup setup mode too.

Reported-by: Adriaan Schmidt <adriaan.schmidt@siemens.com>
Signed-off-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>
src/api.c

index 941b0755ff5f7070567d396f43c55cc01fb3edaf..99ca01b8a911e9996ac6cd47ba4bffc746f4caac 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -4805,17 +4805,37 @@ int cgroup_init_rules_cache(void)
 int cgroup_get_current_controller_path(pid_t pid, const char *controller, char **current_path)
 {
        FILE *pid_cgroup_fd = NULL;
+       enum cg_version_t version;
+       enum cg_setup_mode_t mode;
+       bool unified = false;
        char *path = NULL;
        int ret;
 
-       if (!controller)
-               return ECGOTHER;
-
        if (!cgroup_initialized) {
                cgroup_warn("libcgroup is not initialized\n");
                return ECGROUPNOTINITIALIZED;
        }
 
+       mode = cgroup_setup_mode();
+       if (mode == CGROUP_MODE_LEGACY && !controller)
+               return ECGOTHER;
+
+       /*
+        * both unified/hybrid can have the controller mounted as
+        * cgroup v2 version.
+        */
+       if  (!controller) {
+               unified = true;
+       } else {
+               ret = cgroup_get_controller_version(controller, &version);
+               if (ret) {
+                       cgroup_warn("Failed to get version of the controller: %s\n", controller);
+                       ret = ECGINVAL;
+                       goto cleanup_path;
+               }
+               unified = (version == CGROUP_V2);
+       }
+
        ret = asprintf(&path, "/proc/%d/cgroup", pid);
        if (ret <= 0) {
                cgroup_warn("cannot allocate memory (/proc/pid/cgroup) ret %d\n", ret);
@@ -4842,6 +4862,49 @@ int cgroup_get_current_controller_path(pid_t pid, const char *controller, char *
                char *token;
                int num;
 
+               /*
+                * with unified mode, the /proc/pid/cgroup the output is
+                * similar to that of cgroup legacy and hybrid modes:
+                * hierarchy-ID:controller-list:cgroup-path
+                *
+                * the difference is that in cgroup v2:
+                * - hierarchy-ID is always 0 (one hierarchy allowed)
+                * - controller-list is empty
+                */
+               if (mode == CGROUP_MODE_UNIFIED || unified) {
+                       ret = fscanf(pid_cgroup_fd, "%d::%4096s\n", &num, cgroup_path);
+                       if (ret != 2) {
+                               /*
+                                * we are interested only in unified format
+                                * line, skip this line.
+                                */
+                               if (unified) {
+                                       fscanf(pid_cgroup_fd, "%*[^\n]\n");
+                                       continue;
+                               }
+
+                               cgroup_warn("read failed for pid_cgroup_fd ret %d\n", ret);
+                               last_errno = errno;
+                               ret = ECGOTHER;
+                               goto done;
+                       }
+
+                       /* check if the controller is enabled in cgroup v2 */
+                       if (controller) {
+                               ret = cgroupv2_controller_enabled(cgroup_path, controller);
+                               if (ret)
+                                       goto done;
+                       }
+
+                       *current_path = strdup(cgroup_path);
+                       if (!*current_path) {
+                               last_errno = errno;
+                               ret = ECGOTHER;
+                       }
+                       ret = 0;
+                       goto done;
+               }
+
                /*
                 * 4096 == FILENAME_MAX, keeping the coverity happy with precision
                 * for the cgroup_path.