diff options
Diffstat (limited to 'kernel/taskstats.c')
-rw-r--r-- | kernel/taskstats.c | 24 |
1 files changed, 19 insertions, 5 deletions
diff --git a/kernel/taskstats.c b/kernel/taskstats.c index abb59e323544..f45179ce028e 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c | |||
@@ -51,6 +51,7 @@ __read_mostly = { | |||
51 | struct listener { | 51 | struct listener { |
52 | struct list_head list; | 52 | struct list_head list; |
53 | pid_t pid; | 53 | pid_t pid; |
54 | char valid; | ||
54 | }; | 55 | }; |
55 | 56 | ||
56 | struct listener_list { | 57 | struct listener_list { |
@@ -127,7 +128,7 @@ static int send_cpu_listeners(struct sk_buff *skb, unsigned int cpu) | |||
127 | struct listener *s, *tmp; | 128 | struct listener *s, *tmp; |
128 | struct sk_buff *skb_next, *skb_cur = skb; | 129 | struct sk_buff *skb_next, *skb_cur = skb; |
129 | void *reply = genlmsg_data(genlhdr); | 130 | void *reply = genlmsg_data(genlhdr); |
130 | int rc, ret; | 131 | int rc, ret, delcount = 0; |
131 | 132 | ||
132 | rc = genlmsg_end(skb, reply); | 133 | rc = genlmsg_end(skb, reply); |
133 | if (rc < 0) { | 134 | if (rc < 0) { |
@@ -137,7 +138,7 @@ static int send_cpu_listeners(struct sk_buff *skb, unsigned int cpu) | |||
137 | 138 | ||
138 | rc = 0; | 139 | rc = 0; |
139 | listeners = &per_cpu(listener_array, cpu); | 140 | listeners = &per_cpu(listener_array, cpu); |
140 | down_write(&listeners->sem); | 141 | down_read(&listeners->sem); |
141 | list_for_each_entry_safe(s, tmp, &listeners->list, list) { | 142 | list_for_each_entry_safe(s, tmp, &listeners->list, list) { |
142 | skb_next = NULL; | 143 | skb_next = NULL; |
143 | if (!list_is_last(&s->list, &listeners->list)) { | 144 | if (!list_is_last(&s->list, &listeners->list)) { |
@@ -150,14 +151,26 @@ static int send_cpu_listeners(struct sk_buff *skb, unsigned int cpu) | |||
150 | } | 151 | } |
151 | ret = genlmsg_unicast(skb_cur, s->pid); | 152 | ret = genlmsg_unicast(skb_cur, s->pid); |
152 | if (ret == -ECONNREFUSED) { | 153 | if (ret == -ECONNREFUSED) { |
153 | list_del(&s->list); | 154 | s->valid = 0; |
154 | kfree(s); | 155 | delcount++; |
155 | rc = ret; | 156 | rc = ret; |
156 | } | 157 | } |
157 | skb_cur = skb_next; | 158 | skb_cur = skb_next; |
158 | } | 159 | } |
159 | up_write(&listeners->sem); | 160 | up_read(&listeners->sem); |
161 | |||
162 | if (!delcount) | ||
163 | return rc; | ||
160 | 164 | ||
165 | /* Delete invalidated entries */ | ||
166 | down_write(&listeners->sem); | ||
167 | list_for_each_entry_safe(s, tmp, &listeners->list, list) { | ||
168 | if (!s->valid) { | ||
169 | list_del(&s->list); | ||
170 | kfree(s); | ||
171 | } | ||
172 | } | ||
173 | up_write(&listeners->sem); | ||
161 | return rc; | 174 | return rc; |
162 | } | 175 | } |
163 | 176 | ||
@@ -290,6 +303,7 @@ static int add_del_listener(pid_t pid, cpumask_t *maskp, int isadd) | |||
290 | goto cleanup; | 303 | goto cleanup; |
291 | s->pid = pid; | 304 | s->pid = pid; |
292 | INIT_LIST_HEAD(&s->list); | 305 | INIT_LIST_HEAD(&s->list); |
306 | s->valid = 1; | ||
293 | 307 | ||
294 | listeners = &per_cpu(listener_array, cpu); | 308 | listeners = &per_cpu(listener_array, cpu); |
295 | down_write(&listeners->sem); | 309 | down_write(&listeners->sem); |