aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2008-02-08 07:18:31 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 12:22:23 -0500
commitee992744ea53db0a90c986fd0a70fbbf91e7f8bd (patch)
tree2d15727e92c407bb22c4842923cbfb2dfda82306
parentbe614086a4aff163d5aa0dc160638d1193b59cde (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>
-rw-r--r--fs/proc/array.c24
-rw-r--r--fs/proc/base.c4
-rw-r--r--fs/proc/internal.h9
3 files changed, 20 insertions, 17 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
393static int do_task_stat(struct task_struct *task, char *buffer, int whole) 394static 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
556int proc_tid_stat(struct task_struct *task, char *buffer) 554int 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
561int proc_tgid_stat(struct task_struct *task, char *buffer) 560int 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
566int proc_pid_statm(struct task_struct *task, char *buffer) 566int proc_pid_statm(struct task_struct *task, char *buffer)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index f4b1e14bd95b..f77818ecaa8a 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2280,7 +2280,7 @@ static const struct pid_entry tgid_base_stuff[] = {
2280 REG("sched", S_IRUGO|S_IWUSR, pid_sched), 2280 REG("sched", S_IRUGO|S_IWUSR, pid_sched),
2281#endif 2281#endif
2282 INF("cmdline", S_IRUGO, pid_cmdline), 2282 INF("cmdline", S_IRUGO, pid_cmdline),
2283 INF("stat", S_IRUGO, tgid_stat), 2283 ONE("stat", S_IRUGO, tgid_stat),
2284 INF("statm", S_IRUGO, pid_statm), 2284 INF("statm", S_IRUGO, pid_statm),
2285 REG("maps", S_IRUGO, maps), 2285 REG("maps", S_IRUGO, maps),
2286#ifdef CONFIG_NUMA 2286#ifdef CONFIG_NUMA
@@ -2611,7 +2611,7 @@ static const struct pid_entry tid_base_stuff[] = {
2611 REG("sched", S_IRUGO|S_IWUSR, pid_sched), 2611 REG("sched", S_IRUGO|S_IWUSR, pid_sched),
2612#endif 2612#endif
2613 INF("cmdline", S_IRUGO, pid_cmdline), 2613 INF("cmdline", S_IRUGO, pid_cmdline),
2614 INF("stat", S_IRUGO, tid_stat), 2614 ONE("stat", S_IRUGO, tid_stat),
2615 INF("statm", S_IRUGO, pid_statm), 2615 INF("statm", S_IRUGO, pid_statm),
2616 REG("maps", S_IRUGO, maps), 2616 REG("maps", S_IRUGO, maps),
2617#ifdef CONFIG_NUMA 2617#ifdef CONFIG_NUMA
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 7d57e8069924..f1cc6f1f4e34 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -46,10 +46,13 @@ extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
46 46
47extern int maps_protect; 47extern int maps_protect;
48 48
49extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f); 49extern void create_seq_entry(char *name, mode_t mode,
50 const struct file_operations *f);
50extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **); 51extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **);
51extern int proc_tid_stat(struct task_struct *, char *); 52extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns,
52extern int proc_tgid_stat(struct task_struct *, char *); 53 struct pid *pid, struct task_struct *task);
54extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns,
55 struct pid *pid, struct task_struct *task);
53extern int proc_pid_status(struct task_struct *, char *); 56extern int proc_pid_status(struct task_struct *, char *);
54extern int proc_pid_statm(struct task_struct *, char *); 57extern int proc_pid_statm(struct task_struct *, char *);
55extern loff_t mem_lseek(struct file *file, loff_t offset, int orig); 58extern loff_t mem_lseek(struct file *file, loff_t offset, int orig);