cgroup: Add generic cgroup subsystem permission checks.
[linux-2.6.git] / kernel / taskstats.c
index 3308fd7..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
@@ -89,8 +89,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
                return -ENOMEM;
 
        if (!info) {
-               int seq = get_cpu_var(taskstats_seqnum)++;
-               put_cpu_var(taskstats_seqnum);
+               int seq = this_cpu_inc_return(taskstats_seqnum) - 1;
 
                reply = genlmsg_put(skb, 0, seq, &family, 0, cmd);
        } else
@@ -286,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))
@@ -294,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;
        }
@@ -349,7 +355,7 @@ static int parse(struct nlattr *na, struct cpumask *mask)
        return ret;
 }
 
-#ifdef CONFIG_IA64
+#if defined(CONFIG_64BIT) && !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
 #define TASKSTATS_NEEDS_PADDING 1
 #endif
 
@@ -612,7 +618,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
                fill_tgid_exit(tsk);
        }
 
-       listeners = &__raw_get_cpu_var(listener_array);
+       listeners = __this_cpu_ptr(&listener_array);
        if (list_empty(&listeners->list))
                return;
 
@@ -649,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 = {
@@ -686,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);