linux/fs/proc/base.c

// SPDX-License-Identifier: GPL-2.0
/*
 *  linux/fs/proc/base.c
 *
 *  Copyright (C) 1991, 1992 Linus Torvalds
 *
 *  proc base directory handling functions
 *
 *  1999, Al Viro. Rewritten. Now it covers the whole per-process part.
 *  Instead of using magical inumbers to determine the kind of object
 *  we allocate and fill in-core inodes upon lookup. They don't even
 *  go into icache. We cache the reference to task_struct upon lookup too.
 *  Eventually it should become a filesystem in its own. We don't use the
 *  rest of procfs anymore.
 *
 *
 *  Changelog:
 *  17-Jan-2005
 *  Allan Bezerra
 *  Bruna Moreira <[email protected]>
 *  Edjard Mota <[email protected]>
 *  Ilias Biris <[email protected]>
 *  Mauricio Lin <[email protected]>
 *
 *  Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
 *
 *  A new process specific entry (smaps) included in /proc. It shows the
 *  size of rss for each memory area. The maps entry lacks information
 *  about physical memory size (rss) for each mapped file, i.e.,
 *  rss information for executables and library files.
 *  This additional information is useful for any tools that need to know
 *  about physical memory consumption for a process specific library.
 *
 *  Changelog:
 *  21-Feb-2005
 *  Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
 *  Pud inclusion in the page table walking.
 *
 *  ChangeLog:
 *  10-Mar-2005
 *  10LE Instituto Nokia de Tecnologia - INdT:
 *  A better way to walks through the page table as suggested by Hugh Dickins.
 *
 *  Simo Piiroinen <[email protected]>:
 *  Smaps information related to shared, private, clean and dirty pages.
 *
 *  Paul Mundt <[email protected]>:
 *  Overall revision about smaps.
 */

#include <linux/uaccess.h>

#include <linux/errno.h>
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/init.h>
#include <linux/capability.h>
#include <linux/file.h>
#include <linux/fdtable.h>
#include <linux/generic-radix-tree.h>
#include <linux/string.h>
#include <linux/seq_file.h>
#include <linux/namei.h>
#include <linux/mnt_namespace.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/rcupdate.h>
#include <linux/kallsyms.h>
#include <linux/stacktrace.h>
#include <linux/resource.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/security.h>
#include <linux/ptrace.h>
#include <linux/printk.h>
#include <linux/cache.h>
#include <linux/cgroup.h>
#include <linux/cpuset.h>
#include <linux/audit.h>
#include <linux/poll.h>
#include <linux/nsproxy.h>
#include <linux/oom.h>
#include <linux/elf.h>
#include <linux/pid_namespace.h>
#include <linux/user_namespace.h>
#include <linux/fs_struct.h>
#include <linux/slab.h>
#include <linux/sched/autogroup.h>
#include <linux/sched/mm.h>
#include <linux/sched/coredump.h>
#include <linux/sched/debug.h>
#include <linux/sched/stat.h>
#include <linux/posix-timers.h>
#include <linux/time_namespace.h>
#include <linux/resctrl.h>
#include <linux/cn_proc.h>
#include <linux/ksm.h>
#include <uapi/linux/lsm.h>
#include <trace/events/oom.h>
#include "internal.h"
#include "fd.h"

#include "../../lib/kstrtox.h"

/* NOTE:
 *	Implementing inode permission operations in /proc is almost
 *	certainly an error.  Permission checks need to happen during
 *	each system call not at open time.  The reason is that most of
 *	what we wish to check for permissions in /proc varies at runtime.
 *
 *	The classic example of a problem is opening file descriptors
 *	in /proc for a task before it execs a suid executable.
 */

static u8 nlink_tid __ro_after_init;
static u8 nlink_tgid __ro_after_init;

struct pid_entry {};

#define NOD(NAME, MODE, IOP, FOP, OP)

#define DIR(NAME, MODE, iops, fops)
#define LNK(NAME, get_link)
#define REG(NAME, MODE, fops)
#define ONE(NAME, MODE, show)
#define ATTR(LSMID, NAME, MODE)

/*
 * Count the number of hardlinks for the pid_entry table, excluding the .
 * and .. links.
 */
static unsigned int __init pid_entry_nlink(const struct pid_entry *entries,
	unsigned int n)
{}

static int get_task_root(struct task_struct *task, struct path *root)
{}

