array.c 17.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
/*
 *  linux/fs/proc/array.c
 *
 *  Copyright (C) 1992  by Linus Torvalds
 *  based on ideas by Darren Senn
 *
 * Fixes:
 * Michael. K. Johnson: stat,statm extensions.
 *                      <johnsonm@stolaf.edu>
 *
 * Pauline Middelink :  Made cmdline,envline only break at '\0's, to
 *                      make sure SET_PROCTITLE works. Also removed
 *                      bad '!' which forced address recalculation for
 *                      EVERY character on the current page.
 *                      <middelin@polyware.iaf.nl>
 *
 * Danny ter Haar    :	added cpuinfo
 *			<dth@cistron.nl>
 *
 * Alessandro Rubini :  profile extension.
 *                      <rubini@ipvvis.unipv.it>
 *
 * Jeff Tranter      :  added BogoMips field to cpuinfo
 *                      <Jeff_Tranter@Mitel.COM>
 *
 * Bruno Haible      :  remove 4K limit for the maps file
 *			<haible@ma2s2.mathematik.uni-karlsruhe.de>
 *
 * Yves Arrouye      :  remove removal of trailing spaces in get_array.
 *			<Yves.Arrouye@marin.fdn.fr>
 *
 * Jerome Forissier  :  added per-CPU time information to /proc/stat
 *                      and /proc/<pid>/cpu extension
 *                      <forissier@isia.cma.fr>
 *			- Incorporation and non-SMP safe operation
 *			of forissier patch in 2.1.78 by
 *			Hans Marcus <crowbar@concepts.nl>
 *
 * aeb@cwi.nl        :  /proc/partitions
 *
 *
 * Alan Cox	     :  security fixes.
A
Alan Cox 已提交
43
 *			<alan@lxorguk.ukuu.org.uk>
L
Linus Torvalds 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
 *
 * Al Viro           :  safe handling of mm_struct
 *
 * Gerhard Wichert   :  added BIGMEM support
 * Siemens AG           <Gerhard.Wichert@pdb.siemens.de>
 *
 * Al Viro & Jeff Garzik :  moved most of the thing into base.c and
 *			 :  proc_misc.c. The rest may eventually go into
 *			 :  base.c too.
 */

#include <linux/types.h>
#include <linux/errno.h>
#include <linux/time.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/tty.h>
#include <linux/string.h>
#include <linux/mman.h>
#include <linux/proc_fs.h>
#include <linux/ioport.h>
65 66
#include <linux/uaccess.h>
#include <linux/io.h>
L
Linus Torvalds 已提交
67 68 69 70 71 72 73 74
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
#include <linux/smp.h>
#include <linux/signal.h>
#include <linux/highmem.h>
#include <linux/file.h>
A
Al Viro 已提交
75
#include <linux/fdtable.h>
L
Linus Torvalds 已提交
76 77
#include <linux/times.h>
#include <linux/cpuset.h>
78
#include <linux/rcupdate.h>
79
#include <linux/delayacct.h>
80
#include <linux/seq_file.h>
81
#include <linux/pid_namespace.h>
82
#include <linux/ptrace.h>
83
#include <linux/tracehook.h>
84
#include <linux/user_namespace.h>
L
Linus Torvalds 已提交
85 86 87 88 89

#include <asm/pgtable.h>
#include <asm/processor.h>
#include "internal.h"

90
static inline void task_name(struct seq_file *m, struct task_struct *p)
L
Linus Torvalds 已提交
91 92
{
	int i;
93
	char *buf, *end;
94
	char *name;
L
Linus Torvalds 已提交
95 96 97 98
	char tcomm[sizeof(p->comm)];

	get_task_comm(tcomm, p);

99
	seq_puts(m, "Name:\t");
100 101
	end = m->buf + m->size;
	buf = m->buf + m->count;
L
Linus Torvalds 已提交
102 103
	name = tcomm;
	i = sizeof(tcomm);
104
	while (i && (buf < end)) {
L
Linus Torvalds 已提交
105 106 107 108 109 110 111
		unsigned char c = *name;
		name++;
		i--;
		*buf = c;
		if (!c)
			break;
		if (c == '\\') {
112 113 114
			buf++;
			if (buf < end)
				*buf++ = c;
L
Linus Torvalds 已提交
115 116 117
			continue;
		}
		if (c == '\n') {
118 119 120
			*buf++ = '\\';
			if (buf < end)
				*buf++ = 'n';
L
Linus Torvalds 已提交
121 122 123
			continue;
		}
		buf++;
124 125
	}
	m->count = buf - m->buf;
126
	seq_putc(m, '\n');
L
Linus Torvalds 已提交
127 128 129 130 131 132 133 134
}

