diff options
Diffstat (limited to 'fs/proc/array.c')
-rw-r--r-- | fs/proc/array.c | 147 |
1 files changed, 142 insertions, 5 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index dc4c5a7b9ece..c1c207c36cae 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -370,7 +370,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
370 | struct pid *pid, struct task_struct *task, int whole) | 370 | struct pid *pid, struct task_struct *task, int whole) |
371 | { | 371 | { |
372 | unsigned long vsize, eip, esp, wchan = ~0UL; | 372 | unsigned long vsize, eip, esp, wchan = ~0UL; |
373 | long priority, nice; | 373 | int priority, nice; |
374 | int tty_pgrp = -1, tty_nr = 0; | 374 | int tty_pgrp = -1, tty_nr = 0; |
375 | sigset_t sigign, sigcatch; | 375 | sigset_t sigign, sigcatch; |
376 | char state; | 376 | char state; |
@@ -492,7 +492,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
492 | seq_put_decimal_ull(m, ' ', 0); | 492 | seq_put_decimal_ull(m, ' ', 0); |
493 | seq_put_decimal_ull(m, ' ', start_time); | 493 | seq_put_decimal_ull(m, ' ', start_time); |
494 | seq_put_decimal_ull(m, ' ', vsize); | 494 | seq_put_decimal_ull(m, ' ', vsize); |
495 | seq_put_decimal_ll(m, ' ', mm ? get_mm_rss(mm) : 0); | 495 | seq_put_decimal_ull(m, ' ', mm ? get_mm_rss(mm) : 0); |
496 | seq_put_decimal_ull(m, ' ', rsslim); | 496 | seq_put_decimal_ull(m, ' ', rsslim); |
497 | 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); |
498 | 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); |
@@ -517,9 +517,23 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
517 | seq_put_decimal_ull(m, ' ', delayacct_blkio_ticks(task)); | 517 | seq_put_decimal_ull(m, ' ', delayacct_blkio_ticks(task)); |
518 | seq_put_decimal_ull(m, ' ', cputime_to_clock_t(gtime)); | 518 | seq_put_decimal_ull(m, ' ', cputime_to_clock_t(gtime)); |
519 | seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cgtime)); | 519 | seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cgtime)); |
520 | seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->start_data : 0); | 520 | |
521 | seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->end_data : 0); | 521 | if (mm && permitted) { |
522 | 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 | |||
523 | seq_putc(m, '\n'); | 537 | seq_putc(m, '\n'); |
524 | if (mm) | 538 | if (mm) |
525 | mmput(mm); | 539 | mmput(mm); |
@@ -565,3 +579,126 @@ int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns, | |||
565 | 579 | ||
566 | return 0; | 580 | return 0; |
567 | } | 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 */ | ||