static int proc_cwd_link(struct dentry *dentry, struct path *path)
{}

static int proc_root_link(struct dentry *dentry, struct path *path)
{}

/*
 * If the user used setproctitle(), we just get the string from
 * user space at arg_start, and limit it to a maximum of one page.
 */
static ssize_t get_mm_proctitle(struct mm_struct *mm, char __user *buf,
				size_t count, unsigned long pos,
				unsigned long arg_start)
{}

static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
			      size_t count, loff_t *ppos)
{}

static ssize_t get_task_cmdline(struct task_struct *tsk, char __user *buf,
				size_t count, loff_t *pos)
{}

static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf,
				     size_t count, loff_t *pos)
{}

static const struct file_operations proc_pid_cmdline_ops =;

#ifdef CONFIG_KALLSYMS
/*
 * Provides a wchan file via kallsyms in a proper one-value-per-file format.
 * Returns the resolved symbol.  If that fails, simply return the address.
 */
static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns,
			  struct pid *pid, struct task_struct *task)
{}
#endif /* CONFIG_KALLSYMS */

static int lock_trace(struct task_struct *task)
{}

static void unlock_trace(struct task_struct *task)
{}

#ifdef CONFIG_STACKTRACE

#define MAX_STACK_TRACE_DEPTH

static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns,
			  struct pid *pid, struct task_struct *task)
{}
#endif

#ifdef CONFIG_SCHED_INFO
/*
 * Provides /proc/PID/schedstat
 */
static int proc_pid_schedstat(struct seq_file *m, struct pid_namespace *ns,
			      struct pid *pid, struct task_struct *task)
{}
#endif

#ifdef CONFIG_LATENCYTOP
static int lstats_show_proc(struct seq_file *m, void *v)
{}

static int lstats_open(struct inode *inode, struct file *file)
{}

static ssize_t lstats_write(struct file *file, const char __user *buf,
			    size_t count, loff_t *offs)
{}

static const struct file_operations proc_lstats_operations =;

#endif

static int proc_oom_score(struct seq_file *m, struct pid_namespace *ns,
			  struct pid *pid, struct task_struct *task)
{}

struct limit_names {};

static const struct limit_names lnames[RLIM_NLIMITS] =;

/* Display limits for a process */
static int proc_pid_limits(struct seq_file *m, struct pid_namespace *ns,
			   struct pid *pid, struct task_struct *task)
{}

#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
static int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns,
			    struct pid *pid, struct task_struct *task)
{}
#endif /* CONFIG_HAVE_ARCH_TRACEHOOK */

/************************************************************************/
/*                       Here the fs part begins                        */
/************************************************************************/

/* permission checks */
static bool proc_fd_access_allowed(struct inode *inode)
{}

int proc_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
		 struct iattr *attr)
{}

/*
 * May current process learn task's sched/cmdline info (for hide_pid_min=1)
 * or euid/egid (for hide_pid_min=2)?
 */
static bool has_pid_permissions(struct proc_fs_info *fs_info,
				 struct task_struct *task,
				 enum proc_hidepid hide_pid_min)
{}


static int proc_pid_permission(struct mnt_idmap *idmap,
			       struct inode *inode, int mask)
{}



static const struct inode_operations proc_def_inode_operations =;

static int proc_single_show(struct seq_file *m, void *v)
{}

static int proc_single_open(struct inode *inode, struct file *filp)
{}

static const struct file_operations proc_single_file_operations =;


struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode)
{}

static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
{}

static int mem_open(struct inode *inode, struct file *file)
{}

static ssize_t mem_rw(struct file *file, char __user *buf,
			size_t count, loff_t *ppos, int write)
{}

static ssize_t mem_read(struct file *file, char __user *buf,
			size_t count, loff_t *ppos)
{}

static ssize_t mem_write(struct file *file, const char __user *buf,
			 size_t count, loff_t *ppos)
{}

loff_t mem_lseek(struct file *file, loff_t offset, int orig)
{}

static int mem_release(struct inode *inode, struct file *file)
{}

static const struct file_operations proc_mem_operations =;

static int environ_open(struct inode *inode, struct file *file)
{}

static ssize_t environ_read(struct file *file, char __user *buf,
			size_t count, loff_t *ppos)
{}

static const struct file_operations proc_environ_operations =;

static int auxv_open(struct inode *inode, struct file *file)
{}

