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 dc4c5a7b9ec..c1c207c36ca 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,  			struct pid *pid, struct task_struct *task, int whole)  {  	unsigned long vsize, eip, esp, wchan = ~0UL; -	long priority, nice; +	int priority, nice;  	int tty_pgrp = -1, tty_nr = 0;  	sigset_t sigign, sigcatch;  	char state; @@ -492,7 +492,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,  	seq_put_decimal_ull(m, ' ', 0);  	seq_put_decimal_ull(m, ' ', start_time);  	seq_put_decimal_ull(m, ' ', vsize); -	seq_put_decimal_ll(m, ' ', mm ? get_mm_rss(mm) : 0); +	seq_put_decimal_ull(m, ' ', mm ? get_mm_rss(mm) : 0);  	seq_put_decimal_ull(m, ' ', rsslim);  	seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->start_code : 1) : 0);  	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,  	seq_put_decimal_ull(m, ' ', delayacct_blkio_ticks(task));  	seq_put_decimal_ull(m, ' ', cputime_to_clock_t(gtime));  	seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cgtime)); -	seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->start_data : 0); -	seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->end_data : 0); -	seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->start_brk : 0); + +	if (mm && permitted) { +		seq_put_decimal_ull(m, ' ', mm->start_data); +		seq_put_decimal_ull(m, ' ', mm->end_data); +		seq_put_decimal_ull(m, ' ', mm->start_brk); +		seq_put_decimal_ull(m, ' ', mm->arg_start); +		seq_put_decimal_ull(m, ' ', mm->arg_end); +		seq_put_decimal_ull(m, ' ', mm->env_start); +		seq_put_decimal_ull(m, ' ', mm->env_end); +	} else +		seq_printf(m, " 0 0 0 0 0 0 0"); + +	if (permitted) +		seq_put_decimal_ll(m, ' ', task->exit_code); +	else +		seq_put_decimal_ll(m, ' ', 0); +  	seq_putc(m, '\n');  	if (mm)  		mmput(mm); @@ -565,3 +579,126 @@ int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns,  	return 0;  } + +#ifdef CONFIG_CHECKPOINT_RESTORE +static struct pid * +get_children_pid(struct inode *inode, struct pid *pid_prev, loff_t pos) +{ +	struct task_struct *start, *task; +	struct pid *pid = NULL; + +	read_lock(&tasklist_lock); + +	start = pid_task(proc_pid(inode), PIDTYPE_PID); +	if (!start) +		goto out; + +	/* +	 * Lets try to continue searching first, this gives +	 * us significant speedup on children-rich processes. +	 */ +	if (pid_prev) { +		task = pid_task(pid_prev, PIDTYPE_PID); +		if (task && task->real_parent == start && +		    !(list_empty(&task->sibling))) { +			if (list_is_last(&task->sibling, &start->children)) +				goto out; +			task = list_first_entry(&task->sibling, +						struct task_struct, sibling); +			pid = get_pid(task_pid(task)); +			goto out; +		} +	} + +	/* +	 * Slow search case. +	 * +	 * We might miss some children here if children +	 * are exited while we were not holding the lock, +	 * but it was never promised to be accurate that +	 * much. +	 * +	 * "Just suppose that the parent sleeps, but N children +	 *  exit after we printed their tids. Now the slow paths +	 *  skips N extra children, we miss N tasks." (c) +	 * +	 * So one need to stop or freeze the leader and all +	 * its children to get a precise result. +	 */ +	list_for_each_entry(task, &start->children, sibling) { +		if (pos-- == 0) { +			pid = get_pid(task_pid(task)); +			break; +		} +	} + +out: +	read_unlock(&tasklist_lock); +	return pid; +} + +static int children_seq_show(struct seq_file *seq, void *v) +{ +	struct inode *inode = seq->private; +	pid_t pid; + +	pid = pid_nr_ns(v, inode->i_sb->s_fs_info); +	return seq_printf(seq, "%d ", pid); +} + +static void *children_seq_start(struct seq_file *seq, loff_t *pos) +{ +	return get_children_pid(seq->private, NULL, *pos); +} + +static void *children_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ +	struct pid *pid; + +	pid = get_children_pid(seq->private, v, *pos + 1); +	put_pid(v); + +	++*pos; +	return pid; +} + +static void children_seq_stop(struct seq_file *seq, void *v) +{ +	put_pid(v); +} + +static const struct seq_operations children_seq_ops = { +	.start	= children_seq_start, +	.next	= children_seq_next, +	.stop	= children_seq_stop, +	.show	= children_seq_show, +}; + +static int children_seq_open(struct inode *inode, struct file *file) +{ +	struct seq_file *m; +	int ret; + +	ret = seq_open(file, &children_seq_ops); +	if (ret) +		return ret; + +	m = file->private_data; +	m->private = inode; + +	return ret; +} + +int children_seq_release(struct inode *inode, struct file *file) +{ +	seq_release(inode, file); +	return 0; +} + +const struct file_operations proc_tid_children_operations = { +	.open    = children_seq_open, +	.read    = seq_read, +	.llseek  = seq_lseek, +	.release = children_seq_release, +}; +#endif /* CONFIG_CHECKPOINT_RESTORE */  |