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