aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2006-10-28 13:38:54 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-28 14:30:54 -0400
commita98b6094261c0112e9c455c96995972181bff049 (patch)
tree01a15d79e331730de5a255a7109cf1318b95f6ac
parentb8534d7bd89df0cd41cd47bcd6733a05ea9a691a (diff)
[PATCH] taskstats: don't use tasklist_lock
Remove tasklist_lock from taskstats.c. find_task_by_pid() is rcu-safe. ->siglock allows us to traverse subthread without tasklist. Q: delay accounting looks wrong to me. If sub-thread has already called taskstats_exit_send() but didn't call release_task(self) yet it will be accounted twice. The window is big. No? Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> Cc: Shailabh Nagar <nagar@watson.ibm.com> Cc: Balbir Singh <balbir@in.ibm.com> Cc: Jay Lan <jlan@sgi.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--kernel/taskstats.c59
1 files changed, 24 insertions, 35 deletions
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index b2efda94615a..b724aeea5443 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -174,21 +174,19 @@ static void send_cpu_listeners(struct sk_buff *skb, unsigned int cpu)
174 up_write(&listeners->sem); 174 up_write(&listeners->sem);
175} 175}
176 176
177static int fill_pid(pid_t pid, struct task_struct *pidtsk, 177static int fill_pid(pid_t pid, struct task_struct *tsk,
178 struct taskstats *stats) 178 struct taskstats *stats)
179{ 179{
180 int rc = 0; 180 int rc = 0;
181 struct task_struct *tsk = pidtsk;
182 181
183 if (!pidtsk) { 182 if (!tsk) {
184 read_lock(&tasklist_lock); 183 rcu_read_lock();
185 tsk = find_task_by_pid(pid); 184 tsk = find_task_by_pid(pid);
186 if (!tsk) { 185 if (tsk)
187 read_unlock(&tasklist_lock); 186 get_task_struct(tsk);
187 rcu_read_unlock();
188 if (!tsk)
188 return -ESRCH; 189 return -ESRCH;
189 }
190 get_task_struct(tsk);
191 read_unlock(&tasklist_lock);
192 } else 190 } else
193 get_task_struct(tsk); 191 get_task_struct(tsk);
194 192
@@ -214,40 +212,28 @@ static int fill_pid(pid_t pid, struct task_struct *pidtsk,
214 212
215} 213}
216 214
217static int fill_tgid(pid_t tgid, struct task_struct *tgidtsk, 215static int fill_tgid(pid_t tgid, struct task_struct *first,
218 struct taskstats *stats) 216 struct taskstats *stats)
219{ 217{
220 struct task_struct *tsk, *first; 218 struct task_struct *tsk;
221 unsigned long flags; 219 unsigned long flags;
220 int rc = -ESRCH;
222 221
223 /* 222 /*
224 * Add additional stats from live tasks except zombie thread group 223 * Add additional stats from live tasks except zombie thread group
225 * leaders who are already counted with the dead tasks 224 * leaders who are already counted with the dead tasks
226 */ 225 */
227 first = tgidtsk; 226 rcu_read_lock();
228 if (!first) { 227 if (!first)
229 read_lock(&tasklist_lock);
230 first = find_task_by_pid(tgid); 228 first = find_task_by_pid(tgid);
231 if (!first) {
232 read_unlock(&tasklist_lock);
233 return -ESRCH;
234 }
235 get_task_struct(first);
236 read_unlock(&tasklist_lock);
237 } else
238 get_task_struct(first);
239 229
230 if (!first || !lock_task_sighand(first, &flags))
231 goto out;
240 232
241 tsk = first; 233 if (first->signal->stats)
242 read_lock(&tasklist_lock); 234 memcpy(stats, first->signal->stats, sizeof(*stats));
243 /* Start with stats from dead tasks */
244 if (first->sighand) {
245 spin_lock_irqsave(&first->sighand->siglock, flags);
246 if (first->signal->stats)
247 memcpy(stats, first->signal->stats, sizeof(*stats));
248 spin_unlock_irqrestore(&first->sighand->siglock, flags);
249 }
250 235
236 tsk = first;
251 do { 237 do {
252 if (tsk->exit_state == EXIT_ZOMBIE && thread_group_leader(tsk)) 238 if (tsk->exit_state == EXIT_ZOMBIE && thread_group_leader(tsk))
253 continue; 239 continue;
@@ -260,15 +246,18 @@ static int fill_tgid(pid_t tgid, struct task_struct *tgidtsk,
260 delayacct_add_tsk(stats, tsk); 246 delayacct_add_tsk(stats, tsk);
261 247
262 } while_each_thread(first, tsk); 248 } while_each_thread(first, tsk);
263 read_unlock(&tasklist_lock);
264 stats->version = TASKSTATS_VERSION;
265 249
250 unlock_task_sighand(first, &flags);
251 rc = 0;
252out:
253 rcu_read_unlock();
254
255 stats->version = TASKSTATS_VERSION;
266 /* 256 /*
267 * Accounting subsytems can also add calls here to modify 257 * Accounting subsytems can also add calls here to modify
268 * fields of taskstats. 258 * fields of taskstats.
269 */ 259 */
270 put_task_struct(first); 260 return rc;
271 return 0;
272} 261}
273 262
274 263