diff options
Diffstat (limited to 'fs/proc/array.c')
-rw-r--r-- | fs/proc/array.c | 162 |
1 files changed, 154 insertions, 8 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index f9bd395b3473..c1c207c36cae 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -81,6 +81,7 @@ | |||
81 | #include <linux/pid_namespace.h> | 81 | #include <linux/pid_namespace.h> |
82 | #include <linux/ptrace.h> | 82 | #include <linux/ptrace.h> |
83 | #include <linux/tracehook.h> | 83 | #include <linux/tracehook.h> |
84 | #include <linux/user_namespace.h> | ||
84 | 85 | ||
85 | #include <asm/pgtable.h> | 86 | #include <asm/pgtable.h> |
86 | #include <asm/processor.h> | 87 | #include <asm/processor.h> |
@@ -161,6 +162,7 @@ static inline const char *get_task_state(struct task_struct *tsk) | |||
161 | static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | 162 | static inline void task_state(struct seq_file *m, struct pid_namespace *ns, |
162 | struct pid *pid, struct task_struct *p) | 163 | struct pid *pid, struct task_struct *p) |
163 | { | 164 | { |
165 | struct user_namespace *user_ns = current_user_ns(); | ||
164 | struct group_info *group_info; | 166 | struct group_info *group_info; |
165 | int g; | 167 | int g; |
166 | struct fdtable *fdt = NULL; | 168 | struct fdtable *fdt = NULL; |
@@ -189,8 +191,14 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
189 | task_tgid_nr_ns(p, ns), | 191 | task_tgid_nr_ns(p, ns), |
190 | pid_nr_ns(pid, ns), | 192 | pid_nr_ns(pid, ns), |
191 | ppid, tpid, | 193 | ppid, tpid, |
192 | cred->uid, cred->euid, cred->suid, cred->fsuid, | 194 | from_kuid_munged(user_ns, cred->uid), |
193 | cred->gid, cred->egid, cred->sgid, cred->fsgid); | 195 | from_kuid_munged(user_ns, cred->euid), |
196 | from_kuid_munged(user_ns, cred->suid), | ||
197 | from_kuid_munged(user_ns, cred->fsuid), | ||
198 | from_kgid_munged(user_ns, cred->gid), | ||
199 | from_kgid_munged(user_ns, cred->egid), | ||
200 | from_kgid_munged(user_ns, cred->sgid), | ||
201 | from_kgid_munged(user_ns, cred->fsgid)); | ||
194 | 202 | ||
195 | task_lock(p); | 203 | task_lock(p); |
196 | if (p->files) | 204 | if (p->files) |
@@ -205,7 +213,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
205 | task_unlock(p); | 213 | task_unlock(p); |
206 | 214 | ||
207 | for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) | 215 | for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) |
208 | seq_printf(m, "%d ", GROUP_AT(group_info, g)); | 216 | seq_printf(m, "%d ", |
217 | from_kgid_munged(user_ns, GROUP_AT(group_info, g))); | ||
209 | put_cred(cred); | 218 | put_cred(cred); |
210 | 219 | ||
211 | seq_putc(m, '\n'); | 220 | seq_putc(m, '\n'); |
@@ -361,7 +370,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
361 | struct pid *pid, struct task_struct *task, int whole) | 370 | struct pid *pid, struct task_struct *task, int whole) |
362 | { | 371 | { |
363 | unsigned long vsize, eip, esp, wchan = ~0UL; | 372 | unsigned long vsize, eip, esp, wchan = ~0UL; |
364 | long priority, nice; | 373 | int priority, nice; |
365 | int tty_pgrp = -1, tty_nr = 0; | 374 | int tty_pgrp = -1, tty_nr = 0; |
366 | sigset_t sigign, sigcatch; | 375 | sigset_t sigign, sigcatch; |
367 | char state; | 376 | char state; |
@@ -483,7 +492,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
483 | seq_put_decimal_ull(m, ' ', 0); | 492 | seq_put_decimal_ull(m, ' ', 0); |
484 | seq_put_decimal_ull(m, ' ', start_time); | 493 | seq_put_decimal_ull(m, ' ', start_time); |
485 | seq_put_decimal_ull(m, ' ', vsize); | 494 | seq_put_decimal_ull(m, ' ', vsize); |
486 | seq_put_decimal_ll(m, ' ', mm ? get_mm_rss(mm) : 0); | 495 | seq_put_decimal_ull(m, ' ', mm ? get_mm_rss(mm) : 0); |
487 | seq_put_decimal_ull(m, ' ', rsslim); | 496 | seq_put_decimal_ull(m, ' ', rsslim); |
488 | seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->start_code : 1) : 0); | 497 | seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->start_code : 1) : 0); |
489 | seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->end_code : 1) : 0); | 498 | seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->end_code : 1) : 0); |
@@ -508,9 +517,23 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
508 | seq_put_decimal_ull(m, ' ', delayacct_blkio_ticks(task)); | 517 | seq_put_decimal_ull(m, ' ', delayacct_blkio_ticks(task)); |
509 | seq_put_decimal_ull(m, ' ', cputime_to_clock_t(gtime)); | 518 | seq_put_decimal_ull(m, ' ', cputime_to_clock_t(gtime)); |
510 | seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cgtime)); | 519 | seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cgtime)); |
511 | seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->start_data : 0); | 520 | |
512 | seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->end_data : 0); | 521 | if (mm && permitted) { |
513 | seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->start_brk : 0); | 522 | seq_put_decimal_ull(m, ' ', mm->start_data); |
523 | seq_put_decimal_ull(m, ' ', mm->end_data); | ||
524 | seq_put_decimal_ull(m, ' ', mm->start_brk); | ||
525 | seq_put_decimal_ull(m, ' ', mm->arg_start); | ||
526 | seq_put_decimal_ull(m, ' ', mm->arg_end); | ||
527 | seq_put_decimal_ull(m, ' ', mm->env_start); | ||
528 | seq_put_decimal_ull(m, ' ', mm->env_end); | ||
529 | } else | ||
530 | seq_printf(m, " 0 0 0 0 0 0 0"); | ||
531 | |||
532 | if (permitted) | ||
533 | seq_put_decimal_ll(m, ' ', task->exit_code); | ||
534 | else | ||
535 | seq_put_decimal_ll(m, ' ', 0); | ||
536 | |||
514 | seq_putc(m, '\n'); | 537 | seq_putc(m, '\n'); |
515 | if (mm) | 538 | if (mm) |
516 | mmput(mm); | 539 | mmput(mm); |
@@ -556,3 +579,126 @@ int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns, | |||
556 | 579 | ||
557 | return 0; | 580 | return 0; |
558 | } | 581 | } |
582 | |||
583 | #ifdef CONFIG_CHECKPOINT_RESTORE | ||
584 | static struct pid * | ||
585 | get_children_pid(struct inode *inode, struct pid *pid_prev, loff_t pos) | ||
586 | { | ||
587 | struct task_struct *start, *task; | ||
588 | struct pid *pid = NULL; | ||
589 | |||
590 | read_lock(&tasklist_lock); | ||
591 | |||
592 | start = pid_task(proc_pid(inode), PIDTYPE_PID); | ||
593 | if (!start) | ||
594 | goto out; | ||
595 | |||
596 | /* | ||
597 | * Lets try to continue searching first, this gives | ||
598 | * us significant speedup on children-rich processes. | ||
599 | */ | ||
600 | if (pid_prev) { | ||
601 | task = pid_task(pid_prev, PIDTYPE_PID); | ||
602 | if (task && task->real_parent == start && | ||
603 | !(list_empty(&task->sibling))) { | ||
604 | if (list_is_last(&task->sibling, &start->children)) | ||
605 | goto out; | ||
606 | task = list_first_entry(&task->sibling, | ||
607 | struct task_struct, sibling); | ||
608 | pid = get_pid(task_pid(task)); | ||
609 | goto out; | ||
610 | } | ||
611 | } | ||
612 | |||
613 | /* | ||
614 | * Slow search case. | ||
615 | * | ||
616 | * We might miss some children here if children | ||
617 | * are exited while we were not holding the lock, | ||
618 | * but it was never promised to be accurate that | ||
619 | * much. | ||
620 | * | ||
621 | * "Just suppose that the parent sleeps, but N children | ||
622 | * exit after we printed their tids. Now the slow paths | ||
623 | * skips N extra children, we miss N tasks." (c) | ||
624 | * | ||
625 | * So one need to stop or freeze the leader and all | ||
626 | * its children to get a precise result. | ||
627 | */ | ||
628 | list_for_each_entry(task, &start->children, sibling) { | ||
629 | if (pos-- == 0) { | ||
630 | pid = get_pid(task_pid(task)); | ||
631 | break; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | out: | ||
636 | read_unlock(&tasklist_lock); | ||
637 | return pid; | ||
638 | } | ||
639 | |||
640 | static int children_seq_show(struct seq_file *seq, void *v) | ||
641 | { | ||
642 | struct inode *inode = seq->private; | ||
643 | pid_t pid; | ||
644 | |||
645 | pid = pid_nr_ns(v, inode->i_sb->s_fs_info); | ||
646 | return seq_printf(seq, "%d ", pid); | ||
647 | } | ||
648 | |||
649 | static void *children_seq_start(struct seq_file *seq, loff_t *pos) | ||
650 | { | ||
651 | return get_children_pid(seq->private, NULL, *pos); | ||
652 | } | ||
653 | |||
654 | static void *children_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
655 | { | ||
656 | struct pid *pid; | ||
657 | |||
658 | pid = get_children_pid(seq->private, v, *pos + 1); | ||
659 | put_pid(v); | ||
660 | |||
661 | ++*pos; | ||
662 | return pid; | ||
663 | } | ||
664 | |||
665 | static void children_seq_stop(struct seq_file *seq, void *v) | ||
666 | { | ||
667 | put_pid(v); | ||
668 | } | ||
669 | |||
670 | static const struct seq_operations children_seq_ops = { | ||
671 | .start = children_seq_start, | ||
672 | .next = children_seq_next, | ||
673 | .stop = children_seq_stop, | ||
674 | .show = children_seq_show, | ||
675 | }; | ||
676 | |||
677 | static int children_seq_open(struct inode *inode, struct file *file) | ||
678 | { | ||
679 | struct seq_file *m; | ||
680 | int ret; | ||
681 | |||
682 | ret = seq_open(file, &children_seq_ops); | ||
683 | if (ret) | ||
684 | return ret; | ||
685 | |||
686 | m = file->private_data; | ||
687 | m->private = inode; | ||
688 | |||
689 | return ret; | ||
690 | } | ||
691 | |||
692 | int children_seq_release(struct inode *inode, struct file *file) | ||
693 | { | ||
694 | seq_release(inode, file); | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | const struct file_operations proc_tid_children_operations = { | ||
699 | .open = children_seq_open, | ||
700 | .read = seq_read, | ||
701 | .llseek = seq_lseek, | ||
702 | .release = children_seq_release, | ||
703 | }; | ||
704 | #endif /* CONFIG_CHECKPOINT_RESTORE */ | ||