diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2008-02-08 07:18:31 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-08 12:22:23 -0500 |
commit | ee992744ea53db0a90c986fd0a70fbbf91e7f8bd (patch) | |
tree | 2d15727e92c407bb22c4842923cbfb2dfda82306 /fs/proc/array.c | |
parent | be614086a4aff163d5aa0dc160638d1193b59cde (diff) |
proc: rewrite do_task_stat to correctly handle pid namespaces.
Currently (as pointed out by Oleg) do_task_stat has a race when calling
task_pid_nr_ns with the task exiting. In addition do_task_stat is not
currently displaying information in the context of the pid namespace that
mounted the /proc filesystem. So "cut -d' ' -f 1 /proc/<pid>/stat" may not
equal <pid>.
This patch fixes the problem by converting to a single_open seq_file show
method. Getting the pid namespace from the filesystem superblock instead of
current, and simply using the the struct pid from the inode instead of
attempting to get that same pid from the task.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Cc: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc/array.c')
-rw-r--r-- | fs/proc/array.c | 24 |
1 files changed, 12 insertions, 12 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 6ba2746e4517..7e9f3b65f25b 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -77,6 +77,7 @@ | |||
77 | #include <linux/cpuset.h> | 77 | #include <linux/cpuset.h> |
78 | #include <linux/rcupdate.h> | 78 | #include <linux/rcupdate.h> |
79 | #include <linux/delayacct.h> | 79 | #include <linux/delayacct.h> |
80 | #include <linux/seq_file.h> | ||
80 | #include <linux/pid_namespace.h> | 81 | #include <linux/pid_namespace.h> |
81 | 82 | ||
82 | #include <asm/pgtable.h> | 83 | #include <asm/pgtable.h> |
@@ -390,14 +391,14 @@ static cputime_t task_gtime(struct task_struct *p) | |||
390 | return p->gtime; | 391 | return p->gtime; |
391 | } | 392 | } |
392 | 393 | ||
393 | static int do_task_stat(struct task_struct *task, char *buffer, int whole) | 394 | static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, |
395 | struct pid *pid, struct task_struct *task, int whole) | ||
394 | { | 396 | { |
395 | unsigned long vsize, eip, esp, wchan = ~0UL; | 397 | unsigned long vsize, eip, esp, wchan = ~0UL; |
396 | long priority, nice; | 398 | long priority, nice; |
397 | int tty_pgrp = -1, tty_nr = 0; | 399 | int tty_pgrp = -1, tty_nr = 0; |
398 | sigset_t sigign, sigcatch; | 400 | sigset_t sigign, sigcatch; |
399 | char state; | 401 | char state; |
400 | int res; | ||
401 | pid_t ppid = 0, pgid = -1, sid = -1; | 402 | pid_t ppid = 0, pgid = -1, sid = -1; |
402 | int num_threads = 0; | 403 | int num_threads = 0; |
403 | struct mm_struct *mm; | 404 | struct mm_struct *mm; |
@@ -409,9 +410,6 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) | |||
409 | unsigned long rsslim = 0; | 410 | unsigned long rsslim = 0; |
410 | char tcomm[sizeof(task->comm)]; | 411 | char tcomm[sizeof(task->comm)]; |
411 | unsigned long flags; | 412 | unsigned long flags; |
412 | struct pid_namespace *ns; | ||
413 | |||
414 | ns = current->nsproxy->pid_ns; | ||
415 | 413 | ||
416 | state = *get_task_state(task); | 414 | state = *get_task_state(task); |
417 | vsize = eip = esp = 0; | 415 | vsize = eip = esp = 0; |
@@ -498,10 +496,10 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) | |||
498 | /* convert nsec -> ticks */ | 496 | /* convert nsec -> ticks */ |
499 | start_time = nsec_to_clock_t(start_time); | 497 | start_time = nsec_to_clock_t(start_time); |
500 | 498 | ||
501 | res = sprintf(buffer, "%d (%s) %c %d %d %d %d %d %u %lu \ | 499 | seq_printf(m, "%d (%s) %c %d %d %d %d %d %u %lu \ |
502 | %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ | 500 | %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ |
503 | %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n", | 501 | %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n", |
504 | task_pid_nr_ns(task, ns), | 502 | pid_nr_ns(pid, ns), |
505 | tcomm, | 503 | tcomm, |
506 | state, | 504 | state, |
507 | ppid, | 505 | ppid, |
@@ -550,17 +548,19 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) | |||
550 | cputime_to_clock_t(cgtime)); | 548 | cputime_to_clock_t(cgtime)); |
551 | if (mm) | 549 | if (mm) |
552 | mmput(mm); | 550 | mmput(mm); |
553 | return res; | 551 | return 0; |
554 | } | 552 | } |
555 | 553 | ||
556 | int proc_tid_stat(struct task_struct *task, char *buffer) | 554 | int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns, |
555 | struct pid *pid, struct task_struct *task) | ||
557 | { | 556 | { |
558 | return do_task_stat(task, buffer, 0); | 557 | return do_task_stat(m, ns, pid, task, 0); |
559 | } | 558 | } |
560 | 559 | ||
561 | int proc_tgid_stat(struct task_struct *task, char *buffer) | 560 | int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns, |
561 | struct pid *pid, struct task_struct *task) | ||
562 | { | 562 | { |
563 | return do_task_stat(task, buffer, 1); | 563 | return do_task_stat(m, ns, pid, task, 1); |
564 | } | 564 | } |
565 | 565 | ||
566 | int proc_pid_statm(struct task_struct *task, char *buffer) | 566 | int proc_pid_statm(struct task_struct *task, char *buffer) |