/*
 * The task state array is a strange "bitmap" of
 * reasons to sleep. Thus "running" is zero, and
 * you can test for combinations of others with
 * simple bit tests.
 */
M
Mike Frysinger 已提交
135
static const char * const task_state_array[] = {
136 137 138 139 140
	"R (running)",		/*   0 */
	"S (sleeping)",		/*   1 */
	"D (disk sleep)",	/*   2 */
	"T (stopped)",		/*   4 */
	"t (tracing stop)",	/*   8 */
141 142
	"X (dead)",		/*  16 */
	"Z (zombie)",		/*  32 */
L
Linus Torvalds 已提交
143 144
};

145
static inline const char *get_task_state(struct task_struct *tsk)
L
Linus Torvalds 已提交
146
{
147
	unsigned int state = (tsk->state | tsk->exit_state) & TASK_REPORT;
L
Linus Torvalds 已提交
148

149
	BUILD_BUG_ON(1 + ilog2(TASK_REPORT) != ARRAY_SIZE(task_state_array)-1);
150

151
	return task_state_array[fls(state)];
L
Linus Torvalds 已提交
152 153
}

154 155
static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
				struct pid *pid, struct task_struct *p)
L
Linus Torvalds 已提交
156
{
157
	struct user_namespace *user_ns = seq_user_ns(m);
L
Linus Torvalds 已提交
158 159
	struct group_info *group_info;
	int g;
160
	struct task_struct *tracer;
161
	const struct cred *cred;
162
	pid_t ppid, tpid = 0, tgid, ngid;
163
	unsigned int max_fds = 0;
L
Linus Torvalds 已提交
164

165
	rcu_read_lock();
166 167
	ppid = pid_alive(p) ?
		task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0;
168 169 170 171

	tracer = ptrace_parent(p);
	if (tracer)
		tpid = task_pid_nr_ns(tracer, ns);
172 173 174

	tgid = task_tgid_nr_ns(p, ns);
	ngid = task_numa_group_id(p);
175
	cred = get_task_cred(p);
176 177 178 179 180

	task_lock(p);
	if (p->files)
		max_fds = files_fdtable(p->files)->max_fds;
	task_unlock(p);
181
	rcu_read_unlock();
182

183
	seq_printf(m,
L
Linus Torvalds 已提交
184 185
		"State:\t%s\n"
		"Tgid:\t%d\n"
186
		"Ngid:\t%d\n"
L
Linus Torvalds 已提交
187 188 189 190
		"Pid:\t%d\n"
		"PPid:\t%d\n"
		"TracerPid:\t%d\n"
		"Uid:\t%d\t%d\t%d\t%d\n"
191 192
		"Gid:\t%d\t%d\t%d\t%d\n"
		"FDSize:\t%d\nGroups:\t",
L
Linus Torvalds 已提交
193
		get_task_state(p),
194
		tgid, ngid, pid_nr_ns(pid, ns), ppid, tpid,
195 196 197 198 199 200 201
		from_kuid_munged(user_ns, cred->uid),
		from_kuid_munged(user_ns, cred->euid),
		from_kuid_munged(user_ns, cred->suid),
		from_kuid_munged(user_ns, cred->fsuid),
		from_kgid_munged(user_ns, cred->gid),
		from_kgid_munged(user_ns, cred->egid),
		from_kgid_munged(user_ns, cred->sgid),
202 203
		from_kgid_munged(user_ns, cred->fsgid),
		max_fds);
L
Linus Torvalds 已提交
204

205
	group_info = cred->group_info;
206
	for (g = 0; g < group_info->ngroups; g++)
207 208
		seq_printf(m, "%d ",
			   from_kgid_munged(user_ns, GROUP_AT(group_info, g)));
209
	put_cred(cred);
L
Linus Torvalds 已提交
210

211
	seq_putc(m, '\n');
L
Linus Torvalds 已提交
212 213
}