static ssize_t auxv_read(struct file *file, char __user *buf,
			size_t count, loff_t *ppos)
{}

static const struct file_operations proc_auxv_operations =;

static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count,
			    loff_t *ppos)
{}

static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)
{}

/*
 * /proc/pid/oom_adj exists solely for backwards compatibility with previous
 * kernels.  The effective policy is defined by oom_score_adj, which has a
 * different scale: oom_adj grew exponentially and oom_score_adj grows linearly.
 * Values written to oom_adj are simply mapped linearly to oom_score_adj.
 * Processes that become oom disabled via oom_adj will still be oom disabled
 * with this implementation.
 *
 * oom_adj cannot be removed since existing userspace binaries use it.
 */
static ssize_t oom_adj_write(struct file *file, const char __user *buf,
			     size_t count, loff_t *ppos)
{}

static const struct file_operations proc_oom_adj_operations =;

static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
					size_t count, loff_t *ppos)
{}

static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
					size_t count, loff_t *ppos)
{}

static const struct file_operations proc_oom_score_adj_operations =;

#ifdef CONFIG_AUDIT
#define TMPBUFLEN
static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
				  size_t count, loff_t *ppos)
{}

static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
				   size_t count, loff_t *ppos)
{}

static const struct file_operations proc_loginuid_operations =;

static ssize_t proc_sessionid_read(struct file * file, char __user * buf,
				  size_t count, loff_t *ppos)
{}

static const struct file_operations proc_sessionid_operations =;
#endif

#ifdef CONFIG_FAULT_INJECTION
static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
				      size_t count, loff_t *ppos)
{}

static ssize_t proc_fault_inject_write(struct file * file,
			const char __user * buf, size_t count, loff_t *ppos)
{}

static const struct file_operations proc_fault_inject_operations =;

static ssize_t proc_fail_nth_write(struct file *file, const char __user *buf,
				   size_t count, loff_t *ppos)
{}

static ssize_t proc_fail_nth_read(struct file *file, char __user *buf,
				  size_t count, loff_t *ppos)
{}

static const struct file_operations proc_fail_nth_operations =;
#endif


#ifdef CONFIG_SCHED_DEBUG
/*
 * Print out various scheduling related per-task fields:
 */
static int sched_show(struct seq_file *m, void *v)
{}

static ssize_t
sched_write(struct file *file, const char __user *buf,
	    size_t count, loff_t *offset)
{}

static int sched_open(struct inode *inode, struct file *filp)
{}

static const struct file_operations proc_pid_sched_operations =;

#endif

#ifdef CONFIG_SCHED_AUTOGROUP
/*
 * Print out autogroup related information:
 */
static int sched_autogroup_show(struct seq_file *m, void *v)
{}

static ssize_t
sched_autogroup_write(struct file *file, const char __user *buf,
	    size_t count, loff_t *offset)
{}

static int sched_autogroup_open(struct inode *inode, struct file *filp)
{}

static const struct file_operations proc_pid_sched_autogroup_operations =;

#endif /* CONFIG_SCHED_AUTOGROUP */

#ifdef CONFIG_TIME_NS
static int timens_offsets_show(struct seq_file *m, void *v)
{}

static ssize_t timens_offsets_write(struct file *file, const char __user *buf,
				    size_t count, loff_t *ppos)
{}

static int timens_offsets_open(struct inode *inode, struct file *filp)
{}

static const struct file_operations proc_timens_offsets_operations =;
#endif /* CONFIG_TIME_NS */

static ssize_t comm_write(struct file *file, const char __user *buf,
				size_t count, loff_t *offset)
{}

static int comm_show(struct seq_file *m, void *v)
{}

static int comm_open(struct inode *inode, struct file *filp)
{}

static const struct file_operations proc_pid_set_comm_operations =;

static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
{}

static const char *proc_pid_get_link(struct dentry *dentry,
				     struct inode *inode,
				     struct delayed_call *done)
{}

static int do_proc_readlink(const struct path *path, char __user *buffer, int buflen)
{}

static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int buflen)
{}

const struct inode_operations proc_pid_link_inode_operations =;


/* building an inode */

void task_dump_owner(struct task_struct *task, umode_t mode,
		     kuid_t *ruid, kgid_t *rgid)
{}

void proc_pid_evict_inode(struct proc_inode *ei)
{}

