perf counters: group counter, fixes
authorIngo Molnar <mingo@elte.hu>
Thu, 11 Dec 2008 10:26:29 +0000 (11:26 +0100)
committerIngo Molnar <mingo@elte.hu>
Thu, 11 Dec 2008 14:45:50 +0000 (15:45 +0100)
Impact: bugfix

Check that a group does not span outside the context of a CPU or a task.

Also, do not allow deep recursive hierarchies.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
kernel/perf_counter.c

index fa59fe8c02d5b7d393f6fef36ca97e9a6bd84a74..278209c547a870dd12a43997dc3c5915ca084665 100644 (file)
@@ -107,9 +107,6 @@ list_del_counter(struct perf_counter *counter, struct perf_counter_context *ctx)
 
        list_del_init(&counter->list_entry);
 
-       if (list_empty(&counter->sibling_list))
-               return;
-
        /*
         * If this was a group counter with sibling counters then
         * upgrade the siblings to singleton counters by adding them
@@ -395,9 +392,6 @@ counter_sched_in(struct perf_counter *counter,
                 struct perf_counter_context *ctx,
                 int cpu)
 {
-       if (!counter->active)
-               return;
-
        hw_perf_counter_enable(counter);
        counter->active = 1;
        counter->oncpu = cpu;   /* TODO: put 'cpu' into cpuctx->cpu */
@@ -876,32 +870,39 @@ asmlinkage int sys_perf_counter_open(
                return -EFAULT;
 
        /*
-        * Look up the group leader:
+        * Get the target context (task or percpu):
+        */
+       ctx = find_get_context(pid, cpu);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+
+       /*
+        * Look up the group leader (we will attach this counter to it):
         */
        group_leader = NULL;
        if (group_fd != -1) {
                ret = -EINVAL;
                group_file = fget_light(group_fd, &fput_needed);
                if (!group_file)
-                       goto out_fput;
+                       goto err_put_context;
                if (group_file->f_op != &perf_fops)
-                       goto out_fput;
+                       goto err_put_context;
 
                group_leader = group_file->private_data;
                /*
-                * Do not allow a recursive hierarchy:
+                * Do not allow a recursive hierarchy (this new sibling
+                * becoming part of another group-sibling):
+                */
+               if (group_leader->group_leader != group_leader)
+                       goto err_put_context;
+               /*
+                * Do not allow to attach to a group in a different
+                * task or CPU context:
                 */
-               if (group_leader->group_leader)
-                       goto out_fput;
+               if (group_leader->ctx != ctx)
+                       goto err_put_context;
        }
 
-       /*
-        * Get the target context (task or percpu):
-        */
-       ctx = find_get_context(pid, cpu);
-       if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
-
        ret = -ENOMEM;
        counter = perf_counter_alloc(&hw_event, cpu, group_leader);
        if (!counter)