214
void render_sigset_t(struct seq_file *m, const char *header,
215
				sigset_t *set)
L
Linus Torvalds 已提交
216
{
217
	int i;
L
Linus Torvalds 已提交
218

219
	seq_puts(m, header);
L
Linus Torvalds 已提交
220 221 222 223 224 225 226 227 228 229

	i = _NSIG;
	do {
		int x = 0;

		i -= 4;
		if (sigismember(set, i+1)) x |= 1;
		if (sigismember(set, i+2)) x |= 2;
		if (sigismember(set, i+3)) x |= 4;
		if (sigismember(set, i+4)) x |= 8;
230
		seq_printf(m, "%x", x);
L
Linus Torvalds 已提交
231 232
	} while (i >= 4);

233
	seq_putc(m, '\n');
L
Linus Torvalds 已提交
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
}

static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
				    sigset_t *catch)
{
	struct k_sigaction *k;
	int i;

	k = p->sighand->action;
	for (i = 1; i <= _NSIG; ++i, ++k) {
		if (k->sa.sa_handler == SIG_IGN)
			sigaddset(ign, i);
		else if (k->sa.sa_handler != SIG_DFL)
			sigaddset(catch, i);
	}
}

251
static inline void task_sig(struct seq_file *m, struct task_struct *p)
L
Linus Torvalds 已提交
252
{
253
	unsigned long flags;
L
Linus Torvalds 已提交
254 255 256 257 258 259 260 261 262 263 264
	sigset_t pending, shpending, blocked, ignored, caught;
	int num_threads = 0;
	unsigned long qsize = 0;
	unsigned long qlim = 0;

	sigemptyset(&pending);
	sigemptyset(&shpending);
	sigemptyset(&blocked);
	sigemptyset(&ignored);
	sigemptyset(&caught);

265
	if (lock_task_sighand(p, &flags)) {
L
Linus Torvalds 已提交
266 267 268 269
		pending = p->pending.signal;
		shpending = p->signal->shared_pending.signal;
		blocked = p->blocked;
		collect_sigign_sigcatch(p, &ignored, &caught);
270
		num_threads = get_nr_threads(p);
271
		rcu_read_lock();  /* FIXME: is this correct? */
272
		qsize = atomic_read(&__task_cred(p)->user->sigpending);
273
		rcu_read_unlock();
J
Jiri Slaby 已提交
274
		qlim = task_rlimit(p, RLIMIT_SIGPENDING);
275
		unlock_task_sighand(p, &flags);
L
Linus Torvalds 已提交
276 277
	}

278 279
	seq_printf(m, "Threads:\t%d\n", num_threads);
	seq_printf(m, "SigQ:\t%lu/%lu\n", qsize, qlim);
L
Linus Torvalds 已提交
280 281

	/* render them all */
282 283 284 285 286
	render_sigset_t(m, "SigPnd:\t", &pending);
	render_sigset_t(m, "ShdPnd:\t", &shpending);
	render_sigset_t(m, "SigBlk:\t", &blocked);
	render_sigset_t(m, "SigIgn:\t", &ignored);
	render_sigset_t(m, "SigCgt:\t", &caught);
L
Linus Torvalds 已提交
287 288
}

289 290
static void render_cap_t(struct seq_file *m, const char *header,
			kernel_cap_t *a)
291 292 293
{
	unsigned __capi;

294
	seq_puts(m, header);
295
	CAP_FOR_EACH_U32(__capi) {
296
		seq_printf(m, "%08x",
297
			   a->cap[CAP_LAST_U32 - __capi]);
298
	}
299
	seq_putc(m, '\n');
300 301
}