struct inode *proc_pid_make_inode(struct super_block *sb,
				  struct task_struct *task, umode_t mode)
{}

/*
 * Generating an inode and adding it into @pid->inodes, so that task will
 * invalidate inode's dentry before being released.
 *
 * This helper is used for creating dir-type entries under '/proc' and
 * '/proc/<tgid>/task'. Other entries(eg. fd, stat) under '/proc/<tgid>'
 * can be released by invalidating '/proc/<tgid>' dentry.
 * In theory, dentries under '/proc/<tgid>/task' can also be released by
 * invalidating '/proc/<tgid>' dentry, we reserve it to handle single
 * thread exiting situation: Any one of threads should invalidate its
 * '/proc/<tgid>/task/<pid>' dentry before released.
 */
static struct inode *proc_pid_make_base_inode(struct super_block *sb,
				struct task_struct *task, umode_t mode)
{}

int pid_getattr(struct mnt_idmap *idmap, const struct path *path,
		struct kstat *stat, u32 request_mask, unsigned int query_flags)
{}

/* dentry stuff */

/*
 * Set <pid>/... inode ownership (can change due to setuid(), etc.)
 */
void pid_update_inode(struct task_struct *task, struct inode *inode)
{}

/*
 * Rewrite the inode's ownerships here because the owning task may have
 * performed a setuid(), etc.
 *
 */
static int pid_revalidate(struct dentry *dentry, unsigned int flags)
{}

static inline bool proc_inode_is_dead(struct inode *inode)
{}

int pid_delete_dentry(const struct dentry *dentry)
{}

const struct dentry_operations pid_dentry_operations =;

/* Lookups */

/*
 * Fill a directory entry.
 *
 * If possible create the dcache entry and derive our inode number and
 * file type from dcache entry.
 *
 * Since all of the proc inode numbers are dynamically generated, the inode
 * numbers do not exist until the inode is cache.  This means creating
 * the dcache entry in readdir is necessary to keep the inode numbers
 * reported by readdir in sync with the inode numbers reported
 * by stat.
 */
bool proc_fill_cache(struct file *file, struct dir_context *ctx,
	const char *name, unsigned int len,
	instantiate_t instantiate, struct task_struct *task, const void *ptr)
{}

/*
 * dname_to_vma_addr - maps a dentry name into two unsigned longs
 * which represent vma start and end addresses.
 */
static int dname_to_vma_addr(struct dentry *dentry,
			     unsigned long *start, unsigned long *end)
{}

static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags)
{}

static const struct dentry_operations tid_map_files_dentry_operations =;

static int map_files_get_link(struct dentry *dentry, struct path *path)
{}

struct map_files_info {};

/*
 * Only allow CAP_SYS_ADMIN and CAP_CHECKPOINT_RESTORE to follow the links, due
 * to concerns about how the symlinks may be used to bypass permissions on
 * ancestor directories in the path to the file in question.
 */
static const char *
proc_map_files_get_link(struct dentry *dentry,
			struct inode *inode,
		        struct delayed_call *done)
{}

/*
 * Identical to proc_pid_link_inode_operations except for get_link()
 */
static const struct inode_operations proc_map_files_link_inode_operations =;

static struct dentry *
proc_map_files_instantiate(struct dentry *dentry,
			   struct task_struct *task, const void *ptr)
{}

static struct dentry *proc_map_files_lookup(struct inode *dir,
		struct dentry *dentry, unsigned int flags)
{}

static const struct inode_operations proc_map_files_inode_operations =;

static int
proc_map_files_readdir(struct file *file, struct dir_context *ctx)
{}

static const struct file_operations proc_map_files_operations =;

#if defined(CONFIG_CHECKPOINT_RESTORE) && defined(CONFIG_POSIX_TIMERS)
struct timers_private {};

static void *timers_start(struct seq_file *m, loff_t *pos)
{}

static void *timers_next(struct seq_file *m, void *v, loff_t *pos)
{}

static void timers_stop(struct seq_file *m, void *v)
{}

static int show_timer(struct seq_file *m, void *v)
{}

static const struct seq_operations proc_timers_seq_ops =;

static int proc_timers_open(struct inode *inode, struct file *file)
{}

static const struct file_operations proc_timers_operations =;
#endif

static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
					size_t count, loff_t *offset)
{}

static int timerslack_ns_show(struct seq_file *m, void *v)
{}

