162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/fs/proc/array.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 1992  by Linus Torvalds
662306a36Sopenharmony_ci *  based on ideas by Darren Senn
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Fixes:
962306a36Sopenharmony_ci * Michael. K. Johnson: stat,statm extensions.
1062306a36Sopenharmony_ci *                      <johnsonm@stolaf.edu>
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Pauline Middelink :  Made cmdline,envline only break at '\0's, to
1362306a36Sopenharmony_ci *                      make sure SET_PROCTITLE works. Also removed
1462306a36Sopenharmony_ci *                      bad '!' which forced address recalculation for
1562306a36Sopenharmony_ci *                      EVERY character on the current page.
1662306a36Sopenharmony_ci *                      <middelin@polyware.iaf.nl>
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * Danny ter Haar    :	added cpuinfo
1962306a36Sopenharmony_ci *			<dth@cistron.nl>
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * Alessandro Rubini :  profile extension.
2262306a36Sopenharmony_ci *                      <rubini@ipvvis.unipv.it>
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * Jeff Tranter      :  added BogoMips field to cpuinfo
2562306a36Sopenharmony_ci *                      <Jeff_Tranter@Mitel.COM>
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * Bruno Haible      :  remove 4K limit for the maps file
2862306a36Sopenharmony_ci *			<haible@ma2s2.mathematik.uni-karlsruhe.de>
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * Yves Arrouye      :  remove removal of trailing spaces in get_array.
3162306a36Sopenharmony_ci *			<Yves.Arrouye@marin.fdn.fr>
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * Jerome Forissier  :  added per-CPU time information to /proc/stat
3462306a36Sopenharmony_ci *                      and /proc/<pid>/cpu extension
3562306a36Sopenharmony_ci *                      <forissier@isia.cma.fr>
3662306a36Sopenharmony_ci *			- Incorporation and non-SMP safe operation
3762306a36Sopenharmony_ci *			of forissier patch in 2.1.78 by
3862306a36Sopenharmony_ci *			Hans Marcus <crowbar@concepts.nl>
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * aeb@cwi.nl        :  /proc/partitions
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * Alan Cox	     :  security fixes.
4462306a36Sopenharmony_ci *			<alan@lxorguk.ukuu.org.uk>
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci * Al Viro           :  safe handling of mm_struct
4762306a36Sopenharmony_ci *
4862306a36Sopenharmony_ci * Gerhard Wichert   :  added BIGMEM support
4962306a36Sopenharmony_ci * Siemens AG           <Gerhard.Wichert@pdb.siemens.de>
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * Al Viro & Jeff Garzik :  moved most of the thing into base.c and
5262306a36Sopenharmony_ci *			 :  proc_misc.c. The rest may eventually go into
5362306a36Sopenharmony_ci *			 :  base.c too.
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#include <linux/types.h>
5762306a36Sopenharmony_ci#include <linux/errno.h>
5862306a36Sopenharmony_ci#include <linux/time.h>
5962306a36Sopenharmony_ci#include <linux/time_namespace.h>
6062306a36Sopenharmony_ci#include <linux/kernel.h>
6162306a36Sopenharmony_ci#include <linux/kernel_stat.h>
6262306a36Sopenharmony_ci#include <linux/tty.h>
6362306a36Sopenharmony_ci#include <linux/string.h>
6462306a36Sopenharmony_ci#include <linux/mman.h>
6562306a36Sopenharmony_ci#include <linux/sched/mm.h>
6662306a36Sopenharmony_ci#include <linux/sched/numa_balancing.h>
6762306a36Sopenharmony_ci#include <linux/sched/task_stack.h>
6862306a36Sopenharmony_ci#include <linux/sched/task.h>
6962306a36Sopenharmony_ci#include <linux/sched/cputime.h>
7062306a36Sopenharmony_ci#include <linux/proc_fs.h>
7162306a36Sopenharmony_ci#include <linux/ioport.h>
7262306a36Sopenharmony_ci#include <linux/io.h>
7362306a36Sopenharmony_ci#include <linux/mm.h>
7462306a36Sopenharmony_ci#include <linux/hugetlb.h>
7562306a36Sopenharmony_ci#include <linux/pagemap.h>
7662306a36Sopenharmony_ci#include <linux/swap.h>
7762306a36Sopenharmony_ci#include <linux/smp.h>
7862306a36Sopenharmony_ci#include <linux/signal.h>
7962306a36Sopenharmony_ci#include <linux/highmem.h>
8062306a36Sopenharmony_ci#include <linux/file.h>
8162306a36Sopenharmony_ci#include <linux/fdtable.h>
8262306a36Sopenharmony_ci#include <linux/times.h>
8362306a36Sopenharmony_ci#include <linux/cpuset.h>
8462306a36Sopenharmony_ci#include <linux/rcupdate.h>
8562306a36Sopenharmony_ci#include <linux/delayacct.h>
8662306a36Sopenharmony_ci#include <linux/seq_file.h>
8762306a36Sopenharmony_ci#include <linux/pid_namespace.h>
8862306a36Sopenharmony_ci#include <linux/prctl.h>
8962306a36Sopenharmony_ci#include <linux/ptrace.h>
9062306a36Sopenharmony_ci#include <linux/string_helpers.h>
9162306a36Sopenharmony_ci#include <linux/user_namespace.h>
9262306a36Sopenharmony_ci#include <linux/fs_struct.h>
9362306a36Sopenharmony_ci#include <linux/kthread.h>
9462306a36Sopenharmony_ci#include <linux/mmu_context.h>
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#include <asm/processor.h>
9762306a36Sopenharmony_ci#include "internal.h"
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_civoid proc_task_name(struct seq_file *m, struct task_struct *p, bool escape)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	char tcomm[64];
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	/*
10462306a36Sopenharmony_ci	 * Test before PF_KTHREAD because all workqueue worker threads are
10562306a36Sopenharmony_ci	 * kernel threads.
10662306a36Sopenharmony_ci	 */
10762306a36Sopenharmony_ci	if (p->flags & PF_WQ_WORKER)
10862306a36Sopenharmony_ci		wq_worker_comm(tcomm, sizeof(tcomm), p);
10962306a36Sopenharmony_ci	else if (p->flags & PF_KTHREAD)
11062306a36Sopenharmony_ci		get_kthread_comm(tcomm, sizeof(tcomm), p);
11162306a36Sopenharmony_ci	else
11262306a36Sopenharmony_ci		__get_task_comm(tcomm, sizeof(tcomm), p);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	if (escape)
11562306a36Sopenharmony_ci		seq_escape_str(m, tcomm, ESCAPE_SPACE | ESCAPE_SPECIAL, "\n\\");
11662306a36Sopenharmony_ci	else
11762306a36Sopenharmony_ci		seq_printf(m, "%.64s", tcomm);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/*
12162306a36Sopenharmony_ci * The task state array is a strange "bitmap" of
12262306a36Sopenharmony_ci * reasons to sleep. Thus "running" is zero, and
12362306a36Sopenharmony_ci * you can test for combinations of others with
12462306a36Sopenharmony_ci * simple bit tests.
12562306a36Sopenharmony_ci */
12662306a36Sopenharmony_cistatic const char * const task_state_array[] = {
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* states in TASK_REPORT: */
12962306a36Sopenharmony_ci	"R (running)",		/* 0x00 */
13062306a36Sopenharmony_ci	"S (sleeping)",		/* 0x01 */
13162306a36Sopenharmony_ci	"D (disk sleep)",	/* 0x02 */
13262306a36Sopenharmony_ci	"T (stopped)",		/* 0x04 */
13362306a36Sopenharmony_ci	"t (tracing stop)",	/* 0x08 */
13462306a36Sopenharmony_ci	"X (dead)",		/* 0x10 */
13562306a36Sopenharmony_ci	"Z (zombie)",		/* 0x20 */
13662306a36Sopenharmony_ci	"P (parked)",		/* 0x40 */
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/* states beyond TASK_REPORT: */
13962306a36Sopenharmony_ci	"I (idle)",		/* 0x80 */
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic inline const char *get_task_state(struct task_struct *tsk)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	BUILD_BUG_ON(1 + ilog2(TASK_REPORT_MAX) != ARRAY_SIZE(task_state_array));
14562306a36Sopenharmony_ci	return task_state_array[task_state_index(tsk)];
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic inline void task_state(struct seq_file *m, struct pid_namespace *ns,
14962306a36Sopenharmony_ci				struct pid *pid, struct task_struct *p)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct user_namespace *user_ns = seq_user_ns(m);
15262306a36Sopenharmony_ci	struct group_info *group_info;
15362306a36Sopenharmony_ci	int g, umask = -1;
15462306a36Sopenharmony_ci	struct task_struct *tracer;
15562306a36Sopenharmony_ci	const struct cred *cred;
15662306a36Sopenharmony_ci	pid_t ppid, tpid = 0, tgid, ngid;
15762306a36Sopenharmony_ci	unsigned int max_fds = 0;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	rcu_read_lock();
16062306a36Sopenharmony_ci	ppid = pid_alive(p) ?
16162306a36Sopenharmony_ci		task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	tracer = ptrace_parent(p);
16462306a36Sopenharmony_ci	if (tracer)
16562306a36Sopenharmony_ci		tpid = task_pid_nr_ns(tracer, ns);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	tgid = task_tgid_nr_ns(p, ns);
16862306a36Sopenharmony_ci	ngid = task_numa_group_id(p);
16962306a36Sopenharmony_ci	cred = get_task_cred(p);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	task_lock(p);
17262306a36Sopenharmony_ci	if (p->fs)
17362306a36Sopenharmony_ci		umask = p->fs->umask;
17462306a36Sopenharmony_ci	if (p->files)
17562306a36Sopenharmony_ci		max_fds = files_fdtable(p->files)->max_fds;
17662306a36Sopenharmony_ci	task_unlock(p);
17762306a36Sopenharmony_ci	rcu_read_unlock();
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (umask >= 0)
18062306a36Sopenharmony_ci		seq_printf(m, "Umask:\t%#04o\n", umask);
18162306a36Sopenharmony_ci	seq_puts(m, "State:\t");
18262306a36Sopenharmony_ci	seq_puts(m, get_task_state(p));
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\nTgid:\t", tgid);
18562306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\nNgid:\t", ngid);
18662306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\nPid:\t", pid_nr_ns(pid, ns));
18762306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\nPPid:\t", ppid);
18862306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\nTracerPid:\t", tpid);
18962306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\nUid:\t", from_kuid_munged(user_ns, cred->uid));
19062306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->euid));
19162306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->suid));
19262306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->fsuid));
19362306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\nGid:\t", from_kgid_munged(user_ns, cred->gid));
19462306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->egid));
19562306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->sgid));
19662306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->fsgid));
19762306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\nFDSize:\t", max_fds);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	seq_puts(m, "\nGroups:\t");
20062306a36Sopenharmony_ci	group_info = cred->group_info;
20162306a36Sopenharmony_ci	for (g = 0; g < group_info->ngroups; g++)
20262306a36Sopenharmony_ci		seq_put_decimal_ull(m, g ? " " : "",
20362306a36Sopenharmony_ci				from_kgid_munged(user_ns, group_info->gid[g]));
20462306a36Sopenharmony_ci	put_cred(cred);
20562306a36Sopenharmony_ci	/* Trailing space shouldn't have been added in the first place. */
20662306a36Sopenharmony_ci	seq_putc(m, ' ');
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci#ifdef CONFIG_PID_NS
20962306a36Sopenharmony_ci	seq_puts(m, "\nNStgid:");
21062306a36Sopenharmony_ci	for (g = ns->level; g <= pid->level; g++)
21162306a36Sopenharmony_ci		seq_put_decimal_ull(m, "\t", task_tgid_nr_ns(p, pid->numbers[g].ns));
21262306a36Sopenharmony_ci	seq_puts(m, "\nNSpid:");
21362306a36Sopenharmony_ci	for (g = ns->level; g <= pid->level; g++)
21462306a36Sopenharmony_ci		seq_put_decimal_ull(m, "\t", task_pid_nr_ns(p, pid->numbers[g].ns));
21562306a36Sopenharmony_ci	seq_puts(m, "\nNSpgid:");
21662306a36Sopenharmony_ci	for (g = ns->level; g <= pid->level; g++)
21762306a36Sopenharmony_ci		seq_put_decimal_ull(m, "\t", task_pgrp_nr_ns(p, pid->numbers[g].ns));
21862306a36Sopenharmony_ci	seq_puts(m, "\nNSsid:");
21962306a36Sopenharmony_ci	for (g = ns->level; g <= pid->level; g++)
22062306a36Sopenharmony_ci		seq_put_decimal_ull(m, "\t", task_session_nr_ns(p, pid->numbers[g].ns));
22162306a36Sopenharmony_ci#endif
22262306a36Sopenharmony_ci	seq_putc(m, '\n');
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	seq_printf(m, "Kthread:\t%c\n", p->flags & PF_KTHREAD ? '1' : '0');
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_civoid render_sigset_t(struct seq_file *m, const char *header,
22862306a36Sopenharmony_ci				sigset_t *set)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	int i;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	seq_puts(m, header);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	i = _NSIG;
23562306a36Sopenharmony_ci	do {
23662306a36Sopenharmony_ci		int x = 0;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		i -= 4;
23962306a36Sopenharmony_ci		if (sigismember(set, i+1)) x |= 1;
24062306a36Sopenharmony_ci		if (sigismember(set, i+2)) x |= 2;
24162306a36Sopenharmony_ci		if (sigismember(set, i+3)) x |= 4;
24262306a36Sopenharmony_ci		if (sigismember(set, i+4)) x |= 8;
24362306a36Sopenharmony_ci		seq_putc(m, hex_asc[x]);
24462306a36Sopenharmony_ci	} while (i >= 4);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	seq_putc(m, '\n');
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic void collect_sigign_sigcatch(struct task_struct *p, sigset_t *sigign,
25062306a36Sopenharmony_ci				    sigset_t *sigcatch)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct k_sigaction *k;
25362306a36Sopenharmony_ci	int i;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	k = p->sighand->action;
25662306a36Sopenharmony_ci	for (i = 1; i <= _NSIG; ++i, ++k) {
25762306a36Sopenharmony_ci		if (k->sa.sa_handler == SIG_IGN)
25862306a36Sopenharmony_ci			sigaddset(sigign, i);
25962306a36Sopenharmony_ci		else if (k->sa.sa_handler != SIG_DFL)
26062306a36Sopenharmony_ci			sigaddset(sigcatch, i);
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic inline void task_sig(struct seq_file *m, struct task_struct *p)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	unsigned long flags;
26762306a36Sopenharmony_ci	sigset_t pending, shpending, blocked, ignored, caught;
26862306a36Sopenharmony_ci	int num_threads = 0;
26962306a36Sopenharmony_ci	unsigned int qsize = 0;
27062306a36Sopenharmony_ci	unsigned long qlim = 0;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	sigemptyset(&pending);
27362306a36Sopenharmony_ci	sigemptyset(&shpending);
27462306a36Sopenharmony_ci	sigemptyset(&blocked);
27562306a36Sopenharmony_ci	sigemptyset(&ignored);
27662306a36Sopenharmony_ci	sigemptyset(&caught);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	if (lock_task_sighand(p, &flags)) {
27962306a36Sopenharmony_ci		pending = p->pending.signal;
28062306a36Sopenharmony_ci		shpending = p->signal->shared_pending.signal;
28162306a36Sopenharmony_ci		blocked = p->blocked;
28262306a36Sopenharmony_ci		collect_sigign_sigcatch(p, &ignored, &caught);
28362306a36Sopenharmony_ci		num_threads = get_nr_threads(p);
28462306a36Sopenharmony_ci		rcu_read_lock();  /* FIXME: is this correct? */
28562306a36Sopenharmony_ci		qsize = get_rlimit_value(task_ucounts(p), UCOUNT_RLIMIT_SIGPENDING);
28662306a36Sopenharmony_ci		rcu_read_unlock();
28762306a36Sopenharmony_ci		qlim = task_rlimit(p, RLIMIT_SIGPENDING);
28862306a36Sopenharmony_ci		unlock_task_sighand(p, &flags);
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	seq_put_decimal_ull(m, "Threads:\t", num_threads);
29262306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\nSigQ:\t", qsize);
29362306a36Sopenharmony_ci	seq_put_decimal_ull(m, "/", qlim);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	/* render them all */
29662306a36Sopenharmony_ci	render_sigset_t(m, "\nSigPnd:\t", &pending);
29762306a36Sopenharmony_ci	render_sigset_t(m, "ShdPnd:\t", &shpending);
29862306a36Sopenharmony_ci	render_sigset_t(m, "SigBlk:\t", &blocked);
29962306a36Sopenharmony_ci	render_sigset_t(m, "SigIgn:\t", &ignored);
30062306a36Sopenharmony_ci	render_sigset_t(m, "SigCgt:\t", &caught);
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic void render_cap_t(struct seq_file *m, const char *header,
30462306a36Sopenharmony_ci			kernel_cap_t *a)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	seq_puts(m, header);
30762306a36Sopenharmony_ci	seq_put_hex_ll(m, NULL, a->val, 16);
30862306a36Sopenharmony_ci	seq_putc(m, '\n');
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic inline void task_cap(struct seq_file *m, struct task_struct *p)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	const struct cred *cred;
31462306a36Sopenharmony_ci	kernel_cap_t cap_inheritable, cap_permitted, cap_effective,
31562306a36Sopenharmony_ci			cap_bset, cap_ambient;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	rcu_read_lock();
31862306a36Sopenharmony_ci	cred = __task_cred(p);
31962306a36Sopenharmony_ci	cap_inheritable	= cred->cap_inheritable;
32062306a36Sopenharmony_ci	cap_permitted	= cred->cap_permitted;
32162306a36Sopenharmony_ci	cap_effective	= cred->cap_effective;
32262306a36Sopenharmony_ci	cap_bset	= cred->cap_bset;
32362306a36Sopenharmony_ci	cap_ambient	= cred->cap_ambient;
32462306a36Sopenharmony_ci	rcu_read_unlock();
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	render_cap_t(m, "CapInh:\t", &cap_inheritable);
32762306a36Sopenharmony_ci	render_cap_t(m, "CapPrm:\t", &cap_permitted);
32862306a36Sopenharmony_ci	render_cap_t(m, "CapEff:\t", &cap_effective);
32962306a36Sopenharmony_ci	render_cap_t(m, "CapBnd:\t", &cap_bset);
33062306a36Sopenharmony_ci	render_cap_t(m, "CapAmb:\t", &cap_ambient);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic inline void task_seccomp(struct seq_file *m, struct task_struct *p)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	seq_put_decimal_ull(m, "NoNewPrivs:\t", task_no_new_privs(p));
33662306a36Sopenharmony_ci#ifdef CONFIG_SECCOMP
33762306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\nSeccomp:\t", p->seccomp.mode);
33862306a36Sopenharmony_ci#ifdef CONFIG_SECCOMP_FILTER
33962306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\nSeccomp_filters:\t",
34062306a36Sopenharmony_ci			    atomic_read(&p->seccomp.filter_count));
34162306a36Sopenharmony_ci#endif
34262306a36Sopenharmony_ci#endif
34362306a36Sopenharmony_ci	seq_puts(m, "\nSpeculation_Store_Bypass:\t");
34462306a36Sopenharmony_ci	switch (arch_prctl_spec_ctrl_get(p, PR_SPEC_STORE_BYPASS)) {
34562306a36Sopenharmony_ci	case -EINVAL:
34662306a36Sopenharmony_ci		seq_puts(m, "unknown");
34762306a36Sopenharmony_ci		break;
34862306a36Sopenharmony_ci	case PR_SPEC_NOT_AFFECTED:
34962306a36Sopenharmony_ci		seq_puts(m, "not vulnerable");
35062306a36Sopenharmony_ci		break;
35162306a36Sopenharmony_ci	case PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE:
35262306a36Sopenharmony_ci		seq_puts(m, "thread force mitigated");
35362306a36Sopenharmony_ci		break;
35462306a36Sopenharmony_ci	case PR_SPEC_PRCTL | PR_SPEC_DISABLE:
35562306a36Sopenharmony_ci		seq_puts(m, "thread mitigated");
35662306a36Sopenharmony_ci		break;
35762306a36Sopenharmony_ci	case PR_SPEC_PRCTL | PR_SPEC_ENABLE:
35862306a36Sopenharmony_ci		seq_puts(m, "thread vulnerable");
35962306a36Sopenharmony_ci		break;
36062306a36Sopenharmony_ci	case PR_SPEC_DISABLE:
36162306a36Sopenharmony_ci		seq_puts(m, "globally mitigated");
36262306a36Sopenharmony_ci		break;
36362306a36Sopenharmony_ci	default:
36462306a36Sopenharmony_ci		seq_puts(m, "vulnerable");
36562306a36Sopenharmony_ci		break;
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	seq_puts(m, "\nSpeculationIndirectBranch:\t");
36962306a36Sopenharmony_ci	switch (arch_prctl_spec_ctrl_get(p, PR_SPEC_INDIRECT_BRANCH)) {
37062306a36Sopenharmony_ci	case -EINVAL:
37162306a36Sopenharmony_ci		seq_puts(m, "unsupported");
37262306a36Sopenharmony_ci		break;
37362306a36Sopenharmony_ci	case PR_SPEC_NOT_AFFECTED:
37462306a36Sopenharmony_ci		seq_puts(m, "not affected");
37562306a36Sopenharmony_ci		break;
37662306a36Sopenharmony_ci	case PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE:
37762306a36Sopenharmony_ci		seq_puts(m, "conditional force disabled");
37862306a36Sopenharmony_ci		break;
37962306a36Sopenharmony_ci	case PR_SPEC_PRCTL | PR_SPEC_DISABLE:
38062306a36Sopenharmony_ci		seq_puts(m, "conditional disabled");
38162306a36Sopenharmony_ci		break;
38262306a36Sopenharmony_ci	case PR_SPEC_PRCTL | PR_SPEC_ENABLE:
38362306a36Sopenharmony_ci		seq_puts(m, "conditional enabled");
38462306a36Sopenharmony_ci		break;
38562306a36Sopenharmony_ci	case PR_SPEC_ENABLE:
38662306a36Sopenharmony_ci		seq_puts(m, "always enabled");
38762306a36Sopenharmony_ci		break;
38862306a36Sopenharmony_ci	case PR_SPEC_DISABLE:
38962306a36Sopenharmony_ci		seq_puts(m, "always disabled");
39062306a36Sopenharmony_ci		break;
39162306a36Sopenharmony_ci	default:
39262306a36Sopenharmony_ci		seq_puts(m, "unknown");
39362306a36Sopenharmony_ci		break;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci	seq_putc(m, '\n');
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic inline void task_context_switch_counts(struct seq_file *m,
39962306a36Sopenharmony_ci						struct task_struct *p)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw);
40262306a36Sopenharmony_ci	seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw);
40362306a36Sopenharmony_ci	seq_putc(m, '\n');
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic void task_cpus_allowed(struct seq_file *m, struct task_struct *task)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	seq_printf(m, "Cpus_allowed:\t%*pb\n",
40962306a36Sopenharmony_ci		   cpumask_pr_args(&task->cpus_mask));
41062306a36Sopenharmony_ci	seq_printf(m, "Cpus_allowed_list:\t%*pbl\n",
41162306a36Sopenharmony_ci		   cpumask_pr_args(&task->cpus_mask));
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic inline void task_core_dumping(struct seq_file *m, struct task_struct *task)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	seq_put_decimal_ull(m, "CoreDumping:\t", !!task->signal->core_state);
41762306a36Sopenharmony_ci	seq_putc(m, '\n');
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic inline void task_thp_status(struct seq_file *m, struct mm_struct *mm)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	bool thp_enabled = IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	if (thp_enabled)
42562306a36Sopenharmony_ci		thp_enabled = !test_bit(MMF_DISABLE_THP, &mm->flags);
42662306a36Sopenharmony_ci	seq_printf(m, "THP_enabled:\t%d\n", thp_enabled);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic inline void task_untag_mask(struct seq_file *m, struct mm_struct *mm)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	seq_printf(m, "untag_mask:\t%#lx\n", mm_untag_mask(mm));
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci__weak void arch_proc_pid_thread_features(struct seq_file *m,
43562306a36Sopenharmony_ci					  struct task_struct *task)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ciint proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
44062306a36Sopenharmony_ci			struct pid *pid, struct task_struct *task)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct mm_struct *mm = get_task_mm(task);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	seq_puts(m, "Name:\t");
44562306a36Sopenharmony_ci	proc_task_name(m, task, true);
44662306a36Sopenharmony_ci	seq_putc(m, '\n');
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	task_state(m, ns, pid, task);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (mm) {
45162306a36Sopenharmony_ci		task_mem(m, mm);
45262306a36Sopenharmony_ci		task_core_dumping(m, task);
45362306a36Sopenharmony_ci		task_thp_status(m, mm);
45462306a36Sopenharmony_ci		task_untag_mask(m, mm);
45562306a36Sopenharmony_ci		mmput(mm);
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci	task_sig(m, task);
45862306a36Sopenharmony_ci	task_cap(m, task);
45962306a36Sopenharmony_ci	task_seccomp(m, task);
46062306a36Sopenharmony_ci	task_cpus_allowed(m, task);
46162306a36Sopenharmony_ci	cpuset_task_status_allowed(m, task);
46262306a36Sopenharmony_ci	task_context_switch_counts(m, task);
46362306a36Sopenharmony_ci	arch_proc_pid_thread_features(m, task);
46462306a36Sopenharmony_ci	return 0;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
46862306a36Sopenharmony_ci			struct pid *pid, struct task_struct *task, int whole)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	unsigned long vsize, eip, esp, wchan = 0;
47162306a36Sopenharmony_ci	int priority, nice;
47262306a36Sopenharmony_ci	int tty_pgrp = -1, tty_nr = 0;
47362306a36Sopenharmony_ci	sigset_t sigign, sigcatch;
47462306a36Sopenharmony_ci	char state;
47562306a36Sopenharmony_ci	pid_t ppid = 0, pgid = -1, sid = -1;
47662306a36Sopenharmony_ci	int num_threads = 0;
47762306a36Sopenharmony_ci	int permitted;
47862306a36Sopenharmony_ci	struct mm_struct *mm;
47962306a36Sopenharmony_ci	unsigned long long start_time;
48062306a36Sopenharmony_ci	unsigned long cmin_flt = 0, cmaj_flt = 0;
48162306a36Sopenharmony_ci	unsigned long  min_flt = 0,  maj_flt = 0;
48262306a36Sopenharmony_ci	u64 cutime, cstime, utime, stime;
48362306a36Sopenharmony_ci	u64 cgtime, gtime;
48462306a36Sopenharmony_ci	unsigned long rsslim = 0;
48562306a36Sopenharmony_ci	unsigned long flags;
48662306a36Sopenharmony_ci	int exit_code = task->exit_code;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	state = *get_task_state(task);
48962306a36Sopenharmony_ci	vsize = eip = esp = 0;
49062306a36Sopenharmony_ci	permitted = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS | PTRACE_MODE_NOAUDIT);
49162306a36Sopenharmony_ci	mm = get_task_mm(task);
49262306a36Sopenharmony_ci	if (mm) {
49362306a36Sopenharmony_ci		vsize = task_vsize(mm);
49462306a36Sopenharmony_ci		/*
49562306a36Sopenharmony_ci		 * esp and eip are intentionally zeroed out.  There is no
49662306a36Sopenharmony_ci		 * non-racy way to read them without freezing the task.
49762306a36Sopenharmony_ci		 * Programs that need reliable values can use ptrace(2).
49862306a36Sopenharmony_ci		 *
49962306a36Sopenharmony_ci		 * The only exception is if the task is core dumping because
50062306a36Sopenharmony_ci		 * a program is not able to use ptrace(2) in that case. It is
50162306a36Sopenharmony_ci		 * safe because the task has stopped executing permanently.
50262306a36Sopenharmony_ci		 */
50362306a36Sopenharmony_ci		if (permitted && (task->flags & (PF_EXITING|PF_DUMPCORE))) {
50462306a36Sopenharmony_ci			if (try_get_task_stack(task)) {
50562306a36Sopenharmony_ci				eip = KSTK_EIP(task);
50662306a36Sopenharmony_ci				esp = KSTK_ESP(task);
50762306a36Sopenharmony_ci				put_task_stack(task);
50862306a36Sopenharmony_ci			}
50962306a36Sopenharmony_ci		}
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	sigemptyset(&sigign);
51362306a36Sopenharmony_ci	sigemptyset(&sigcatch);
51462306a36Sopenharmony_ci	cutime = cstime = 0;
51562306a36Sopenharmony_ci	cgtime = gtime = 0;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	if (lock_task_sighand(task, &flags)) {
51862306a36Sopenharmony_ci		struct signal_struct *sig = task->signal;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		if (sig->tty) {
52162306a36Sopenharmony_ci			struct pid *pgrp = tty_get_pgrp(sig->tty);
52262306a36Sopenharmony_ci			tty_pgrp = pid_nr_ns(pgrp, ns);
52362306a36Sopenharmony_ci			put_pid(pgrp);
52462306a36Sopenharmony_ci			tty_nr = new_encode_dev(tty_devnum(sig->tty));
52562306a36Sopenharmony_ci		}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		num_threads = get_nr_threads(task);
52862306a36Sopenharmony_ci		collect_sigign_sigcatch(task, &sigign, &sigcatch);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci		cmin_flt = sig->cmin_flt;
53162306a36Sopenharmony_ci		cmaj_flt = sig->cmaj_flt;
53262306a36Sopenharmony_ci		cutime = sig->cutime;
53362306a36Sopenharmony_ci		cstime = sig->cstime;
53462306a36Sopenharmony_ci		cgtime = sig->cgtime;
53562306a36Sopenharmony_ci		rsslim = READ_ONCE(sig->rlim[RLIMIT_RSS].rlim_cur);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		/* add up live thread stats at the group level */
53862306a36Sopenharmony_ci		if (whole) {
53962306a36Sopenharmony_ci			struct task_struct *t = task;
54062306a36Sopenharmony_ci			do {
54162306a36Sopenharmony_ci				min_flt += t->min_flt;
54262306a36Sopenharmony_ci				maj_flt += t->maj_flt;
54362306a36Sopenharmony_ci				gtime += task_gtime(t);
54462306a36Sopenharmony_ci			} while_each_thread(task, t);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci			min_flt += sig->min_flt;
54762306a36Sopenharmony_ci			maj_flt += sig->maj_flt;
54862306a36Sopenharmony_ci			gtime += sig->gtime;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci			if (sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_STOP_STOPPED))
55162306a36Sopenharmony_ci				exit_code = sig->group_exit_code;
55262306a36Sopenharmony_ci		}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci		sid = task_session_nr_ns(task, ns);
55562306a36Sopenharmony_ci		ppid = task_tgid_nr_ns(task->real_parent, ns);
55662306a36Sopenharmony_ci		pgid = task_pgrp_nr_ns(task, ns);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci		unlock_task_sighand(task, &flags);
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if (permitted && (!whole || num_threads < 2))
56262306a36Sopenharmony_ci		wchan = !task_is_running(task);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	if (whole) {
56562306a36Sopenharmony_ci		thread_group_cputime_adjusted(task, &utime, &stime);
56662306a36Sopenharmony_ci	} else {
56762306a36Sopenharmony_ci		task_cputime_adjusted(task, &utime, &stime);
56862306a36Sopenharmony_ci		min_flt = task->min_flt;
56962306a36Sopenharmony_ci		maj_flt = task->maj_flt;
57062306a36Sopenharmony_ci		gtime = task_gtime(task);
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	/* scale priority and nice values from timeslices to -20..20 */
57462306a36Sopenharmony_ci	/* to make it look like a "normal" Unix priority/nice value  */
57562306a36Sopenharmony_ci	priority = task_prio(task);
57662306a36Sopenharmony_ci	nice = task_nice(task);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	/* apply timens offset for boottime and convert nsec -> ticks */
57962306a36Sopenharmony_ci	start_time =
58062306a36Sopenharmony_ci		nsec_to_clock_t(timens_add_boottime_ns(task->start_boottime));
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	seq_put_decimal_ull(m, "", pid_nr_ns(pid, ns));
58362306a36Sopenharmony_ci	seq_puts(m, " (");
58462306a36Sopenharmony_ci	proc_task_name(m, task, false);
58562306a36Sopenharmony_ci	seq_puts(m, ") ");
58662306a36Sopenharmony_ci	seq_putc(m, state);
58762306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", ppid);
58862306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", pgid);
58962306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", sid);
59062306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", tty_nr);
59162306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", tty_pgrp);
59262306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", task->flags);
59362306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", min_flt);
59462306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", cmin_flt);
59562306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", maj_flt);
59662306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", cmaj_flt);
59762306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", nsec_to_clock_t(utime));
59862306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", nsec_to_clock_t(stime));
59962306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", nsec_to_clock_t(cutime));
60062306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", nsec_to_clock_t(cstime));
60162306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", priority);
60262306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", nice);
60362306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", num_threads);
60462306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", 0);
60562306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", start_time);
60662306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", vsize);
60762306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", mm ? get_mm_rss(mm) : 0);
60862306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", rsslim);
60962306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", mm ? (permitted ? mm->start_code : 1) : 0);
61062306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", mm ? (permitted ? mm->end_code : 1) : 0);
61162306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", (permitted && mm) ? mm->start_stack : 0);
61262306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", esp);
61362306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", eip);
61462306a36Sopenharmony_ci	/* The signal information here is obsolete.
61562306a36Sopenharmony_ci	 * It must be decimal for Linux 2.0 compatibility.
61662306a36Sopenharmony_ci	 * Use /proc/#/status for real-time signals.
61762306a36Sopenharmony_ci	 */
61862306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", task->pending.signal.sig[0] & 0x7fffffffUL);
61962306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", task->blocked.sig[0] & 0x7fffffffUL);
62062306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", sigign.sig[0] & 0x7fffffffUL);
62162306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", sigcatch.sig[0] & 0x7fffffffUL);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	/*
62462306a36Sopenharmony_ci	 * We used to output the absolute kernel address, but that's an
62562306a36Sopenharmony_ci	 * information leak - so instead we show a 0/1 flag here, to signal
62662306a36Sopenharmony_ci	 * to user-space whether there's a wchan field in /proc/PID/wchan.
62762306a36Sopenharmony_ci	 *
62862306a36Sopenharmony_ci	 * This works with older implementations of procps as well.
62962306a36Sopenharmony_ci	 */
63062306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", wchan);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", 0);
63362306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", 0);
63462306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", task->exit_signal);
63562306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", task_cpu(task));
63662306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", task->rt_priority);
63762306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", task->policy);
63862306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", delayacct_blkio_ticks(task));
63962306a36Sopenharmony_ci	seq_put_decimal_ull(m, " ", nsec_to_clock_t(gtime));
64062306a36Sopenharmony_ci	seq_put_decimal_ll(m, " ", nsec_to_clock_t(cgtime));
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (mm && permitted) {
64362306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", mm->start_data);
64462306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", mm->end_data);
64562306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", mm->start_brk);
64662306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", mm->arg_start);
64762306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", mm->arg_end);
64862306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", mm->env_start);
64962306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", mm->env_end);
65062306a36Sopenharmony_ci	} else
65162306a36Sopenharmony_ci		seq_puts(m, " 0 0 0 0 0 0 0");
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	if (permitted)
65462306a36Sopenharmony_ci		seq_put_decimal_ll(m, " ", exit_code);
65562306a36Sopenharmony_ci	else
65662306a36Sopenharmony_ci		seq_puts(m, " 0");
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	seq_putc(m, '\n');
65962306a36Sopenharmony_ci	if (mm)
66062306a36Sopenharmony_ci		mmput(mm);
66162306a36Sopenharmony_ci	return 0;
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ciint proc_tid_stat(struct seq_file *m, struct pid_namespace *ns,
66562306a36Sopenharmony_ci			struct pid *pid, struct task_struct *task)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	return do_task_stat(m, ns, pid, task, 0);
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ciint proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns,
67162306a36Sopenharmony_ci			struct pid *pid, struct task_struct *task)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	return do_task_stat(m, ns, pid, task, 1);
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ciint proc_pid_statm(struct seq_file *m, struct pid_namespace *ns,
67762306a36Sopenharmony_ci			struct pid *pid, struct task_struct *task)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct mm_struct *mm = get_task_mm(task);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (mm) {
68262306a36Sopenharmony_ci		unsigned long size;
68362306a36Sopenharmony_ci		unsigned long resident = 0;
68462306a36Sopenharmony_ci		unsigned long shared = 0;
68562306a36Sopenharmony_ci		unsigned long text = 0;
68662306a36Sopenharmony_ci		unsigned long data = 0;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci		size = task_statm(mm, &shared, &text, &data, &resident);
68962306a36Sopenharmony_ci		mmput(mm);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci		/*
69262306a36Sopenharmony_ci		 * For quick read, open code by putting numbers directly
69362306a36Sopenharmony_ci		 * expected format is
69462306a36Sopenharmony_ci		 * seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n",
69562306a36Sopenharmony_ci		 *               size, resident, shared, text, data);
69662306a36Sopenharmony_ci		 */
69762306a36Sopenharmony_ci		seq_put_decimal_ull(m, "", size);
69862306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", resident);
69962306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", shared);
70062306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", text);
70162306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", 0);
70262306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", data);
70362306a36Sopenharmony_ci		seq_put_decimal_ull(m, " ", 0);
70462306a36Sopenharmony_ci		seq_putc(m, '\n');
70562306a36Sopenharmony_ci	} else {
70662306a36Sopenharmony_ci		seq_write(m, "0 0 0 0 0 0 0\n", 14);
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci	return 0;
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci#ifdef CONFIG_PROC_CHILDREN
71262306a36Sopenharmony_cistatic struct pid *
71362306a36Sopenharmony_ciget_children_pid(struct inode *inode, struct pid *pid_prev, loff_t pos)
71462306a36Sopenharmony_ci{
71562306a36Sopenharmony_ci	struct task_struct *start, *task;
71662306a36Sopenharmony_ci	struct pid *pid = NULL;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	read_lock(&tasklist_lock);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	start = pid_task(proc_pid(inode), PIDTYPE_PID);
72162306a36Sopenharmony_ci	if (!start)
72262306a36Sopenharmony_ci		goto out;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/*
72562306a36Sopenharmony_ci	 * Lets try to continue searching first, this gives
72662306a36Sopenharmony_ci	 * us significant speedup on children-rich processes.
72762306a36Sopenharmony_ci	 */
72862306a36Sopenharmony_ci	if (pid_prev) {
72962306a36Sopenharmony_ci		task = pid_task(pid_prev, PIDTYPE_PID);
73062306a36Sopenharmony_ci		if (task && task->real_parent == start &&
73162306a36Sopenharmony_ci		    !(list_empty(&task->sibling))) {
73262306a36Sopenharmony_ci			if (list_is_last(&task->sibling, &start->children))
73362306a36Sopenharmony_ci				goto out;
73462306a36Sopenharmony_ci			task = list_first_entry(&task->sibling,
73562306a36Sopenharmony_ci						struct task_struct, sibling);
73662306a36Sopenharmony_ci			pid = get_pid(task_pid(task));
73762306a36Sopenharmony_ci			goto out;
73862306a36Sopenharmony_ci		}
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/*
74262306a36Sopenharmony_ci	 * Slow search case.
74362306a36Sopenharmony_ci	 *
74462306a36Sopenharmony_ci	 * We might miss some children here if children
74562306a36Sopenharmony_ci	 * are exited while we were not holding the lock,
74662306a36Sopenharmony_ci	 * but it was never promised to be accurate that
74762306a36Sopenharmony_ci	 * much.
74862306a36Sopenharmony_ci	 *
74962306a36Sopenharmony_ci	 * "Just suppose that the parent sleeps, but N children
75062306a36Sopenharmony_ci	 *  exit after we printed their tids. Now the slow paths
75162306a36Sopenharmony_ci	 *  skips N extra children, we miss N tasks." (c)
75262306a36Sopenharmony_ci	 *
75362306a36Sopenharmony_ci	 * So one need to stop or freeze the leader and all
75462306a36Sopenharmony_ci	 * its children to get a precise result.
75562306a36Sopenharmony_ci	 */
75662306a36Sopenharmony_ci	list_for_each_entry(task, &start->children, sibling) {
75762306a36Sopenharmony_ci		if (pos-- == 0) {
75862306a36Sopenharmony_ci			pid = get_pid(task_pid(task));
75962306a36Sopenharmony_ci			break;
76062306a36Sopenharmony_ci		}
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ciout:
76462306a36Sopenharmony_ci	read_unlock(&tasklist_lock);
76562306a36Sopenharmony_ci	return pid;
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic int children_seq_show(struct seq_file *seq, void *v)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	struct inode *inode = file_inode(seq->file);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	seq_printf(seq, "%d ", pid_nr_ns(v, proc_pid_ns(inode->i_sb)));
77362306a36Sopenharmony_ci	return 0;
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_cistatic void *children_seq_start(struct seq_file *seq, loff_t *pos)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	return get_children_pid(file_inode(seq->file), NULL, *pos);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic void *children_seq_next(struct seq_file *seq, void *v, loff_t *pos)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	struct pid *pid;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	pid = get_children_pid(file_inode(seq->file), v, *pos + 1);
78662306a36Sopenharmony_ci	put_pid(v);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	++*pos;
78962306a36Sopenharmony_ci	return pid;
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic void children_seq_stop(struct seq_file *seq, void *v)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	put_pid(v);
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic const struct seq_operations children_seq_ops = {
79862306a36Sopenharmony_ci	.start	= children_seq_start,
79962306a36Sopenharmony_ci	.next	= children_seq_next,
80062306a36Sopenharmony_ci	.stop	= children_seq_stop,
80162306a36Sopenharmony_ci	.show	= children_seq_show,
80262306a36Sopenharmony_ci};
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_cistatic int children_seq_open(struct inode *inode, struct file *file)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	return seq_open(file, &children_seq_ops);
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ciconst struct file_operations proc_tid_children_operations = {
81062306a36Sopenharmony_ci	.open    = children_seq_open,
81162306a36Sopenharmony_ci	.read    = seq_read,
81262306a36Sopenharmony_ci	.llseek  = seq_lseek,
81362306a36Sopenharmony_ci	.release = seq_release,
81462306a36Sopenharmony_ci};
81562306a36Sopenharmony_ci#endif /* CONFIG_PROC_CHILDREN */
816