302
static inline void task_cap(struct seq_file *m, struct task_struct *p)
L
Linus Torvalds 已提交
303
{
304 305
	const struct cred *cred;
	kernel_cap_t cap_inheritable, cap_permitted, cap_effective, cap_bset;
306

307 308 309 310 311 312 313 314 315 316 317 318
	rcu_read_lock();
	cred = __task_cred(p);
	cap_inheritable	= cred->cap_inheritable;
	cap_permitted	= cred->cap_permitted;
	cap_effective	= cred->cap_effective;
	cap_bset	= cred->cap_bset;
	rcu_read_unlock();

	render_cap_t(m, "CapInh:\t", &cap_inheritable);
	render_cap_t(m, "CapPrm:\t", &cap_permitted);
	render_cap_t(m, "CapEff:\t", &cap_effective);
	render_cap_t(m, "CapBnd:\t", &cap_bset);
L
Linus Torvalds 已提交
319 320
}

K
Kees Cook 已提交
321 322 323 324 325 326 327
static inline void task_seccomp(struct seq_file *m, struct task_struct *p)
{
#ifdef CONFIG_SECCOMP
	seq_printf(m, "Seccomp:\t%d\n", p->seccomp.mode);
#endif
}

328 329
static inline void task_context_switch_counts(struct seq_file *m,
						struct task_struct *p)
330
{
331 332 333 334
	seq_printf(m,	"voluntary_ctxt_switches:\t%lu\n"
			"nonvoluntary_ctxt_switches:\t%lu\n",
			p->nvcsw,
			p->nivcsw);
335 336
}

337 338
static void task_cpus_allowed(struct seq_file *m, struct task_struct *task)
{
339
	seq_puts(m, "Cpus_allowed:\t");
340
	seq_cpumask(m, &task->cpus_allowed);
341 342
	seq_putc(m, '\n');
	seq_puts(m, "Cpus_allowed_list:\t");
343
	seq_cpumask_list(m, &task->cpus_allowed);
344
	seq_putc(m, '\n');
345 346
}

347 348
int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
			struct pid *pid, struct task_struct *task)
L
Linus Torvalds 已提交
349 350 351
{
	struct mm_struct *mm = get_task_mm(task);

352 353
	task_name(m, task);
	task_state(m, ns, pid, task);
354

L
Linus Torvalds 已提交
355
	if (mm) {
356
		task_mem(m, mm);
L
Linus Torvalds 已提交
357 358
		mmput(mm);
	}
359 360
	task_sig(m, task);
	task_cap(m, task);
K
Kees Cook 已提交
361
	task_seccomp(m, task);
362
	task_cpus_allowed(m, task);
363 364 365
	cpuset_task_status_allowed(m, task);
	task_context_switch_counts(m, task);
	return 0;
L
Linus Torvalds 已提交
366 367
}

368 369
static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
			struct pid *pid, struct task_struct *task, int whole)
