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 */ | ||
