]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
The automatic classification engine (cgexec, cgclassify, pam_cgroup)
authorBalbir Singh <balbir@linux.vnet.ibm.com>
Mon, 29 Sep 2008 12:09:04 +0000 (12:09 +0000)
committerBalbir Singh <balbir@linux.vnet.ibm.com>
Mon, 29 Sep 2008 12:09:04 +0000 (12:09 +0000)
classify tasks. It is useful for an application to know where it has
been classified. I propose to add a new API
cgroup_get_current_controller_path() that returns the current
classification directory for the specified controller. One can easily
add on and build new API that will return paths of all mounted
controllers, but I want to start with something simple and useful.

I've also added a bunch of test cases for the same purpose.

Test output

# ./pathtest.sh
Test FAIL, get path failed for controller cpuset
Test PASS, controller cpu path /default
Test PASS, controller cpuacct path /default
Test PASS, controller memory path /default
Test FAIL, get path failed for controller memrlimit

I mounted just cpu, cpuacct and memory, thus the path for cpuset and
memrlimit could not be found (as expected).

Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com>
Reviewed-by: Dhaval Giani <dhaval@linux.vnet.ibm.com>
git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/trunk@200 4f4bb910-9a46-0410-90c8-c897d4f1cd53

api.c
libcgroup.h
tests/Makefile
tests/pathtest.c [new file with mode: 0644]
tests/pathtest.sh [new file with mode: 0755]

diff --git a/api.c b/api.c
index 60a458cf90e9f2022cbc7c1e6bce4bcf4359907b..2cd1a3735c30169d905c77b46517edc62da51f74 100644 (file)
--- a/api.c
+++ b/api.c
@@ -1908,3 +1908,89 @@ int cgroup_init_rules_cache()
 
        return ret;
 }
+
+/**
+ * cgroup_get_current_controller_path
+ * @pid: pid of the current process for which the path is to be determined
+ * @controller: name of the controller for which to determine current path
+ * @current_path: a pointer that is filled with the value of the current
+ *             path as seen in /proc/<pid>/cgroup
+ */
+int cgroup_get_current_controller_path(pid_t pid, const char *controller,
+                                       char **current_path)
+{
+       char *path;
+       int ret;
+       FILE *pid_cgroup_fd;
+
+       if (!controller)
+               return ECGOTHER;
+
+       if (!cgroup_initialized) {
+               dbg("libcgroup is not initialized\n");
+               return ECGROUPNOTINITIALIZED;
+       }
+
+       ret = asprintf(&path, "/proc/%d/cgroup", pid);
+       if (ret <= 0) {
+               dbg("cannot allocate memory (/proc/pid/cgroup) ret %d\n", ret);
+               return ret;
+       }
+
+       ret = ECGROUPNOTEXIST;
+       pid_cgroup_fd = fopen(path, "r");
+       if (!pid_cgroup_fd)
+               goto cleanup_path;
+
+       /*
+        * Why do we grab the cg_mount_table_lock?, the reason is that
+        * the cgroup of a pid can change via the cgroup_attach_task_pid()
+        * call. To make sure, we return consitent and safe results,
+        * we acquire the lock upfront. We can optimize by acquiring
+        * and releasing the lock in the while loop, but that
+        * will be more expensive.
+        */
+       pthread_rwlock_rdlock(&cg_mount_table_lock);
+       while (!feof(pid_cgroup_fd)) {
+               char controllers[FILENAME_MAX];
+               char cgroup_path[FILENAME_MAX];
+               int num;
+               char *savedptr;
+               char *token;
+
+               ret = fscanf(pid_cgroup_fd, "%d:%[^:]:%s\n", &num, controllers,
+                               cgroup_path);
+               /*
+                * Magic numbers like "3" seem to be integrating into
+                * my daily life, I need some magic to help make them
+                * disappear :)
+                */
+               if (ret != 3 || ret == EOF) {
+                       dbg("read failed for pid_cgroup_fd ret %d\n", ret);
+                       ret = ECGOTHER;
+                       goto done;
+               }
+
+               token = strtok_r(controllers, ",", &savedptr);
+               do {
+                       if (strncmp(controller, token, strlen(controller) + 1)
+                                                               == 0) {
+                               *current_path = strdup(cgroup_path);
+                               if (!*current_path) {
+                                       ret = ECGOTHER;
+                                       goto done;
+                               }
+                               ret = 0;
+                               goto done;
+                       }
+                       token = strtok_r(NULL, ",", &savedptr);
+               } while (token);
+       }
+
+done:
+       pthread_rwlock_unlock(&cg_mount_table_lock);
+       fclose(pid_cgroup_fd);
+cleanup_path:
+       free(path);
+       return ret;
+}
index c9e9689c7eb51add2be345cf9c05f4a23a2ce6bc..97c663dc6580f5ad00f0cea3d9b366cdd2102ad1 100644 (file)
@@ -255,6 +255,12 @@ int cgroup_reload_cached_rules(void);
  */
 int cgroup_init_rules_cache(void);
 
+/**
+ * Get the current cgroup path where the task specified by pid_t pid
+ * has been classified
+ */
+int cgroup_get_current_controller_path(pid_t pid, const char *controller,
+                                       char **current_path);
 
 /* The wrappers for filling libcg structures */
 
index 7a38b7a774906c9e7a0c5507e50e6aa8257292c4..5c602cbc5691128c6dc7c8ad108521c28008318b 100644 (file)
@@ -6,7 +6,8 @@ CFLAGS = -g -O2 -Wall -DDEBUG
 
 TARGET= libcgrouptest01 \
        libcg_ba \
-       setuid
+       setuid \
+       pathtest
 
 all:   $(TARGET)
 
@@ -19,5 +20,8 @@ libcg_ba: libcg_ba.cpp
 setuid: setuid.c
        $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LIBS)
 
+pathtest: pathtest.c
+       $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LIBS)
+
 clean:
        \rm -f $(TARGET)
diff --git a/tests/pathtest.c b/tests/pathtest.c
new file mode 100644 (file)
index 0000000..076c38a
--- /dev/null
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <libcgroup.h>
+
+int main(int argc, char *argv[])
+{
+       char *path;
+       char *expected_path, *controller;
+       int ret;
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage %s: <controller name> <path>\n",
+                       argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       controller = argv[1];
+       expected_path = argv[2];
+
+       cgroup_init();
+
+       ret = cgroup_get_current_controller_path(getpid(), controller, &path);
+       if (ret)
+               printf("Test FAIL, get path failed for controller %s\n",
+                       controller);
+       else {
+               if (strcmp(path, expected_path))
+                       printf("Test FAIL, expected_path %s, got path %s\n",
+                               expected_path, path);
+               else
+                       printf("Test PASS, controller %s path %s\n",
+                               controller, path);
+               free(path);
+       }
+
+       return EXIT_SUCCESS;
+}
diff --git a/tests/pathtest.sh b/tests/pathtest.sh
new file mode 100755 (executable)
index 0000000..b373389
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+while read name extra
+do
+       echo $name | grep -q '^#'
+       if [ $? -eq 0 ]
+       then
+               continue
+       fi
+       path=`cat /proc/$$/cgroup | cut -d ':' -f 3`
+       ./pathtest $name $path
+done < /proc/cgroups