[PATCH] Remove down_write() from taskstats code invoked on the exit() path
[linux-2.6.git] / kernel / taskstats.c
index abb59e3..f45179c 100644 (file)
@@ -51,6 +51,7 @@ __read_mostly = {
 struct listener {
        struct list_head list;
        pid_t pid;
+       char valid;
 };
 
 struct listener_list {
@@ -127,7 +128,7 @@ static int send_cpu_listeners(struct sk_buff *skb, unsigned int cpu)
        struct listener *s, *tmp;
        struct sk_buff *skb_next, *skb_cur = skb;
        void *reply = genlmsg_data(genlhdr);
-       int rc, ret;
+       int rc, ret, delcount = 0;
 
        rc = genlmsg_end(skb, reply);
        if (rc < 0) {
@@ -137,7 +138,7 @@ static int send_cpu_listeners(struct sk_buff *skb, unsigned int cpu)
 
        rc = 0;
        listeners = &per_cpu(listener_array, cpu);
-       down_write(&listeners->sem);
+       down_read(&listeners->sem);
        list_for_each_entry_safe(s, tmp, &listeners->list, list) {
                skb_next = NULL;
                if (!list_is_last(&s->list, &listeners->list)) {
@@ -150,14 +151,26 @@ static int send_cpu_listeners(struct sk_buff *skb, unsigned int cpu)
                }
                ret = genlmsg_unicast(skb_cur, s->pid);
                if (ret == -ECONNREFUSED) {
-                       list_del(&s->list);
-                       kfree(s);
+                       s->valid = 0;
+                       delcount++;
                        rc = ret;
                }
                skb_cur = skb_next;
        }
-       up_write(&listeners->sem);
+       up_read(&listeners->sem);
+
+       if (!delcount)
+               return rc;
 
+       /* Delete invalidated entries */
+       down_write(&listeners->sem);
+       list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+               if (!s->valid) {
+                       list_del(&s->list);
+                       kfree(s);
+               }
+       }
+       up_write(&listeners->sem);
        return rc;
 }
 
@@ -290,6 +303,7 @@ static int add_del_listener(pid_t pid, cpumask_t *maskp, int isadd)
                                goto cleanup;
                        s->pid = pid;
                        INIT_LIST_HEAD(&s->list);
+                       s->valid = 1;
 
                        listeners = &per_cpu(listener_array, cpu);
                        down_write(&listeners->sem);