hung_task: fix false positive during vfork
[linux-2.6.git] / kernel / taskstats.c
index 3971c6b..e660464 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/fs.h>
 #include <linux/file.h>
 #include <net/genetlink.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
 
 /*
  * Maximum length of a cpumask that can be specified in
@@ -285,7 +285,7 @@ ret:
 static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
 {
        struct listener_list *listeners;
-       struct listener *s, *tmp;
+       struct listener *s, *tmp, *s2;
        unsigned int cpu;
 
        if (!cpumask_subset(mask, cpu_possible_mask))
@@ -293,18 +293,25 @@ static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
 
        if (isadd == REGISTER) {
                for_each_cpu(cpu, mask) {
-                       s = kmalloc_node(sizeof(struct listener), GFP_KERNEL,
-                                        cpu_to_node(cpu));
+                       s = kmalloc_node(sizeof(struct listener),
+                                       GFP_KERNEL, cpu_to_node(cpu));
                        if (!s)
                                goto cleanup;
+
                        s->pid = pid;
-                       INIT_LIST_HEAD(&s->list);
                        s->valid = 1;
 
                        listeners = &per_cpu(listener_array, cpu);
                        down_write(&listeners->sem);
+                       list_for_each_entry(s2, &listeners->list, list) {
+                               if (s2->pid == pid && s2->valid)
+                                       goto exists;
+                       }
                        list_add(&s->list, &listeners->list);
+                       s = NULL;
+exists:
                        up_write(&listeners->sem);
+                       kfree(s); /* nop if NULL */
                }
                return 0;
        }
@@ -648,6 +655,7 @@ static struct genl_ops taskstats_ops = {
        .cmd            = TASKSTATS_CMD_GET,
        .doit           = taskstats_user_cmd,
        .policy         = taskstats_cmd_get_policy,
+       .flags          = GENL_ADMIN_PERM,
 };
 
 static struct genl_ops cgroupstats_ops = {
@@ -685,7 +693,7 @@ static int __init taskstats_init(void)
                goto err_cgroup_ops;
 
        family_registered = 1;
-       printk("registered taskstats version %d\n", TASKSTATS_GENL_VERSION);
+       pr_info("registered taskstats version %d\n", TASKSTATS_GENL_VERSION);
        return 0;
 err_cgroup_ops:
        genl_unregister_ops(&family, &taskstats_ops);