diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2006-10-02 05:18:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-02 10:57:24 -0400 |
commit | a593d6edeb0a5a2c6e6919b225cec668a375df52 (patch) | |
tree | f61ea811ad6c9d6bbba9268bdb08cf507fab5e93 | |
parent | 5e6b3f42edc20e988b186fbfb9eec174294222ea (diff) |
[PATCH] proc: convert do_task_stat() to use lock_task_sighand()
Drop tasklist_lock. ->siglock protects almost all interesting data
(including sub-threads traversal) except:
->signal->tty
protected by tty_mutex
->real_parent
the task can't be unhashed while we are holding
->siglock, so ->real_parent can change from under us
but we can safely dereference it under rcu_read_lock()
->pgrp/->session
we can get inconsistent numbers if the task does
sys_setsid/daemonize at the same time. I hope this
is acceptable.
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/proc/array.c | 63 |
1 files changed, 35 insertions, 28 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 279fbf542c88..35bd39dac247 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -321,7 +321,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
321 | sigset_t sigign, sigcatch; | 321 | sigset_t sigign, sigcatch; |
322 | char state; | 322 | char state; |
323 | int res; | 323 | int res; |
324 | pid_t ppid, pgid = -1, sid = -1; | 324 | pid_t ppid = 0, pgid = -1, sid = -1; |
325 | int num_threads = 0; | 325 | int num_threads = 0; |
326 | struct mm_struct *mm; | 326 | struct mm_struct *mm; |
327 | unsigned long long start_time; | 327 | unsigned long long start_time; |
@@ -329,8 +329,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
329 | unsigned long min_flt = 0, maj_flt = 0; | 329 | unsigned long min_flt = 0, maj_flt = 0; |
330 | cputime_t cutime, cstime, utime, stime; | 330 | cputime_t cutime, cstime, utime, stime; |
331 | unsigned long rsslim = 0; | 331 | unsigned long rsslim = 0; |
332 | struct task_struct *t; | ||
333 | char tcomm[sizeof(task->comm)]; | 332 | char tcomm[sizeof(task->comm)]; |
333 | unsigned long flags; | ||
334 | 334 | ||
335 | state = *get_task_state(task); | 335 | state = *get_task_state(task); |
336 | vsize = eip = esp = 0; | 336 | vsize = eip = esp = 0; |
@@ -348,15 +348,33 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
348 | cutime = cstime = utime = stime = cputime_zero; | 348 | cutime = cstime = utime = stime = cputime_zero; |
349 | 349 | ||
350 | mutex_lock(&tty_mutex); | 350 | mutex_lock(&tty_mutex); |
351 | read_lock(&tasklist_lock); | 351 | rcu_read_lock(); |
352 | if (task->sighand) { | 352 | if (lock_task_sighand(task, &flags)) { |
353 | spin_lock_irq(&task->sighand->siglock); | 353 | struct signal_struct *sig = task->signal; |
354 | num_threads = atomic_read(&task->signal->count); | 354 | struct tty_struct *tty = sig->tty; |
355 | |||
356 | if (tty) { | ||
357 | /* | ||
358 | * sig->tty is not stable, but tty_mutex | ||
359 | * protects us from release_dev(tty) | ||
360 | */ | ||
361 | barrier(); | ||
362 | tty_pgrp = tty->pgrp; | ||
363 | tty_nr = new_encode_dev(tty_devnum(tty)); | ||
364 | } | ||
365 | |||
366 | num_threads = atomic_read(&sig->count); | ||
355 | collect_sigign_sigcatch(task, &sigign, &sigcatch); | 367 | collect_sigign_sigcatch(task, &sigign, &sigcatch); |
356 | 368 | ||
369 | cmin_flt = sig->cmin_flt; | ||
370 | cmaj_flt = sig->cmaj_flt; | ||
371 | cutime = sig->cutime; | ||
372 | cstime = sig->cstime; | ||
373 | rsslim = sig->rlim[RLIMIT_RSS].rlim_cur; | ||
374 | |||
357 | /* add up live thread stats at the group level */ | 375 | /* add up live thread stats at the group level */ |
358 | if (whole) { | 376 | if (whole) { |
359 | t = task; | 377 | struct task_struct *t = task; |
360 | do { | 378 | do { |
361 | min_flt += t->min_flt; | 379 | min_flt += t->min_flt; |
362 | maj_flt += t->maj_flt; | 380 | maj_flt += t->maj_flt; |
@@ -364,31 +382,20 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
364 | stime = cputime_add(stime, t->stime); | 382 | stime = cputime_add(stime, t->stime); |
365 | t = next_thread(t); | 383 | t = next_thread(t); |
366 | } while (t != task); | 384 | } while (t != task); |
367 | } | ||
368 | 385 | ||
369 | spin_unlock_irq(&task->sighand->siglock); | 386 | min_flt += sig->min_flt; |
370 | } | 387 | maj_flt += sig->maj_flt; |
371 | if (task->signal) { | 388 | utime = cputime_add(utime, sig->utime); |
372 | if (task->signal->tty) { | 389 | stime = cputime_add(stime, sig->stime); |
373 | tty_pgrp = task->signal->tty->pgrp; | ||
374 | tty_nr = new_encode_dev(tty_devnum(task->signal->tty)); | ||
375 | } | 390 | } |
391 | |||
392 | sid = sig->session; | ||
376 | pgid = process_group(task); | 393 | pgid = process_group(task); |
377 | sid = task->signal->session; | 394 | ppid = rcu_dereference(task->real_parent)->tgid; |
378 | cmin_flt = task->signal->cmin_flt; | 395 | |
379 | cmaj_flt = task->signal->cmaj_flt; | 396 | unlock_task_sighand(task, &flags); |
380 | cutime = task->signal->cutime; | ||
381 | cstime = task->signal->cstime; | ||
382 | rsslim = task->signal->rlim[RLIMIT_RSS].rlim_cur; | ||
383 | if (whole) { | ||
384 | min_flt += task->signal->min_flt; | ||
385 | maj_flt += task->signal->maj_flt; | ||
386 | utime = cputime_add(utime, task->signal->utime); | ||
387 | stime = cputime_add(stime, task->signal->stime); | ||
388 | } | ||
389 | } | 397 | } |
390 | ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0; | 398 | rcu_read_unlock(); |
391 | read_unlock(&tasklist_lock); | ||
392 | mutex_unlock(&tty_mutex); | 399 | mutex_unlock(&tty_mutex); |
393 | 400 | ||
394 | if (!whole || num_threads<2) | 401 | if (!whole || num_threads<2) |