static int timerslack_ns_open(struct inode *inode, struct file *filp)
{}

static const struct file_operations proc_pid_set_timerslack_ns_operations =;

static struct dentry *proc_pident_instantiate(struct dentry *dentry,
	struct task_struct *task, const void *ptr)
{}

static struct dentry *proc_pident_lookup(struct inode *dir, 
					 struct dentry *dentry,
					 const struct pid_entry *p,
					 const struct pid_entry *end)
{}

static int proc_pident_readdir(struct file *file, struct dir_context *ctx,
		const struct pid_entry *ents, unsigned int nents)
{}

#ifdef CONFIG_SECURITY
static int proc_pid_attr_open(struct inode *inode, struct file *file)
{}

static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
				  size_t count, loff_t *ppos)
{}

static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
				   size_t count, loff_t *ppos)
{}

static const struct file_operations proc_pid_attr_operations =;

#define LSM_DIR_OPS(LSM)

#ifdef CONFIG_SECURITY_SMACK
static const struct pid_entry smack_attr_dir_stuff[] =;
LSM_DIR_OPS();
#endif

#ifdef CONFIG_SECURITY_APPARMOR
static const struct pid_entry apparmor_attr_dir_stuff[] =;
LSM_DIR_OPS();
#endif

static const struct pid_entry attr_dir_stuff[] =;

static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx)
{}

static const struct file_operations proc_attr_dir_operations =;

static struct dentry *proc_attr_dir_lookup(struct inode *dir,
				struct dentry *dentry, unsigned int flags)
{}

static const struct inode_operations proc_attr_dir_inode_operations =;

#endif

#ifdef CONFIG_ELF_CORE
static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf,
					 size_t count, loff_t *ppos)
{}

static ssize_t proc_coredump_filter_write(struct file *file,
					  const char __user *buf,
					  size_t count,
					  loff_t *ppos)
{}

static const struct file_operations proc_coredump_filter_operations =;
#endif

#ifdef CONFIG_TASK_IO_ACCOUNTING
static int do_io_accounting(struct task_struct *task, struct seq_file *m, int whole)
{}

static int proc_tid_io_accounting(struct seq_file *m, struct pid_namespace *ns,
				  struct pid *pid, struct task_struct *task)
{}

static int proc_tgid_io_accounting(struct seq_file *m, struct pid_namespace *ns,
				   struct pid *pid, struct task_struct *task)
{}
#endif /* CONFIG_TASK_IO_ACCOUNTING */

#ifdef CONFIG_USER_NS
static int proc_id_map_open(struct inode *inode, struct file *file,
	const struct seq_operations *seq_ops)
{}

static int proc_id_map_release(struct inode *inode, struct file *file)
{}

static int proc_uid_map_open(struct inode *inode, struct file *file)
{}

static int proc_gid_map_open(struct inode *inode, struct file *file)
{}

static int proc_projid_map_open(struct inode *inode, struct file *file)
{}

static const struct file_operations proc_uid_map_operations =;

static const struct file_operations proc_gid_map_operations =;

static const struct file_operations proc_projid_map_operations =;

static int proc_setgroups_open(struct inode *inode, struct file *file)
{}

static int proc_setgroups_release(struct inode *inode, struct file *file)
{}

static const struct file_operations proc_setgroups_operations =;
#endif /* CONFIG_USER_NS */

static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
				struct pid *pid, struct task_struct *task)
{}

#ifdef CONFIG_LIVEPATCH
static int proc_pid_patch_state(struct seq_file *m, struct pid_namespace *ns,
				struct pid *pid, struct task_struct *task)
{
	seq_printf(m, "%d\n", task->patch_state);
	return 0;
}
#endif /* CONFIG_LIVEPATCH */

#ifdef CONFIG_KSM
static int proc_pid_ksm_merging_pages(struct seq_file *m, struct pid_namespace *ns,
				struct pid *pid, struct task_struct *task)
{}
static int proc_pid_ksm_stat(struct seq_file *m, struct pid_namespace *ns,
				struct pid *pid, struct task_struct *task)
{}
#endif /* CONFIG_KSM */