L
Linus Torvalds 已提交
370 371
{
	unsigned long vsize, eip, esp, wchan = ~0UL;
372
	int priority, nice;
L
Linus Torvalds 已提交
373 374 375
	int tty_pgrp = -1, tty_nr = 0;
	sigset_t sigign, sigcatch;
	char state;
376
	pid_t ppid = 0, pgid = -1, sid = -1;
L
Linus Torvalds 已提交
377
	int num_threads = 0;
378
	int permitted;
L
Linus Torvalds 已提交
379 380 381 382
	struct mm_struct *mm;
	unsigned long long start_time;
	unsigned long cmin_flt = 0, cmaj_flt = 0;
	unsigned long  min_flt = 0,  maj_flt = 0;
383
	cputime_t cutime, cstime, utime, stime;
384
	cputime_t cgtime, gtime;
L
Linus Torvalds 已提交
385 386
	unsigned long rsslim = 0;
	char tcomm[sizeof(task->comm)];
387
	unsigned long flags;
L
Linus Torvalds 已提交
388 389 390

	state = *get_task_state(task);
	vsize = eip = esp = 0;
391
	permitted = ptrace_may_access(task, PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT);
L
Linus Torvalds 已提交
392 393 394
	mm = get_task_mm(task);
	if (mm) {
		vsize = task_vsize(mm);
395 396 397 398
		if (permitted) {
			eip = KSTK_EIP(task);
			esp = KSTK_ESP(task);
		}
L
Linus Torvalds 已提交
399 400 401 402 403 404
	}

	get_task_comm(tcomm, task);

	sigemptyset(&sigign);
	sigemptyset(&sigcatch);
405 406
	cutime = cstime = utime = stime = 0;
	cgtime = gtime = 0;
407

408 409
	if (lock_task_sighand(task, &flags)) {
		struct signal_struct *sig = task->signal;
410 411

		if (sig->tty) {
412 413 414
			struct pid *pgrp = tty_get_pgrp(sig->tty);
			tty_pgrp = pid_nr_ns(pgrp, ns);
			put_pid(pgrp);
415
			tty_nr = new_encode_dev(tty_devnum(sig->tty));
416 417
		}

418
		num_threads = get_nr_threads(task);
L
Linus Torvalds 已提交
419 420
		collect_sigign_sigcatch(task, &sigign, &sigcatch);

421 422 423 424
		cmin_flt = sig->cmin_flt;
		cmaj_flt = sig->cmaj_flt;
		cutime = sig->cutime;
		cstime = sig->cstime;
425
		cgtime = sig->cgtime;
J
Jiri Slaby 已提交
426
		rsslim = ACCESS_ONCE(sig->rlim[RLIMIT_RSS].rlim_cur);
427

L
Linus Torvalds 已提交
428 429
		/* add up live thread stats at the group level */
		if (whole) {
430
			struct task_struct *t = task;
L
Linus Torvalds 已提交
431 432 433
			do {
				min_flt += t->min_flt;
				maj_flt += t->maj_flt;
434
				gtime += task_gtime(t);
435
			} while_each_thread(task, t);
L
Linus Torvalds 已提交
436

437 438
			min_flt += sig->min_flt;
			maj_flt += sig->maj_flt;
439
			thread_group_cputime_adjusted(task, &utime, &stime);
440
			gtime += sig->gtime;
L
Linus Torvalds 已提交
441
		}
442

443
		sid = task_session_nr_ns(task, ns);
444
		ppid = task_tgid_nr_ns(task->real_parent, ns);
445
		pgid = task_pgrp_nr_ns(task, ns);
446 447

		unlock_task_sighand(task, &flags);
L
Linus Torvalds 已提交
448 449
	}

450
	if (permitted && (!whole || num_threads < 2))
L
Linus Torvalds 已提交
451 452 453 454
		wchan = get_wchan(task);
	if (!whole) {
		min_flt = task->min_flt;
		maj_flt = task->maj_flt;
455
		task_cputime_adjusted(task, &utime, &stime);
456
		gtime = task_gtime(task);
L
Linus Torvalds 已提交
457 458 459 460 461 462 463 464
	}

	/* scale priority and nice values from timeslices to -20..20 */
	/* to make it look like a "normal" Unix priority/nice value  */
	priority = task_prio(task);
	nice = task_nice(task);

	/* convert nsec -> ticks */
465
	start_time = nsec_to_clock_t(task->real_start_time);
L
Linus Torvalds 已提交
466

467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
	seq_printf(m, "%d (%s) %c", pid_nr_ns(pid, ns), tcomm, state);
	seq_put_decimal_ll(m, ' ', ppid);
	seq_put_decimal_ll(m, ' ', pgid);
	seq_put_decimal_ll(m, ' ', sid);
	seq_put_decimal_ll(m, ' ', tty_nr);
	seq_put_decimal_ll(m, ' ', tty_pgrp);
	seq_put_decimal_ull(m, ' ', task->flags);
	seq_put_decimal_ull(m, ' ', min_flt);
	seq_put_decimal_ull(m, ' ', cmin_flt);
	seq_put_decimal_ull(m, ' ', maj_flt);
	seq_put_decimal_ull(m, ' ', cmaj_flt);
	seq_put_decimal_ull(m, ' ', cputime_to_clock_t(utime));
	seq_put_decimal_ull(m, ' ', cputime_to_clock_t(stime));
	seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cutime));
	seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cstime));
	seq_put_decimal_ll(m, ' ', priority);
	seq_put_decimal_ll(m, ' ', nice);
	seq_put_decimal_ll(m, ' ', num_threads);
	seq_put_decimal_ull(m, ' ', 0);
	seq_put_decimal_ull(m, ' ', start_time);
	seq_put_decimal_ull(m, ' ', vsize);
