Commit | Line | Data |
---|---|---|
59d8053f | 1 | /* Internal procfs definitions |
1da177e4 LT |
2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | |
4 | * Written by David Howells (dhowells@redhat.com) | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the License, or (at your option) any later version. | |
10 | */ | |
11 | ||
12 | #include <linux/proc_fs.h> | |
59d8053f DH |
13 | #include <linux/proc_ns.h> |
14 | #include <linux/spinlock.h> | |
15 | #include <linux/atomic.h> | |
e579d2c2 | 16 | #include <linux/binfmts.h> |
1da177e4 | 17 | |
59d8053f DH |
18 | struct ctl_table_header; |
19 | struct mempolicy; | |
77b14db5 | 20 | |
59d8053f DH |
21 | /* |
22 | * This is not completely implemented yet. The idea is to | |
23 | * create an in-memory tree (like the actual /proc filesystem | |
24 | * tree) of these proc_dir_entries, so that we can dynamically | |
25 | * add new files to /proc. | |
26 | * | |
710585d4 ND |
27 | * parent/subdir are used for the directory structure (every /proc file has a |
28 | * parent, but "subdir" is empty for all non-directory entries). | |
29 | * subdir_node is used to build the rb tree "subdir" of the parent. | |
59d8053f DH |
30 | */ |
31 | struct proc_dir_entry { | |
32 | unsigned int low_ino; | |
33 | umode_t mode; | |
34 | nlink_t nlink; | |
35 | kuid_t uid; | |
36 | kgid_t gid; | |
37 | loff_t size; | |
38 | const struct inode_operations *proc_iops; | |
39 | const struct file_operations *proc_fops; | |
710585d4 ND |
40 | struct proc_dir_entry *parent; |
41 | struct rb_root subdir; | |
42 | struct rb_node subdir_node; | |
59d8053f DH |
43 | void *data; |
44 | atomic_t count; /* use count */ | |
45 | atomic_t in_use; /* number of callers into module in progress; */ | |
46 | /* negative -> it's going away RSN */ | |
47 | struct completion *pde_unload_completion; | |
48 | struct list_head pde_openers; /* who did ->open, but not ->release */ | |
49 | spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */ | |
50 | u8 namelen; | |
51 | char name[]; | |
1da177e4 | 52 | }; |
1da177e4 | 53 | |
59d8053f DH |
54 | union proc_op { |
55 | int (*proc_get_link)(struct dentry *, struct path *); | |
59d8053f DH |
56 | int (*proc_show)(struct seq_file *m, |
57 | struct pid_namespace *ns, struct pid *pid, | |
58 | struct task_struct *task); | |
59 | }; | |
99f89551 | 60 | |
59d8053f | 61 | struct proc_inode { |
f2beb798 | 62 | struct pid *pid; |
e4df6681 | 63 | unsigned int fd; |
59d8053f DH |
64 | union proc_op op; |
65 | struct proc_dir_entry *pde; | |
66 | struct ctl_table_header *sysctl; | |
67 | struct ctl_table *sysctl_entry; | |
3d3d35b1 | 68 | const struct proc_ns_operations *ns_ops; |
59d8053f | 69 | struct inode vfs_inode; |
f2beb798 SW |
70 | }; |
71 | ||
c30480b9 DH |
72 | /* |
73 | * General functions | |
74 | */ | |
75 | static inline struct proc_inode *PROC_I(const struct inode *inode) | |
76 | { | |
77 | return container_of(inode, struct proc_inode, vfs_inode); | |
78 | } | |
79 | ||
80 | static inline struct proc_dir_entry *PDE(const struct inode *inode) | |
81 | { | |
82 | return PROC_I(inode)->pde; | |
83 | } | |
84 | ||
85 | static inline void *__PDE_DATA(const struct inode *inode) | |
86 | { | |
87 | return PDE(inode)->data; | |
88 | } | |
fee781e6 | 89 | |
13b41b09 | 90 | static inline struct pid *proc_pid(struct inode *inode) |
99f89551 | 91 | { |
13b41b09 | 92 | return PROC_I(inode)->pid; |
99f89551 EB |
93 | } |
94 | ||
95 | static inline struct task_struct *get_proc_task(struct inode *inode) | |
1da177e4 | 96 | { |
13b41b09 | 97 | return get_pid_task(proc_pid(inode), PIDTYPE_PID); |
1da177e4 LT |
98 | } |
99 | ||
faf60af1 CG |
100 | static inline int task_dumpable(struct task_struct *task) |
101 | { | |
102 | int dumpable = 0; | |
103 | struct mm_struct *mm; | |
104 | ||
105 | task_lock(task); | |
106 | mm = task->mm; | |
107 | if (mm) | |
108 | dumpable = get_dumpable(mm); | |
109 | task_unlock(task); | |
e579d2c2 | 110 | if (dumpable == SUID_DUMP_USER) |
faf60af1 CG |
111 | return 1; |
112 | return 0; | |
113 | } | |
114 | ||
dbcdb504 | 115 | static inline unsigned name_to_int(const struct qstr *qstr) |
faf60af1 | 116 | { |
dbcdb504 AD |
117 | const char *name = qstr->name; |
118 | int len = qstr->len; | |
faf60af1 CG |
119 | unsigned n = 0; |
120 | ||
121 | if (len > 1 && *name == '0') | |
122 | goto out; | |
123 | while (len-- > 0) { | |
124 | unsigned c = *name++ - '0'; | |
125 | if (c > 9) | |
126 | goto out; | |
127 | if (n >= (~0U-9)/10) | |
128 | goto out; | |
129 | n *= 10; | |
130 | n += c; | |
131 | } | |
132 | return n; | |
133 | out: | |
134 | return ~0U; | |
135 | } | |
136 | ||
1dd704b6 | 137 | /* |
59d8053f | 138 | * Offset of the first process in the /proc root directory.. |
1dd704b6 | 139 | */ |
59d8053f | 140 | #define FIRST_PROCESS_ENTRY 256 |
1dd704b6 | 141 | |
59d8053f DH |
142 | /* Worst case buffer size needed for holding an integer. */ |
143 | #define PROC_NUMBUF 13 | |
881adb85 | 144 | |
59d8053f DH |
145 | /* |
146 | * array.c | |
147 | */ | |
148 | extern const struct file_operations proc_tid_children_operations; | |
3174c21b | 149 | |
59d8053f DH |
150 | extern int proc_tid_stat(struct seq_file *, struct pid_namespace *, |
151 | struct pid *, struct task_struct *); | |
152 | extern int proc_tgid_stat(struct seq_file *, struct pid_namespace *, | |
153 | struct pid *, struct task_struct *); | |
154 | extern int proc_pid_status(struct seq_file *, struct pid_namespace *, | |
155 | struct pid *, struct task_struct *); | |
156 | extern int proc_pid_statm(struct seq_file *, struct pid_namespace *, | |
157 | struct pid *, struct task_struct *); | |
158 | ||
159 | /* | |
160 | * base.c | |
161 | */ | |
162 | extern const struct dentry_operations pid_dentry_operations; | |
163 | extern int pid_getattr(struct vfsmount *, struct dentry *, struct kstat *); | |
164 | extern int proc_setattr(struct dentry *, struct iattr *); | |
165 | extern struct inode *proc_pid_make_inode(struct super_block *, struct task_struct *); | |
166 | extern int pid_revalidate(struct dentry *, unsigned int); | |
167 | extern int pid_delete_dentry(const struct dentry *); | |
f0c3b509 | 168 | extern int proc_pid_readdir(struct file *, struct dir_context *); |
59d8053f DH |
169 | extern struct dentry *proc_pid_lookup(struct inode *, struct dentry *, unsigned int); |
170 | extern loff_t mem_lseek(struct file *, loff_t, int); | |
866ad9a7 | 171 | |
59d8053f | 172 | /* Lookups */ |
c52a47ac | 173 | typedef int instantiate_t(struct inode *, struct dentry *, |
59d8053f | 174 | struct task_struct *, const void *); |
f0c3b509 | 175 | extern bool proc_fill_cache(struct file *, struct dir_context *, const char *, int, |
59d8053f | 176 | instantiate_t, struct task_struct *, const void *); |
3174c21b | 177 | |
59d8053f DH |
178 | /* |
179 | * generic.c | |
180 | */ | |
59d8053f DH |
181 | extern struct dentry *proc_lookup(struct inode *, struct dentry *, unsigned int); |
182 | extern struct dentry *proc_lookup_de(struct proc_dir_entry *, struct inode *, | |
183 | struct dentry *); | |
f0c3b509 AV |
184 | extern int proc_readdir(struct file *, struct dir_context *); |
185 | extern int proc_readdir_de(struct proc_dir_entry *, struct file *, struct dir_context *); | |
3174c21b | 186 | |
135d5655 AD |
187 | static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) |
188 | { | |
189 | atomic_inc(&pde->count); | |
190 | return pde; | |
191 | } | |
59d8053f | 192 | extern void pde_put(struct proc_dir_entry *); |
3174c21b | 193 | |
eb6d38d5 EB |
194 | static inline bool is_empty_pde(const struct proc_dir_entry *pde) |
195 | { | |
196 | return S_ISDIR(pde->mode) && !pde->proc_iops; | |
197 | } | |
198 | struct proc_dir_entry *proc_create_mount_point(const char *name); | |
199 | ||
3174c21b | 200 | /* |
59d8053f | 201 | * inode.c |
3174c21b | 202 | */ |
59d8053f DH |
203 | struct pde_opener { |
204 | struct file *file; | |
205 | struct list_head lh; | |
206 | int closing; | |
207 | struct completion *c; | |
208 | }; | |
7e0e953b | 209 | extern const struct inode_operations proc_link_inode_operations; |
6b4e306a | 210 | |
59d8053f | 211 | extern const struct inode_operations proc_pid_link_inode_operations; |
6b4e306a | 212 | |
59d8053f DH |
213 | extern void proc_init_inodecache(void); |
214 | extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); | |
e94591d0 | 215 | extern int proc_fill_super(struct super_block *, void *data, int flags); |
59d8053f | 216 | extern void proc_entry_rundown(struct proc_dir_entry *); |
6b4e306a | 217 | |
59d8053f DH |
218 | /* |
219 | * proc_namespaces.c | |
220 | */ | |
6b4e306a EB |
221 | extern const struct inode_operations proc_ns_dir_inode_operations; |
222 | extern const struct file_operations proc_ns_dir_operations; | |
223 | ||
59d8053f DH |
224 | /* |
225 | * proc_net.c | |
226 | */ | |
227 | extern const struct file_operations proc_net_operations; | |
228 | extern const struct inode_operations proc_net_inode_operations; | |
229 | ||
230 | #ifdef CONFIG_NET | |
231 | extern int proc_net_init(void); | |
232 | #else | |
233 | static inline int proc_net_init(void) { return 0; } | |
234 | #endif | |
235 | ||
236 | /* | |
237 | * proc_self.c | |
238 | */ | |
021ada7d | 239 | extern int proc_setup_self(struct super_block *); |
34db8aaf | 240 | |
0097875b EB |
241 | /* |
242 | * proc_thread_self.c | |
243 | */ | |
244 | extern int proc_setup_thread_self(struct super_block *); | |
245 | extern void proc_thread_self_init(void); | |
246 | ||
34db8aaf | 247 | /* |
59d8053f | 248 | * proc_sysctl.c |
34db8aaf | 249 | */ |
59d8053f DH |
250 | #ifdef CONFIG_PROC_SYSCTL |
251 | extern int proc_sys_init(void); | |
252 | extern void sysctl_head_put(struct ctl_table_header *); | |
253 | #else | |
254 | static inline void proc_sys_init(void) { } | |
255 | static inline void sysctl_head_put(struct ctl_table_header *head) { } | |
256 | #endif | |
34db8aaf DH |
257 | |
258 | /* | |
259 | * proc_tty.c | |
260 | */ | |
261 | #ifdef CONFIG_TTY | |
262 | extern void proc_tty_init(void); | |
263 | #else | |
264 | static inline void proc_tty_init(void) {} | |
265 | #endif | |
59d8053f DH |
266 | |
267 | /* | |
268 | * root.c | |
269 | */ | |
270 | extern struct proc_dir_entry proc_root; | |
e94591d0 | 271 | extern int proc_parse_options(char *options, struct pid_namespace *pid); |
59d8053f DH |
272 | |
273 | extern void proc_self_init(void); | |
274 | extern int proc_remount(struct super_block *, int *, char *); | |
275 | ||
276 | /* | |
277 | * task_[no]mmu.c | |
278 | */ | |
279 | struct proc_maps_private { | |
2c03376d | 280 | struct inode *inode; |
59d8053f | 281 | struct task_struct *task; |
29a40ace | 282 | struct mm_struct *mm; |
59d8053f DH |
283 | #ifdef CONFIG_MMU |
284 | struct vm_area_struct *tail_vma; | |
285 | #endif | |
286 | #ifdef CONFIG_NUMA | |
287 | struct mempolicy *task_mempolicy; | |
288 | #endif | |
289 | }; | |
290 | ||
5381e169 ON |
291 | struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode); |
292 | ||
59d8053f DH |
293 | extern const struct file_operations proc_pid_maps_operations; |
294 | extern const struct file_operations proc_tid_maps_operations; | |
295 | extern const struct file_operations proc_pid_numa_maps_operations; | |
296 | extern const struct file_operations proc_tid_numa_maps_operations; | |
297 | extern const struct file_operations proc_pid_smaps_operations; | |
298 | extern const struct file_operations proc_tid_smaps_operations; | |
299 | extern const struct file_operations proc_clear_refs_operations; | |
300 | extern const struct file_operations proc_pagemap_operations; | |
301 | ||
302 | extern unsigned long task_vsize(struct mm_struct *); | |
303 | extern unsigned long task_statm(struct mm_struct *, | |
304 | unsigned long *, unsigned long *, | |
305 | unsigned long *, unsigned long *); | |
306 | extern void task_mem(struct seq_file *, struct mm_struct *); |