#ifdef CONFIG_STACKLEAK_METRICS
static int proc_stack_depth(struct seq_file *m, struct pid_namespace *ns,
				struct pid *pid, struct task_struct *task)
{
	unsigned long prev_depth = THREAD_SIZE -
				(task->prev_lowest_stack & (THREAD_SIZE - 1));
	unsigned long depth = THREAD_SIZE -
				(task->lowest_stack & (THREAD_SIZE - 1));

	seq_printf(m, "previous stack depth: %lu\nstack depth: %lu\n",
							prev_depth, depth);
	return 0;
}
#endif /* CONFIG_STACKLEAK_METRICS */

/*
 * Thread groups
 */
static const struct file_operations proc_task_operations;
static const struct inode_operations proc_task_inode_operations;

static const struct pid_entry tgid_base_stuff[] =;

static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx)
{}

static const struct file_operations proc_tgid_base_operations =;

struct pid *tgid_pidfd_to_pid(const struct file *file)
{}

static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
{}

static const struct inode_operations proc_tgid_base_inode_operations =;

/**
 * proc_flush_pid -  Remove dcache entries for @pid from the /proc dcache.
 * @pid: pid that should be flushed.
 *
 * This function walks a list of inodes (that belong to any proc
 * filesystem) that are attached to the pid and flushes them from
 * the dentry cache.
 *
 * It is safe and reasonable to cache /proc entries for a task until
 * that task exits.  After that they just clog up the dcache with
 * useless entries, possibly causing useful dcache entries to be
 * flushed instead.  This routine is provided to flush those useless
 * dcache entries when a process is reaped.
 *
 * NOTE: This routine is just an optimization so it does not guarantee
 *       that no dcache entries will exist after a process is reaped
 *       it just makes it very unlikely that any will persist.
 */

void proc_flush_pid(struct pid *pid)
{}

static struct dentry *proc_pid_instantiate(struct dentry * dentry,
				   struct task_struct *task, const void *ptr)
{}

struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
{}

/*
 * Find the first task with tgid >= tgid
 *
 */
struct tgid_iter {};
static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter iter)
{}

#define TGID_OFFSET

/* for the /proc/ directory itself, after non-process stuff has been done */
int proc_pid_readdir(struct file *file, struct dir_context *ctx)
{}

/*
 * proc_tid_comm_permission is a special permission function exclusively
 * used for the node /proc/<pid>/task/<tid>/comm.
 * It bypasses generic permission checks in the case where a task of the same
 * task group attempts to access the node.
 * The rationale behind this is that glibc and bionic access this node for
 * cross thread naming (pthread_set/getname_np(!self)). However, if
 * PR_SET_DUMPABLE gets set to 0 this node among others becomes uid=0 gid=0,
 * which locks out the cross thread naming implementation.
 * This function makes sure that the node is always accessible for members of
 * same thread group.
 */
static int proc_tid_comm_permission(struct mnt_idmap *idmap,
				    struct inode *inode, int mask)
{}

static const struct inode_operations proc_tid_comm_inode_operations =;

/*
 * Tasks
 */
static const struct pid_entry tid_base_stuff[] =;

static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx)
{}

static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
{}

static const struct file_operations proc_tid_base_operations =;

static const struct inode_operations proc_tid_base_inode_operations =;

static struct dentry *proc_task_instantiate(struct dentry *dentry,
	struct task_struct *task, const void *ptr)
{}

static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
{}

/*
 * Find the first tid of a thread group to return to user space.
 *
 * Usually this is just the thread group leader, but if the users
 * buffer was too small or there was a seek into the middle of the
 * directory we have more work todo.
 *
 * In the case of a short read we start with find_task_by_pid.
 *
 * In the case of a seek we start with the leader and walk nr
 * threads past it.
 */
static struct task_struct *first_tid(struct pid *pid, int tid, loff_t f_pos,
					struct pid_namespace *ns)
{}

/*
 * Find the next thread in the thread list.
 * Return NULL if there is an error or no next thread.
 *
 * The reference to the input task_struct is released.
 */
static struct task_struct *next_tid(struct task_struct *start)
{}

/* for the /proc/TGID/task/ directories */
static int proc_task_readdir(struct file *file, struct dir_context *ctx)
{}

static int proc_task_getattr(struct mnt_idmap *idmap,
			     const struct path *path, struct kstat *stat,
			     u32 request_mask, unsigned int query_flags)
{}

static const struct inode_operations proc_task_inode_operations =;

static const struct file_operations proc_task_operations =;

void __init set_proc_pid_nlink(void)
{}