cgroup, perf_event: make perf_event controller work on cgroup2 hierarchy
authorTejun Heo <tj@kernel.org>
Sun, 29 Jan 2017 19:35:20 +0000 (14:35 -0500)
committerTejun Heo <tj@kernel.org>
Thu, 2 Feb 2017 18:47:02 +0000 (13:47 -0500)
perf_event is a utility controller whose primary role is identifying
cgroup membership to filter perf events; however, because it also
tracks some per-css state, it can't be replaced by pure cgroup
membership test.  Mark the controller as implicitly enabled on the
default hierarchy so that perf events can always be filtered based on
cgroup v2 path as long as the controller is not mounted on a legacy
hierarchy.

"perf record" is updated accordingly so that it searches for both v1
and v2 hierarchies.  A v1 hierarchy is used if perf_event is mounted
on it; otherwise, it uses the v2 hierarchy.

v2: Doc updated to reflect more flexible rebinding behavior.

Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Documentation/cgroup-v2.txt
kernel/events/core.c
tools/perf/util/cgroup.c

index f6f54107fb4d501634fb9ae4ca22982cb7932592..227ce48837202b27b16d9752c0b32361eca7283d 100644 (file)
@@ -49,6 +49,8 @@ CONTENTS
     5-3-2. Writeback
   5-4. PID
     5-4-1. PID Interface Files
+  5-5. Misc
+    5-5-1. perf_event
 6. Namespace
   6-1. Basics
   6-2. The Root and Views
@@ -1160,6 +1162,16 @@ through fork() or clone(). These will return -EAGAIN if the creation
 of a new process would cause a cgroup policy to be violated.
 
 
+5-5. Misc
+
+5-5-1. perf_event
+
+perf_event controller, if not mounted on a legacy hierarchy, is
+automatically enabled on the v2 hierarchy so that perf events can
+always be filtered by cgroup v2 path.  The controller can still be
+moved to a legacy hierarchy after v2 hierarchy is populated.
+
+
 6. Namespace
 
 6-1. Basics
index ab15509fab8c0659c3f422036f5649718a9e4437..d72128dce1e09bee187fe2c27df1c8f36085e4c0 100644 (file)
@@ -10792,5 +10792,11 @@ struct cgroup_subsys perf_event_cgrp_subsys = {
        .css_alloc      = perf_cgroup_css_alloc,
        .css_free       = perf_cgroup_css_free,
        .attach         = perf_cgroup_attach,
+       /*
+        * Implicitly enable on dfl hierarchy so that perf events can
+        * always be filtered by cgroup2 path as long as perf_event
+        * controller is not mounted on a legacy hierarchy.
+        */
+       .implicit_on_dfl = true,
 };
 #endif /* CONFIG_CGROUP_PERF */
index 8fdee24725a7f59febb37eeb85b3a22d8dd1f82b..eafbf11442b224f90ad9c5d704df75d86985f917 100644 (file)
@@ -12,8 +12,8 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
 {
        FILE *fp;
        char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
+       char path_v1[PATH_MAX + 1], path_v2[PATH_MAX + 2], *path;
        char *token, *saved_ptr = NULL;
-       int found = 0;
 
        fp = fopen("/proc/mounts", "r");
        if (!fp)
@@ -24,31 +24,43 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
         * and inspect every cgroupfs mount point to find one that has
         * perf_event subsystem
         */
+       path_v1[0] = '\0';
+       path_v2[0] = '\0';
+
        while (fscanf(fp, "%*s %"STR(PATH_MAX)"s %"STR(PATH_MAX)"s %"
                                STR(PATH_MAX)"s %*d %*d\n",
                                mountpoint, type, tokens) == 3) {
 
-               if (!strcmp(type, "cgroup")) {
+               if (!path_v1[0] && !strcmp(type, "cgroup")) {
 
                        token = strtok_r(tokens, ",", &saved_ptr);
 
                        while (token != NULL) {
                                if (!strcmp(token, "perf_event")) {
-                                       found = 1;
+                                       strcpy(path_v1, mountpoint);
                                        break;
                                }
                                token = strtok_r(NULL, ",", &saved_ptr);
                        }
                }
-               if (found)
+
+               if (!path_v2[0] && !strcmp(type, "cgroup2"))
+                       strcpy(path_v2, mountpoint);
+
+               if (path_v1[0] && path_v2[0])
                        break;
        }
        fclose(fp);
-       if (!found)
+
+       if (path_v1[0])
+               path = path_v1;
+       else if (path_v2[0])
+               path = path_v2;
+       else
                return -1;
 
-       if (strlen(mountpoint) < maxlen) {
-               strcpy(buf, mountpoint);
+       if (strlen(path) < maxlen) {
+               strcpy(buf, path);
                return 0;
        }
        return -1;