488
	seq_put_decimal_ull(m, ' ', mm ? get_mm_rss(mm) : 0);
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
	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);
	seq_put_decimal_ull(m, ' ', (permitted && mm) ? mm->start_stack : 0);
	seq_put_decimal_ull(m, ' ', esp);
	seq_put_decimal_ull(m, ' ', eip);
	/* The signal information here is obsolete.
	 * It must be decimal for Linux 2.0 compatibility.
	 * Use /proc/#/status for real-time signals.
	 */
	seq_put_decimal_ull(m, ' ', task->pending.signal.sig[0] & 0x7fffffffUL);
	seq_put_decimal_ull(m, ' ', task->blocked.sig[0] & 0x7fffffffUL);
	seq_put_decimal_ull(m, ' ', sigign.sig[0] & 0x7fffffffUL);
	seq_put_decimal_ull(m, ' ', sigcatch.sig[0] & 0x7fffffffUL);
	seq_put_decimal_ull(m, ' ', wchan);
	seq_put_decimal_ull(m, ' ', 0);
	seq_put_decimal_ull(m, ' ', 0);
	seq_put_decimal_ll(m, ' ', task->exit_signal);
	seq_put_decimal_ll(m, ' ', task_cpu(task));
	seq_put_decimal_ull(m, ' ', task->rt_priority);
	seq_put_decimal_ull(m, ' ', task->policy);
	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));
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529

	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);

530
	seq_putc(m, '\n');
531
	if (mm)
L
Linus Torvalds 已提交
532
		mmput(mm);
533
	return 0;
L
Linus Torvalds 已提交
534 535
}

536 537
int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns,
			struct pid *pid, struct task_struct *task)
L
Linus Torvalds 已提交
538
{
539
	return do_task_stat(m, ns, pid, task, 0);
L
Linus Torvalds 已提交
540 541
}

542 543
int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns,
			struct pid *pid, struct task_struct *task)
L
Linus Torvalds 已提交
544
{
545
	return do_task_stat(m, ns, pid, task, 1);
L
Linus Torvalds 已提交
546 547
}

548 549
int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns,
			struct pid *pid, struct task_struct *task)
L
Linus Torvalds 已提交
550
{
551
	unsigned long size = 0, resident = 0, shared = 0, text = 0, data = 0;
L
Linus Torvalds 已提交
552
	struct mm_struct *mm = get_task_mm(task);
553

L
Linus Torvalds 已提交
554 555 556 557
	if (mm) {
		size = task_statm(mm, &shared, &text, &data, &resident);
		mmput(mm);
	}
558 559 560 561 562 563 564 565 566 567 568
	/*
	 * For quick read, open code by putting numbers directly
	 * expected format is
	 * seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n",
	 *               size, resident, shared, text, data);
	 */
	seq_put_decimal_ull(m, 0, size);
	seq_put_decimal_ull(m, ' ', resident);
	seq_put_decimal_ull(m, ' ', shared);
	seq_put_decimal_ull(m, ' ', text);
	seq_put_decimal_ull(m, ' ', 0);
K
KAMEZAWA Hiroyuki 已提交
569
	seq_put_decimal_ull(m, ' ', data);
570 571
	seq_put_decimal_ull(m, ' ', 0);
	seq_putc(m, '\n');
L
Linus Torvalds 已提交
572

573
	return 0;
L
Linus Torvalds 已提交
574
}
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697

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