18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/fs/proc/root.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 1991, 1992 Linus Torvalds
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  proc root directory handling functions
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/errno.h>
138c2ecf20Sopenharmony_ci#include <linux/time.h>
148c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
158c2ecf20Sopenharmony_ci#include <linux/stat.h>
168c2ecf20Sopenharmony_ci#include <linux/init.h>
178c2ecf20Sopenharmony_ci#include <linux/sched.h>
188c2ecf20Sopenharmony_ci#include <linux/sched/stat.h>
198c2ecf20Sopenharmony_ci#include <linux/module.h>
208c2ecf20Sopenharmony_ci#include <linux/bitops.h>
218c2ecf20Sopenharmony_ci#include <linux/user_namespace.h>
228c2ecf20Sopenharmony_ci#include <linux/fs_context.h>
238c2ecf20Sopenharmony_ci#include <linux/mount.h>
248c2ecf20Sopenharmony_ci#include <linux/pid_namespace.h>
258c2ecf20Sopenharmony_ci#include <linux/fs_parser.h>
268c2ecf20Sopenharmony_ci#include <linux/cred.h>
278c2ecf20Sopenharmony_ci#include <linux/magic.h>
288c2ecf20Sopenharmony_ci#include <linux/slab.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include "internal.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistruct proc_fs_context {
338c2ecf20Sopenharmony_ci	struct pid_namespace	*pid_ns;
348c2ecf20Sopenharmony_ci	unsigned int		mask;
358c2ecf20Sopenharmony_ci	enum proc_hidepid	hidepid;
368c2ecf20Sopenharmony_ci	int			gid;
378c2ecf20Sopenharmony_ci	enum proc_pidonly	pidonly;
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cienum proc_param {
418c2ecf20Sopenharmony_ci	Opt_gid,
428c2ecf20Sopenharmony_ci	Opt_hidepid,
438c2ecf20Sopenharmony_ci	Opt_subset,
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic const struct fs_parameter_spec proc_fs_parameters[] = {
478c2ecf20Sopenharmony_ci	fsparam_u32("gid",	Opt_gid),
488c2ecf20Sopenharmony_ci	fsparam_string("hidepid",	Opt_hidepid),
498c2ecf20Sopenharmony_ci	fsparam_string("subset",	Opt_subset),
508c2ecf20Sopenharmony_ci	{}
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic inline int valid_hidepid(unsigned int value)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	return (value == HIDEPID_OFF ||
568c2ecf20Sopenharmony_ci		value == HIDEPID_NO_ACCESS ||
578c2ecf20Sopenharmony_ci		value == HIDEPID_INVISIBLE ||
588c2ecf20Sopenharmony_ci		value == HIDEPID_NOT_PTRACEABLE);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int proc_parse_hidepid_param(struct fs_context *fc, struct fs_parameter *param)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct proc_fs_context *ctx = fc->fs_private;
648c2ecf20Sopenharmony_ci	struct fs_parameter_spec hidepid_u32_spec = fsparam_u32("hidepid", Opt_hidepid);
658c2ecf20Sopenharmony_ci	struct fs_parse_result result;
668c2ecf20Sopenharmony_ci	int base = (unsigned long)hidepid_u32_spec.data;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (param->type != fs_value_is_string)
698c2ecf20Sopenharmony_ci		return invalf(fc, "proc: unexpected type of hidepid value\n");
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	if (!kstrtouint(param->string, base, &result.uint_32)) {
728c2ecf20Sopenharmony_ci		if (!valid_hidepid(result.uint_32))
738c2ecf20Sopenharmony_ci			return invalf(fc, "proc: unknown value of hidepid - %s\n", param->string);
748c2ecf20Sopenharmony_ci		ctx->hidepid = result.uint_32;
758c2ecf20Sopenharmony_ci		return 0;
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (!strcmp(param->string, "off"))
798c2ecf20Sopenharmony_ci		ctx->hidepid = HIDEPID_OFF;
808c2ecf20Sopenharmony_ci	else if (!strcmp(param->string, "noaccess"))
818c2ecf20Sopenharmony_ci		ctx->hidepid = HIDEPID_NO_ACCESS;
828c2ecf20Sopenharmony_ci	else if (!strcmp(param->string, "invisible"))
838c2ecf20Sopenharmony_ci		ctx->hidepid = HIDEPID_INVISIBLE;
848c2ecf20Sopenharmony_ci	else if (!strcmp(param->string, "ptraceable"))
858c2ecf20Sopenharmony_ci		ctx->hidepid = HIDEPID_NOT_PTRACEABLE;
868c2ecf20Sopenharmony_ci	else
878c2ecf20Sopenharmony_ci		return invalf(fc, "proc: unknown value of hidepid - %s\n", param->string);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	return 0;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int proc_parse_subset_param(struct fs_context *fc, char *value)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct proc_fs_context *ctx = fc->fs_private;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	while (value) {
978c2ecf20Sopenharmony_ci		char *ptr = strchr(value, ',');
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci		if (ptr != NULL)
1008c2ecf20Sopenharmony_ci			*ptr++ = '\0';
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci		if (*value != '\0') {
1038c2ecf20Sopenharmony_ci			if (!strcmp(value, "pid")) {
1048c2ecf20Sopenharmony_ci				ctx->pidonly = PROC_PIDONLY_ON;
1058c2ecf20Sopenharmony_ci			} else {
1068c2ecf20Sopenharmony_ci				return invalf(fc, "proc: unsupported subset option - %s\n", value);
1078c2ecf20Sopenharmony_ci			}
1088c2ecf20Sopenharmony_ci		}
1098c2ecf20Sopenharmony_ci		value = ptr;
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	return 0;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct proc_fs_context *ctx = fc->fs_private;
1188c2ecf20Sopenharmony_ci	struct fs_parse_result result;
1198c2ecf20Sopenharmony_ci	int opt;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	opt = fs_parse(fc, proc_fs_parameters, param, &result);
1228c2ecf20Sopenharmony_ci	if (opt < 0)
1238c2ecf20Sopenharmony_ci		return opt;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	switch (opt) {
1268c2ecf20Sopenharmony_ci	case Opt_gid:
1278c2ecf20Sopenharmony_ci		ctx->gid = result.uint_32;
1288c2ecf20Sopenharmony_ci		break;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	case Opt_hidepid:
1318c2ecf20Sopenharmony_ci		if (proc_parse_hidepid_param(fc, param))
1328c2ecf20Sopenharmony_ci			return -EINVAL;
1338c2ecf20Sopenharmony_ci		break;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	case Opt_subset:
1368c2ecf20Sopenharmony_ci		if (proc_parse_subset_param(fc, param->string) < 0)
1378c2ecf20Sopenharmony_ci			return -EINVAL;
1388c2ecf20Sopenharmony_ci		break;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	default:
1418c2ecf20Sopenharmony_ci		return -EINVAL;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	ctx->mask |= 1 << opt;
1458c2ecf20Sopenharmony_ci	return 0;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic void proc_apply_options(struct proc_fs_info *fs_info,
1498c2ecf20Sopenharmony_ci			       struct fs_context *fc,
1508c2ecf20Sopenharmony_ci			       struct user_namespace *user_ns)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	struct proc_fs_context *ctx = fc->fs_private;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (ctx->mask & (1 << Opt_gid))
1558c2ecf20Sopenharmony_ci		fs_info->pid_gid = make_kgid(user_ns, ctx->gid);
1568c2ecf20Sopenharmony_ci	if (ctx->mask & (1 << Opt_hidepid))
1578c2ecf20Sopenharmony_ci		fs_info->hide_pid = ctx->hidepid;
1588c2ecf20Sopenharmony_ci	if (ctx->mask & (1 << Opt_subset))
1598c2ecf20Sopenharmony_ci		fs_info->pidonly = ctx->pidonly;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic int proc_fill_super(struct super_block *s, struct fs_context *fc)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct proc_fs_context *ctx = fc->fs_private;
1658c2ecf20Sopenharmony_ci	struct inode *root_inode;
1668c2ecf20Sopenharmony_ci	struct proc_fs_info *fs_info;
1678c2ecf20Sopenharmony_ci	int ret;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	fs_info = kzalloc(sizeof(*fs_info), GFP_KERNEL);
1708c2ecf20Sopenharmony_ci	if (!fs_info)
1718c2ecf20Sopenharmony_ci		return -ENOMEM;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	fs_info->pid_ns = get_pid_ns(ctx->pid_ns);
1748c2ecf20Sopenharmony_ci	proc_apply_options(fs_info, fc, current_user_ns());
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	/* User space would break if executables or devices appear on proc */
1778c2ecf20Sopenharmony_ci	s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV;
1788c2ecf20Sopenharmony_ci	s->s_flags |= SB_NODIRATIME | SB_NOSUID | SB_NOEXEC;
1798c2ecf20Sopenharmony_ci	s->s_blocksize = 1024;
1808c2ecf20Sopenharmony_ci	s->s_blocksize_bits = 10;
1818c2ecf20Sopenharmony_ci	s->s_magic = PROC_SUPER_MAGIC;
1828c2ecf20Sopenharmony_ci	s->s_op = &proc_sops;
1838c2ecf20Sopenharmony_ci	s->s_time_gran = 1;
1848c2ecf20Sopenharmony_ci	s->s_fs_info = fs_info;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/*
1878c2ecf20Sopenharmony_ci	 * procfs isn't actually a stacking filesystem; however, there is
1888c2ecf20Sopenharmony_ci	 * too much magic going on inside it to permit stacking things on
1898c2ecf20Sopenharmony_ci	 * top of it
1908c2ecf20Sopenharmony_ci	 */
1918c2ecf20Sopenharmony_ci	s->s_stack_depth = FILESYSTEM_MAX_STACK_DEPTH;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* procfs dentries and inodes don't require IO to create */
1948c2ecf20Sopenharmony_ci	s->s_shrink.seeks = 0;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	pde_get(&proc_root);
1978c2ecf20Sopenharmony_ci	root_inode = proc_get_inode(s, &proc_root);
1988c2ecf20Sopenharmony_ci	if (!root_inode) {
1998c2ecf20Sopenharmony_ci		pr_err("proc_fill_super: get root inode failed\n");
2008c2ecf20Sopenharmony_ci		return -ENOMEM;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	s->s_root = d_make_root(root_inode);
2048c2ecf20Sopenharmony_ci	if (!s->s_root) {
2058c2ecf20Sopenharmony_ci		pr_err("proc_fill_super: allocate dentry failed\n");
2068c2ecf20Sopenharmony_ci		return -ENOMEM;
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	ret = proc_setup_self(s);
2108c2ecf20Sopenharmony_ci	if (ret) {
2118c2ecf20Sopenharmony_ci		return ret;
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci	return proc_setup_thread_self(s);
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic int proc_reconfigure(struct fs_context *fc)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct super_block *sb = fc->root->d_sb;
2198c2ecf20Sopenharmony_ci	struct proc_fs_info *fs_info = proc_sb_info(sb);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	sync_filesystem(sb);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	proc_apply_options(fs_info, fc, current_user_ns());
2248c2ecf20Sopenharmony_ci	return 0;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic int proc_get_tree(struct fs_context *fc)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	return get_tree_nodev(fc, proc_fill_super);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic void proc_fs_context_free(struct fs_context *fc)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct proc_fs_context *ctx = fc->fs_private;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	put_pid_ns(ctx->pid_ns);
2378c2ecf20Sopenharmony_ci	kfree(ctx);
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic const struct fs_context_operations proc_fs_context_ops = {
2418c2ecf20Sopenharmony_ci	.free		= proc_fs_context_free,
2428c2ecf20Sopenharmony_ci	.parse_param	= proc_parse_param,
2438c2ecf20Sopenharmony_ci	.get_tree	= proc_get_tree,
2448c2ecf20Sopenharmony_ci	.reconfigure	= proc_reconfigure,
2458c2ecf20Sopenharmony_ci};
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic int proc_init_fs_context(struct fs_context *fc)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	struct proc_fs_context *ctx;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	ctx = kzalloc(sizeof(struct proc_fs_context), GFP_KERNEL);
2528c2ecf20Sopenharmony_ci	if (!ctx)
2538c2ecf20Sopenharmony_ci		return -ENOMEM;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	ctx->pid_ns = get_pid_ns(task_active_pid_ns(current));
2568c2ecf20Sopenharmony_ci	put_user_ns(fc->user_ns);
2578c2ecf20Sopenharmony_ci	fc->user_ns = get_user_ns(ctx->pid_ns->user_ns);
2588c2ecf20Sopenharmony_ci	fc->fs_private = ctx;
2598c2ecf20Sopenharmony_ci	fc->ops = &proc_fs_context_ops;
2608c2ecf20Sopenharmony_ci	return 0;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic void proc_kill_sb(struct super_block *sb)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	struct proc_fs_info *fs_info = proc_sb_info(sb);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (!fs_info) {
2688c2ecf20Sopenharmony_ci		kill_anon_super(sb);
2698c2ecf20Sopenharmony_ci		return;
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	dput(fs_info->proc_self);
2738c2ecf20Sopenharmony_ci	dput(fs_info->proc_thread_self);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	kill_anon_super(sb);
2768c2ecf20Sopenharmony_ci	put_pid_ns(fs_info->pid_ns);
2778c2ecf20Sopenharmony_ci	kfree(fs_info);
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic struct file_system_type proc_fs_type = {
2818c2ecf20Sopenharmony_ci	.name			= "proc",
2828c2ecf20Sopenharmony_ci	.init_fs_context	= proc_init_fs_context,
2838c2ecf20Sopenharmony_ci	.parameters		= proc_fs_parameters,
2848c2ecf20Sopenharmony_ci	.kill_sb		= proc_kill_sb,
2858c2ecf20Sopenharmony_ci	.fs_flags		= FS_USERNS_MOUNT | FS_DISALLOW_NOTIFY_PERM,
2868c2ecf20Sopenharmony_ci};
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_civoid __init proc_root_init(void)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	proc_init_kmemcache();
2918c2ecf20Sopenharmony_ci	set_proc_pid_nlink();
2928c2ecf20Sopenharmony_ci	proc_self_init();
2938c2ecf20Sopenharmony_ci	proc_thread_self_init();
2948c2ecf20Sopenharmony_ci	proc_symlink("mounts", NULL, "self/mounts");
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	proc_net_init();
2978c2ecf20Sopenharmony_ci	proc_mkdir("fs", NULL);
2988c2ecf20Sopenharmony_ci	proc_mkdir("driver", NULL);
2998c2ecf20Sopenharmony_ci	proc_create_mount_point("fs/nfsd"); /* somewhere for the nfsd filesystem to be mounted */
3008c2ecf20Sopenharmony_ci#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
3018c2ecf20Sopenharmony_ci	/* just give it a mountpoint */
3028c2ecf20Sopenharmony_ci	proc_create_mount_point("openprom");
3038c2ecf20Sopenharmony_ci#endif
3048c2ecf20Sopenharmony_ci	proc_tty_init();
3058c2ecf20Sopenharmony_ci	proc_mkdir("bus", NULL);
3068c2ecf20Sopenharmony_ci	proc_sys_init();
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	register_filesystem(&proc_fs_type);
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic int proc_root_getattr(const struct path *path, struct kstat *stat,
3128c2ecf20Sopenharmony_ci			     u32 request_mask, unsigned int query_flags)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	generic_fillattr(d_inode(path->dentry), stat);
3158c2ecf20Sopenharmony_ci	stat->nlink = proc_root.nlink + nr_processes();
3168c2ecf20Sopenharmony_ci	return 0;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	if (!proc_pid_lookup(dentry, flags))
3228c2ecf20Sopenharmony_ci		return NULL;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	return proc_lookup(dir, dentry, flags);
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic int proc_root_readdir(struct file *file, struct dir_context *ctx)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	if (ctx->pos < FIRST_PROCESS_ENTRY) {
3308c2ecf20Sopenharmony_ci		int error = proc_readdir(file, ctx);
3318c2ecf20Sopenharmony_ci		if (unlikely(error <= 0))
3328c2ecf20Sopenharmony_ci			return error;
3338c2ecf20Sopenharmony_ci		ctx->pos = FIRST_PROCESS_ENTRY;
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	return proc_pid_readdir(file, ctx);
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci/*
3408c2ecf20Sopenharmony_ci * The root /proc directory is special, as it has the
3418c2ecf20Sopenharmony_ci * <pid> directories. Thus we don't use the generic
3428c2ecf20Sopenharmony_ci * directory handling functions for that..
3438c2ecf20Sopenharmony_ci */
3448c2ecf20Sopenharmony_cistatic const struct file_operations proc_root_operations = {
3458c2ecf20Sopenharmony_ci	.read		 = generic_read_dir,
3468c2ecf20Sopenharmony_ci	.iterate_shared	 = proc_root_readdir,
3478c2ecf20Sopenharmony_ci	.llseek		= generic_file_llseek,
3488c2ecf20Sopenharmony_ci};
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci/*
3518c2ecf20Sopenharmony_ci * proc root can do almost nothing..
3528c2ecf20Sopenharmony_ci */
3538c2ecf20Sopenharmony_cistatic const struct inode_operations proc_root_inode_operations = {
3548c2ecf20Sopenharmony_ci	.lookup		= proc_root_lookup,
3558c2ecf20Sopenharmony_ci	.getattr	= proc_root_getattr,
3568c2ecf20Sopenharmony_ci};
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci/*
3598c2ecf20Sopenharmony_ci * This is the root "inode" in the /proc tree..
3608c2ecf20Sopenharmony_ci */
3618c2ecf20Sopenharmony_cistruct proc_dir_entry proc_root = {
3628c2ecf20Sopenharmony_ci	.low_ino	= PROC_ROOT_INO,
3638c2ecf20Sopenharmony_ci	.namelen	= 5,
3648c2ecf20Sopenharmony_ci	.mode		= S_IFDIR | S_IRUGO | S_IXUGO,
3658c2ecf20Sopenharmony_ci	.nlink		= 2,
3668c2ecf20Sopenharmony_ci	.refcnt		= REFCOUNT_INIT(1),
3678c2ecf20Sopenharmony_ci	.proc_iops	= &proc_root_inode_operations,
3688c2ecf20Sopenharmony_ci	.proc_dir_ops	= &proc_root_operations,
3698c2ecf20Sopenharmony_ci	.parent		= &proc_root,
3708c2ecf20Sopenharmony_ci	.subdir		= RB_ROOT,
3718c2ecf20Sopenharmony_ci	.name		= "/proc",
3728c2ecf20Sopenharmony_ci};
373