Blame view
fs/proc/inode.c
17.3 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 6 |
/* * linux/fs/proc/inode.c * * Copyright (C) 1991, 1992 Linus Torvalds */ |
efb1a57d9 fs/proc: use __ro... |
7 |
#include <linux/cache.h> |
1da177e4c Linux-2.6.12-rc2 |
8 9 10 |
#include <linux/time.h> #include <linux/proc_fs.h> #include <linux/kernel.h> |
97412950b procfs: parse mou... |
11 |
#include <linux/pid_namespace.h> |
1da177e4c Linux-2.6.12-rc2 |
12 13 14 |
#include <linux/mm.h> #include <linux/string.h> #include <linux/stat.h> |
786d7e161 Fix rmmod/read/wr... |
15 |
#include <linux/completion.h> |
dd23aae4f Fix select on /pr... |
16 |
#include <linux/poll.h> |
87ebdc00e fs/proc: clean up... |
17 |
#include <linux/printk.h> |
1da177e4c Linux-2.6.12-rc2 |
18 19 20 21 |
#include <linux/file.h> #include <linux/limits.h> #include <linux/init.h> #include <linux/module.h> |
9043476f7 [PATCH] sanitize ... |
22 |
#include <linux/sysctl.h> |
97412950b procfs: parse mou... |
23 |
#include <linux/seq_file.h> |
5a0e3ad6a include cleanup: ... |
24 |
#include <linux/slab.h> |
97412950b procfs: parse mou... |
25 |
#include <linux/mount.h> |
1c6c4d112 proc: use human-r... |
26 |
#include <linux/bug.h> |
1da177e4c Linux-2.6.12-rc2 |
27 |
|
7c0f6ba68 Replace <asm/uacc... |
28 |
#include <linux/uaccess.h> |
1da177e4c Linux-2.6.12-rc2 |
29 |
|
fee781e6c [PATCH] fs/proc/:... |
30 |
#include "internal.h" |
1da177e4c Linux-2.6.12-rc2 |
31 |
|
8267952b3 switch procfs to ... |
32 |
static void proc_evict_inode(struct inode *inode) |
1da177e4c Linux-2.6.12-rc2 |
33 34 |
{ struct proc_dir_entry *de; |
dfef6dcd3 unfuck proc_sysct... |
35 |
struct ctl_table_header *head; |
71448011e proc: Clear the p... |
36 |
struct proc_inode *ei = PROC_I(inode); |
1da177e4c Linux-2.6.12-rc2 |
37 |
|
91b0abe36 mm + fs: store sh... |
38 |
truncate_inode_pages_final(&inode->i_data); |
dbd5768f8 vfs: Rename end_w... |
39 |
clear_inode(inode); |
fef266580 [PATCH] update fi... |
40 |
|
99f895518 [PATCH] proc: don... |
41 |
/* Stop tracking associated processes */ |
71448011e proc: Clear the p... |
42 |
if (ei->pid) { |
7bc3e6e55 proc: Use a list ... |
43 |
proc_pid_evict_inode(ei); |
71448011e proc: Clear the p... |
44 45 |
ei->pid = NULL; } |
1da177e4c Linux-2.6.12-rc2 |
46 47 |
/* Let go of any associated proc directory entry */ |
71448011e proc: Clear the p... |
48 49 |
de = ei->pde; if (de) { |
135d5655d proc: rename de_g... |
50 |
pde_put(de); |
71448011e proc: Clear the p... |
51 52 |
ei->pde = NULL; } |
d6cffbbe9 proc/sysctl: prun... |
53 |
|
71448011e proc: Clear the p... |
54 |
head = ei->sysctl; |
dfef6dcd3 unfuck proc_sysct... |
55 |
if (head) { |
71448011e proc: Clear the p... |
56 |
RCU_INIT_POINTER(ei->sysctl, NULL); |
d6cffbbe9 proc/sysctl: prun... |
57 |
proc_sys_evict_inode(inode, head); |
dfef6dcd3 unfuck proc_sysct... |
58 |
} |
1da177e4c Linux-2.6.12-rc2 |
59 |
} |
efb1a57d9 fs/proc: use __ro... |
60 |
static struct kmem_cache *proc_inode_cachep __ro_after_init; |
195b8cf06 proc: move "struc... |
61 |
static struct kmem_cache *pde_opener_cache __ro_after_init; |
1da177e4c Linux-2.6.12-rc2 |
62 63 64 65 |
static struct inode *proc_alloc_inode(struct super_block *sb) { struct proc_inode *ei; |
1da177e4c Linux-2.6.12-rc2 |
66 |
|
f245e1c17 fs/proc/inode.c: ... |
67 |
ei = kmem_cache_alloc(proc_inode_cachep, GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
68 69 |
if (!ei) return NULL; |
13b41b094 [PATCH] proc: Use... |
70 |
ei->pid = NULL; |
aed7a6c47 [PATCH] proc: Rep... |
71 |
ei->fd = 0; |
1da177e4c Linux-2.6.12-rc2 |
72 73 |
ei->op.proc_get_link = NULL; ei->pde = NULL; |
9043476f7 [PATCH] sanitize ... |
74 75 |
ei->sysctl = NULL; ei->sysctl_entry = NULL; |
0afa5ca82 proc: Rename in p... |
76 |
INIT_HLIST_NODE(&ei->sibling_inodes); |
3d3d35b1e kill proc_ns comp... |
77 |
ei->ns_ops = NULL; |
230f72e9f fs/proc/inode.c: ... |
78 |
return &ei->vfs_inode; |
1da177e4c Linux-2.6.12-rc2 |
79 |
} |
4aa6b55c0 procfs: switch to... |
80 |
static void proc_free_inode(struct inode *inode) |
1da177e4c Linux-2.6.12-rc2 |
81 82 83 |
{ kmem_cache_free(proc_inode_cachep, PROC_I(inode)); } |
51cc50685 SL*B: drop kmem c... |
84 |
static void init_once(void *foo) |
1da177e4c Linux-2.6.12-rc2 |
85 86 |
{ struct proc_inode *ei = (struct proc_inode *) foo; |
a35afb830 Remove SLAB_CTOR_... |
87 |
inode_init_once(&ei->vfs_inode); |
1da177e4c Linux-2.6.12-rc2 |
88 |
} |
20c2df83d mm: Remove slab d... |
89 |
|
195b8cf06 proc: move "struc... |
90 |
void __init proc_init_kmemcache(void) |
1da177e4c Linux-2.6.12-rc2 |
91 92 93 |
{ proc_inode_cachep = kmem_cache_create("proc_inode_cache", sizeof(struct proc_inode), |
fffb60f93 [PATCH] cpuset me... |
94 |
0, (SLAB_RECLAIM_ACCOUNT| |
5d097056c kmemcg: account c... |
95 96 |
SLAB_MEM_SPREAD|SLAB_ACCOUNT| SLAB_PANIC), |
20c2df83d mm: Remove slab d... |
97 |
init_once); |
195b8cf06 proc: move "struc... |
98 99 |
pde_opener_cache = kmem_cache_create("pde_opener", sizeof(struct pde_opener), 0, |
2acddbe81 proc: account "st... |
100 |
SLAB_ACCOUNT|SLAB_PANIC, NULL); |
b4884f233 proc: move "struc... |
101 |
proc_dir_entry_cache = kmem_cache_create_usercopy( |
2d6e4e822 proc: fixup PDE a... |
102 103 104 105 |
"proc_dir_entry", SIZEOF_PDE, 0, SLAB_PANIC, offsetof(struct proc_dir_entry, inline_name), SIZEOF_PDE_INLINE_NAME, NULL); BUILD_BUG_ON(sizeof(struct proc_dir_entry) >= SIZEOF_PDE); |
1da177e4c Linux-2.6.12-rc2 |
106 |
} |
f90f3cafe proc: Use d_inval... |
107 |
void proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock) |
26dbc60f3 proc: Generalize ... |
108 109 110 111 |
{ struct inode *inode; struct proc_inode *ei; struct hlist_node *node; |
080f6276f proc: In proc_pru... |
112 |
struct super_block *old_sb = NULL; |
26dbc60f3 proc: Generalize ... |
113 114 115 |
rcu_read_lock(); for (;;) { |
080f6276f proc: In proc_pru... |
116 |
struct super_block *sb; |
26dbc60f3 proc: Generalize ... |
117 118 119 120 121 122 123 124 125 126 |
node = hlist_first_rcu(inodes); if (!node) break; ei = hlist_entry(node, struct proc_inode, sibling_inodes); spin_lock(lock); hlist_del_init_rcu(&ei->sibling_inodes); spin_unlock(lock); inode = &ei->vfs_inode; sb = inode->i_sb; |
080f6276f proc: In proc_pru... |
127 |
if ((sb != old_sb) && !atomic_inc_not_zero(&sb->s_active)) |
26dbc60f3 proc: Generalize ... |
128 129 130 |
continue; inode = igrab(inode); rcu_read_unlock(); |
080f6276f proc: In proc_pru... |
131 132 133 134 135 |
if (sb != old_sb) { if (old_sb) deactivate_super(old_sb); old_sb = sb; } |
26dbc60f3 proc: Generalize ... |
136 |
if (unlikely(!inode)) { |
26dbc60f3 proc: Generalize ... |
137 138 139 |
rcu_read_lock(); continue; } |
f90f3cafe proc: Use d_inval... |
140 141 142 143 144 145 146 147 148 149 150 151 152 |
if (S_ISDIR(inode->i_mode)) { struct dentry *dir = d_find_any_alias(inode); if (dir) { d_invalidate(dir); dput(dir); } } else { struct dentry *dentry; while ((dentry = d_find_alias(inode))) { d_invalidate(dentry); dput(dentry); } } |
26dbc60f3 proc: Generalize ... |
153 |
iput(inode); |
26dbc60f3 proc: Generalize ... |
154 155 156 157 |
rcu_read_lock(); } rcu_read_unlock(); |
080f6276f proc: In proc_pru... |
158 159 |
if (old_sb) deactivate_super(old_sb); |
26dbc60f3 proc: Generalize ... |
160 |
} |
e61bb8b36 proc: use named e... |
161 |
static inline const char *hidepid2str(enum proc_hidepid v) |
1c6c4d112 proc: use human-r... |
162 163 164 165 166 167 168 169 170 171 172 |
{ switch (v) { case HIDEPID_OFF: return "off"; case HIDEPID_NO_ACCESS: return "noaccess"; case HIDEPID_INVISIBLE: return "invisible"; case HIDEPID_NOT_PTRACEABLE: return "ptraceable"; } WARN_ONCE(1, "bad hide_pid value: %d ", v); return "unknown"; } |
97412950b procfs: parse mou... |
173 174 |
static int proc_show_options(struct seq_file *seq, struct dentry *root) { |
fa10fed30 proc: allow to mo... |
175 |
struct proc_fs_info *fs_info = proc_sb_info(root->d_sb); |
0499680a4 procfs: add hidep... |
176 |
|
fa10fed30 proc: allow to mo... |
177 178 179 |
if (!gid_eq(fs_info->pid_gid, GLOBAL_ROOT_GID)) seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, fs_info->pid_gid)); if (fs_info->hide_pid != HIDEPID_OFF) |
1c6c4d112 proc: use human-r... |
180 |
seq_printf(seq, ",hidepid=%s", hidepid2str(fs_info->hide_pid)); |
6814ef2d9 proc: add option ... |
181 182 |
if (fs_info->pidonly != PROC_PIDONLY_OFF) seq_printf(seq, ",subset=pid"); |
0499680a4 procfs: add hidep... |
183 |
|
97412950b procfs: parse mou... |
184 185 |
return 0; } |
60a3c3a58 procfs: Move proc... |
186 |
const struct super_operations proc_sops = { |
1da177e4c Linux-2.6.12-rc2 |
187 |
.alloc_inode = proc_alloc_inode, |
4aa6b55c0 procfs: switch to... |
188 |
.free_inode = proc_free_inode, |
1da177e4c Linux-2.6.12-rc2 |
189 |
.drop_inode = generic_delete_inode, |
8267952b3 switch procfs to ... |
190 |
.evict_inode = proc_evict_inode, |
1da177e4c Linux-2.6.12-rc2 |
191 |
.statfs = simple_statfs, |
97412950b procfs: parse mou... |
192 |
.show_options = proc_show_options, |
1da177e4c Linux-2.6.12-rc2 |
193 |
}; |
866ad9a74 procfs: preparati... |
194 195 196 197 |
enum {BIAS = -1U<<31}; static inline int use_pde(struct proc_dir_entry *pde) { |
15b158b4e proc: spread like... |
198 |
return likely(atomic_inc_unless_negative(&pde->in_use)); |
881adb853 proc: always do -... |
199 |
} |
866ad9a74 procfs: preparati... |
200 |
static void unuse_pde(struct proc_dir_entry *pde) |
881adb853 proc: always do -... |
201 |
{ |
15b158b4e proc: spread like... |
202 |
if (unlikely(atomic_dec_return(&pde->in_use) == BIAS)) |
05c0ae21c try a saner locki... |
203 |
complete(pde->pde_unload_completion); |
786d7e161 Fix rmmod/read/wr... |
204 |
} |
2f8974243 proc: do less stu... |
205 |
/* pde is locked on entry, unlocked on exit */ |
ca469f35a deal with races b... |
206 |
static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) |
904f394e2 fs/proc/inode.c: ... |
207 |
__releases(&pde->pde_unload_lock) |
ca469f35a deal with races b... |
208 |
{ |
492b2da60 proc: tweak comme... |
209 210 211 212 213 214 215 216 217 218 |
/* * close() (proc_reg_release()) can't delete an entry and proceed: * ->release hook needs to be available at the right moment. * * rmmod (remove_proc_entry() et al) can't delete an entry and proceed: * "struct file" needs to be available at the right moment. * * Therefore, first process to enter this function does ->release() and * signals its completion to the other process which does nothing. */ |
05c0ae21c try a saner locki... |
219 |
if (pdeo->closing) { |
ca469f35a deal with races b... |
220 |
/* somebody else is doing that, just wait */ |
05c0ae21c try a saner locki... |
221 222 |
DECLARE_COMPLETION_ONSTACK(c); pdeo->c = &c; |
ca469f35a deal with races b... |
223 |
spin_unlock(&pde->pde_unload_lock); |
05c0ae21c try a saner locki... |
224 |
wait_for_completion(&c); |
ca469f35a deal with races b... |
225 226 |
} else { struct file *file; |
2f8974243 proc: do less stu... |
227 |
struct completion *c; |
f5887c71c proc: fix type of... |
228 |
pdeo->closing = true; |
ca469f35a deal with races b... |
229 230 |
spin_unlock(&pde->pde_unload_lock); file = pdeo->file; |
d56c0d45f proc: decouple pr... |
231 |
pde->proc_ops->proc_release(file_inode(file), file); |
ca469f35a deal with races b... |
232 |
spin_lock(&pde->pde_unload_lock); |
492b2da60 proc: tweak comme... |
233 |
/* After ->release. */ |
06a0c4175 proc: just list_d... |
234 |
list_del(&pdeo->lh); |
2f8974243 proc: do less stu... |
235 236 237 238 |
c = pdeo->c; spin_unlock(&pde->pde_unload_lock); if (unlikely(c)) complete(c); |
195b8cf06 proc: move "struc... |
239 |
kmem_cache_free(pde_opener_cache, pdeo); |
05c0ae21c try a saner locki... |
240 |
} |
ca469f35a deal with races b... |
241 |
} |
866ad9a74 procfs: preparati... |
242 |
void proc_entry_rundown(struct proc_dir_entry *de) |
786d7e161 Fix rmmod/read/wr... |
243 |
{ |
05c0ae21c try a saner locki... |
244 |
DECLARE_COMPLETION_ONSTACK(c); |
866ad9a74 procfs: preparati... |
245 |
/* Wait until all existing callers into module are done. */ |
05c0ae21c try a saner locki... |
246 247 248 |
de->pde_unload_completion = &c; if (atomic_add_return(BIAS, &de->in_use) != BIAS) wait_for_completion(&c); |
786d7e161 Fix rmmod/read/wr... |
249 |
|
492b2da60 proc: tweak comme... |
250 |
/* ->pde_openers list can't grow from now on. */ |
05c0ae21c try a saner locki... |
251 |
spin_lock(&de->pde_unload_lock); |
866ad9a74 procfs: preparati... |
252 253 |
while (!list_empty(&de->pde_openers)) { struct pde_opener *pdeo; |
866ad9a74 procfs: preparati... |
254 |
pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh); |
ca469f35a deal with races b... |
255 |
close_pdeo(de, pdeo); |
2f8974243 proc: do less stu... |
256 |
spin_lock(&de->pde_unload_lock); |
866ad9a74 procfs: preparati... |
257 258 |
} spin_unlock(&de->pde_unload_lock); |
786d7e161 Fix rmmod/read/wr... |
259 |
} |
d919b33da proc: faster open... |
260 261 262 263 264 265 266 267 268 |
static loff_t pde_lseek(struct proc_dir_entry *pde, struct file *file, loff_t offset, int whence) { typeof_member(struct proc_ops, proc_lseek) lseek; lseek = pde->proc_ops->proc_lseek; if (!lseek) lseek = default_llseek; return lseek(file, offset, whence); } |
866ad9a74 procfs: preparati... |
269 270 271 272 |
static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence) { struct proc_dir_entry *pde = PDE(file_inode(file)); loff_t rv = -EINVAL; |
9af27b28b fs/proc/inode.c: ... |
273 |
|
d919b33da proc: faster open... |
274 275 276 277 |
if (pde_is_permanent(pde)) { return pde_lseek(pde, file, offset, whence); } else if (use_pde(pde)) { rv = pde_lseek(pde, file, offset, whence); |
866ad9a74 procfs: preparati... |
278 279 |
unuse_pde(pde); } |
786d7e161 Fix rmmod/read/wr... |
280 281 |
return rv; } |
fd5a13f48 proc: add a read_... |
282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
static ssize_t proc_reg_read_iter(struct kiocb *iocb, struct iov_iter *iter) { struct proc_dir_entry *pde = PDE(file_inode(iocb->ki_filp)); ssize_t ret; if (pde_is_permanent(pde)) return pde->proc_ops->proc_read_iter(iocb, iter); if (!use_pde(pde)) return -EIO; ret = pde->proc_ops->proc_read_iter(iocb, iter); unuse_pde(pde); return ret; } |
d919b33da proc: faster open... |
296 297 298 299 300 301 302 303 304 |
static ssize_t pde_read(struct proc_dir_entry *pde, struct file *file, char __user *buf, size_t count, loff_t *ppos) { typeof_member(struct proc_ops, proc_read) read; read = pde->proc_ops->proc_read; if (read) return read(file, buf, count, ppos); return -EIO; } |
866ad9a74 procfs: preparati... |
305 |
static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) |
786d7e161 Fix rmmod/read/wr... |
306 |
{ |
496ad9aa8 new helper: file_... |
307 |
struct proc_dir_entry *pde = PDE(file_inode(file)); |
786d7e161 Fix rmmod/read/wr... |
308 |
ssize_t rv = -EIO; |
9af27b28b fs/proc/inode.c: ... |
309 |
|
d919b33da proc: faster open... |
310 311 312 313 |
if (pde_is_permanent(pde)) { return pde_read(pde, file, buf, count, ppos); } else if (use_pde(pde)) { rv = pde_read(pde, file, buf, count, ppos); |
866ad9a74 procfs: preparati... |
314 |
unuse_pde(pde); |
786d7e161 Fix rmmod/read/wr... |
315 |
} |
866ad9a74 procfs: preparati... |
316 317 |
return rv; } |
786d7e161 Fix rmmod/read/wr... |
318 |
|
d919b33da proc: faster open... |
319 320 321 322 323 324 325 326 327 |
static ssize_t pde_write(struct proc_dir_entry *pde, struct file *file, const char __user *buf, size_t count, loff_t *ppos) { typeof_member(struct proc_ops, proc_write) write; write = pde->proc_ops->proc_write; if (write) return write(file, buf, count, ppos); return -EIO; } |
866ad9a74 procfs: preparati... |
328 329 |
static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { |
866ad9a74 procfs: preparati... |
330 331 |
struct proc_dir_entry *pde = PDE(file_inode(file)); ssize_t rv = -EIO; |
9af27b28b fs/proc/inode.c: ... |
332 |
|
d919b33da proc: faster open... |
333 334 335 336 |
if (pde_is_permanent(pde)) { return pde_write(pde, file, buf, count, ppos); } else if (use_pde(pde)) { rv = pde_write(pde, file, buf, count, ppos); |
866ad9a74 procfs: preparati... |
337 338 |
unuse_pde(pde); } |
786d7e161 Fix rmmod/read/wr... |
339 340 |
return rv; } |
d919b33da proc: faster open... |
341 342 343 344 345 346 347 348 349 |
static __poll_t pde_poll(struct proc_dir_entry *pde, struct file *file, struct poll_table_struct *pts) { typeof_member(struct proc_ops, proc_poll) poll; poll = pde->proc_ops->proc_poll; if (poll) return poll(file, pts); return DEFAULT_POLLMASK; } |
076ccb76e fs: annotate ->po... |
350 |
static __poll_t proc_reg_poll(struct file *file, struct poll_table_struct *pts) |
786d7e161 Fix rmmod/read/wr... |
351 |
{ |
496ad9aa8 new helper: file_... |
352 |
struct proc_dir_entry *pde = PDE(file_inode(file)); |
e6c8adca2 anntotate the pla... |
353 |
__poll_t rv = DEFAULT_POLLMASK; |
9af27b28b fs/proc/inode.c: ... |
354 |
|
d919b33da proc: faster open... |
355 356 357 358 |
if (pde_is_permanent(pde)) { return pde_poll(pde, file, pts); } else if (use_pde(pde)) { rv = pde_poll(pde, file, pts); |
866ad9a74 procfs: preparati... |
359 |
unuse_pde(pde); |
786d7e161 Fix rmmod/read/wr... |
360 |
} |
786d7e161 Fix rmmod/read/wr... |
361 362 |
return rv; } |
d919b33da proc: faster open... |
363 364 365 366 367 368 369 370 371 |
static long pde_ioctl(struct proc_dir_entry *pde, struct file *file, unsigned int cmd, unsigned long arg) { typeof_member(struct proc_ops, proc_ioctl) ioctl; ioctl = pde->proc_ops->proc_ioctl; if (ioctl) return ioctl(file, cmd, arg); return -ENOTTY; } |
786d7e161 Fix rmmod/read/wr... |
372 373 |
static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { |
496ad9aa8 new helper: file_... |
374 |
struct proc_dir_entry *pde = PDE(file_inode(file)); |
786d7e161 Fix rmmod/read/wr... |
375 |
long rv = -ENOTTY; |
9af27b28b fs/proc/inode.c: ... |
376 |
|
d919b33da proc: faster open... |
377 378 379 380 |
if (pde_is_permanent(pde)) { return pde_ioctl(pde, file, cmd, arg); } else if (use_pde(pde)) { rv = pde_ioctl(pde, file, cmd, arg); |
866ad9a74 procfs: preparati... |
381 |
unuse_pde(pde); |
786d7e161 Fix rmmod/read/wr... |
382 |
} |
786d7e161 Fix rmmod/read/wr... |
383 384 385 386 |
return rv; } #ifdef CONFIG_COMPAT |
d919b33da proc: faster open... |
387 388 389 390 391 392 393 394 395 |
static long pde_compat_ioctl(struct proc_dir_entry *pde, struct file *file, unsigned int cmd, unsigned long arg) { typeof_member(struct proc_ops, proc_compat_ioctl) compat_ioctl; compat_ioctl = pde->proc_ops->proc_compat_ioctl; if (compat_ioctl) return compat_ioctl(file, cmd, arg); return -ENOTTY; } |
786d7e161 Fix rmmod/read/wr... |
396 397 |
static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { |
496ad9aa8 new helper: file_... |
398 |
struct proc_dir_entry *pde = PDE(file_inode(file)); |
786d7e161 Fix rmmod/read/wr... |
399 |
long rv = -ENOTTY; |
d919b33da proc: faster open... |
400 401 402 403 |
if (pde_is_permanent(pde)) { return pde_compat_ioctl(pde, file, cmd, arg); } else if (use_pde(pde)) { rv = pde_compat_ioctl(pde, file, cmd, arg); |
866ad9a74 procfs: preparati... |
404 |
unuse_pde(pde); |
786d7e161 Fix rmmod/read/wr... |
405 |
} |
786d7e161 Fix rmmod/read/wr... |
406 407 408 |
return rv; } #endif |
d919b33da proc: faster open... |
409 410 411 412 413 414 415 416 417 |
static int pde_mmap(struct proc_dir_entry *pde, struct file *file, struct vm_area_struct *vma) { typeof_member(struct proc_ops, proc_mmap) mmap; mmap = pde->proc_ops->proc_mmap; if (mmap) return mmap(file, vma); return -EIO; } |
786d7e161 Fix rmmod/read/wr... |
418 419 |
static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma) { |
496ad9aa8 new helper: file_... |
420 |
struct proc_dir_entry *pde = PDE(file_inode(file)); |
786d7e161 Fix rmmod/read/wr... |
421 |
int rv = -EIO; |
9af27b28b fs/proc/inode.c: ... |
422 |
|
d919b33da proc: faster open... |
423 424 425 426 |
if (pde_is_permanent(pde)) { return pde_mmap(pde, file, vma); } else if (use_pde(pde)) { rv = pde_mmap(pde, file, vma); |
866ad9a74 procfs: preparati... |
427 |
unuse_pde(pde); |
786d7e161 Fix rmmod/read/wr... |
428 |
} |
786d7e161 Fix rmmod/read/wr... |
429 430 |
return rv; } |
5721cf84d procfs: clean up ... |
431 |
static unsigned long |
d919b33da proc: faster open... |
432 |
pde_get_unmapped_area(struct proc_dir_entry *pde, struct file *file, unsigned long orig_addr, |
5721cf84d procfs: clean up ... |
433 434 |
unsigned long len, unsigned long pgoff, unsigned long flags) |
c4fe24485 sparc: fix PCI de... |
435 |
{ |
d919b33da proc: faster open... |
436 |
typeof_member(struct proc_ops, proc_get_unmapped_area) get_area; |
ae5758a1a procfs: also fix ... |
437 |
|
d919b33da proc: faster open... |
438 |
get_area = pde->proc_ops->proc_get_unmapped_area; |
fad1a86e2 procfs: call defa... |
439 |
#ifdef CONFIG_MMU |
d919b33da proc: faster open... |
440 441 |
if (!get_area) get_area = current->mm->get_unmapped_area; |
fad1a86e2 procfs: call defa... |
442 |
#endif |
d919b33da proc: faster open... |
443 444 445 446 447 448 449 450 451 452 453 454 |
if (get_area) return get_area(file, orig_addr, len, pgoff, flags); return orig_addr; } static unsigned long proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct proc_dir_entry *pde = PDE(file_inode(file)); unsigned long rv = -EIO; |
ae5758a1a procfs: also fix ... |
455 |
|
d919b33da proc: faster open... |
456 457 458 459 |
if (pde_is_permanent(pde)) { return pde_get_unmapped_area(pde, file, orig_addr, len, pgoff, flags); } else if (use_pde(pde)) { rv = pde_get_unmapped_area(pde, file, orig_addr, len, pgoff, flags); |
c4fe24485 sparc: fix PCI de... |
460 461 462 463 |
unuse_pde(pde); } return rv; } |
786d7e161 Fix rmmod/read/wr... |
464 465 |
static int proc_reg_open(struct inode *inode, struct file *file) { |
6814ef2d9 proc: add option ... |
466 |
struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); |
786d7e161 Fix rmmod/read/wr... |
467 468 |
struct proc_dir_entry *pde = PDE(inode); int rv = 0; |
d56c0d45f proc: decouple pr... |
469 470 |
typeof_member(struct proc_ops, proc_open) open; typeof_member(struct proc_ops, proc_release) release; |
881adb853 proc: always do -... |
471 |
struct pde_opener *pdeo; |
d919b33da proc: faster open... |
472 473 474 475 476 477 |
if (pde_is_permanent(pde)) { open = pde->proc_ops->proc_open; if (open) rv = open(inode, file); return rv; } |
6814ef2d9 proc: add option ... |
478 479 |
if (fs_info->pidonly == PROC_PIDONLY_ON) return -ENOENT; |
881adb853 proc: always do -... |
480 |
/* |
492b2da60 proc: tweak comme... |
481 482 483 484 485 486 487 |
* Ensure that * 1) PDE's ->release hook will be called no matter what * either normally by close()/->release, or forcefully by * rmmod/remove_proc_entry. * * 2) rmmod isn't blocked by opening file in /proc and sitting on * the descriptor (including "rmmod foo </proc/foo" scenario). |
881adb853 proc: always do -... |
488 |
* |
492b2da60 proc: tweak comme... |
489 |
* Save every "struct file" with custom ->release hook. |
881adb853 proc: always do -... |
490 |
*/ |
e7a6e291e proc: faster open... |
491 |
if (!use_pde(pde)) |
d2857e79a procfs: return EN... |
492 |
return -ENOENT; |
e7a6e291e proc: faster open... |
493 |
|
d56c0d45f proc: decouple pr... |
494 |
release = pde->proc_ops->proc_release; |
e7a6e291e proc: faster open... |
495 |
if (release) { |
195b8cf06 proc: move "struc... |
496 |
pdeo = kmem_cache_alloc(pde_opener_cache, GFP_KERNEL); |
e7a6e291e proc: faster open... |
497 498 499 500 501 |
if (!pdeo) { rv = -ENOMEM; goto out_unuse; } } |
786d7e161 Fix rmmod/read/wr... |
502 |
|
d56c0d45f proc: decouple pr... |
503 |
open = pde->proc_ops->proc_open; |
786d7e161 Fix rmmod/read/wr... |
504 505 |
if (open) rv = open(inode, file); |
e7a6e291e proc: faster open... |
506 507 508 509 510 511 512 513 514 515 |
if (release) { if (rv == 0) { /* To know what to release. */ pdeo->file = file; pdeo->closing = false; pdeo->c = NULL; spin_lock(&pde->pde_unload_lock); list_add(&pdeo->lh, &pde->pde_openers); spin_unlock(&pde->pde_unload_lock); } else |
195b8cf06 proc: move "struc... |
516 |
kmem_cache_free(pde_opener_cache, pdeo); |
e7a6e291e proc: faster open... |
517 |
} |
05c0ae21c try a saner locki... |
518 |
|
e7a6e291e proc: faster open... |
519 |
out_unuse: |
05c0ae21c try a saner locki... |
520 |
unuse_pde(pde); |
786d7e161 Fix rmmod/read/wr... |
521 522 523 524 525 526 |
return rv; } static int proc_reg_release(struct inode *inode, struct file *file) { struct proc_dir_entry *pde = PDE(inode); |
881adb853 proc: always do -... |
527 |
struct pde_opener *pdeo; |
d919b33da proc: faster open... |
528 529 530 531 532 533 534 535 536 537 |
if (pde_is_permanent(pde)) { typeof_member(struct proc_ops, proc_release) release; release = pde->proc_ops->proc_release; if (release) { return release(inode, file); } return 0; } |
786d7e161 Fix rmmod/read/wr... |
538 |
spin_lock(&pde->pde_unload_lock); |
ca469f35a deal with races b... |
539 540 541 |
list_for_each_entry(pdeo, &pde->pde_openers, lh) { if (pdeo->file == file) { close_pdeo(pde, pdeo); |
2f8974243 proc: do less stu... |
542 |
return 0; |
ca469f35a deal with races b... |
543 |
} |
881adb853 proc: always do -... |
544 |
} |
786d7e161 Fix rmmod/read/wr... |
545 |
spin_unlock(&pde->pde_unload_lock); |
ca469f35a deal with races b... |
546 |
return 0; |
786d7e161 Fix rmmod/read/wr... |
547 548 549 550 551 552 553 554 |
} static const struct file_operations proc_reg_file_ops = { .llseek = proc_reg_llseek, .read = proc_reg_read, .write = proc_reg_write, .poll = proc_reg_poll, .unlocked_ioctl = proc_reg_unlocked_ioctl, |
786d7e161 Fix rmmod/read/wr... |
555 |
.mmap = proc_reg_mmap, |
c4fe24485 sparc: fix PCI de... |
556 |
.get_unmapped_area = proc_reg_get_unmapped_area, |
786d7e161 Fix rmmod/read/wr... |
557 558 559 |
.open = proc_reg_open, .release = proc_reg_release, }; |
fd5a13f48 proc: add a read_... |
560 561 562 563 |
static const struct file_operations proc_iter_file_ops = { .llseek = proc_reg_llseek, .read_iter = proc_reg_read_iter, .write = proc_reg_write, |
86aa9dba8 FROMLIST: proc: w... |
564 |
.splice_read = generic_file_splice_read, |
fd5a13f48 proc: add a read_... |
565 566 567 568 569 570 571 |
.poll = proc_reg_poll, .unlocked_ioctl = proc_reg_unlocked_ioctl, .mmap = proc_reg_mmap, .get_unmapped_area = proc_reg_get_unmapped_area, .open = proc_reg_open, .release = proc_reg_release, }; |
778f3dd5a Fix procfs compat... |
572 |
#ifdef CONFIG_COMPAT |
906146f44 proc: cleanup the... |
573 |
static const struct file_operations proc_reg_file_ops_compat = { |
778f3dd5a Fix procfs compat... |
574 575 576 577 578 |
.llseek = proc_reg_llseek, .read = proc_reg_read, .write = proc_reg_write, .poll = proc_reg_poll, .unlocked_ioctl = proc_reg_unlocked_ioctl, |
906146f44 proc: cleanup the... |
579 |
.compat_ioctl = proc_reg_compat_ioctl, |
778f3dd5a Fix procfs compat... |
580 |
.mmap = proc_reg_mmap, |
c4fe24485 sparc: fix PCI de... |
581 |
.get_unmapped_area = proc_reg_get_unmapped_area, |
778f3dd5a Fix procfs compat... |
582 583 584 |
.open = proc_reg_open, .release = proc_reg_release, }; |
fd5a13f48 proc: add a read_... |
585 586 587 588 |
static const struct file_operations proc_iter_file_ops_compat = { .llseek = proc_reg_llseek, .read_iter = proc_reg_read_iter, |
86aa9dba8 FROMLIST: proc: w... |
589 |
.splice_read = generic_file_splice_read, |
fd5a13f48 proc: add a read_... |
590 591 592 593 594 595 596 597 598 |
.write = proc_reg_write, .poll = proc_reg_poll, .unlocked_ioctl = proc_reg_unlocked_ioctl, .compat_ioctl = proc_reg_compat_ioctl, .mmap = proc_reg_mmap, .get_unmapped_area = proc_reg_get_unmapped_area, .open = proc_reg_open, .release = proc_reg_release, }; |
778f3dd5a Fix procfs compat... |
599 |
#endif |
fceef393a switch ->get_link... |
600 601 602 603 |
static void proc_put_link(void *p) { unuse_pde(p); } |
6b2553918 replace ->follow_... |
604 |
static const char *proc_get_link(struct dentry *dentry, |
fceef393a switch ->get_link... |
605 606 |
struct inode *inode, struct delayed_call *done) |
7e0e953bb procfs: fix race ... |
607 |
{ |
6b2553918 replace ->follow_... |
608 |
struct proc_dir_entry *pde = PDE(inode); |
15b158b4e proc: spread like... |
609 |
if (!use_pde(pde)) |
7e0e953bb procfs: fix race ... |
610 |
return ERR_PTR(-EINVAL); |
fceef393a switch ->get_link... |
611 |
set_delayed_call(done, proc_put_link, pde); |
680baacbc new ->follow_link... |
612 |
return pde->data; |
7e0e953bb procfs: fix race ... |
613 |
} |
7e0e953bb procfs: fix race ... |
614 |
const struct inode_operations proc_link_inode_operations = { |
6b2553918 replace ->follow_... |
615 |
.get_link = proc_get_link, |
7e0e953bb procfs: fix race ... |
616 |
}; |
6d1b6e4ef proc: ->low_ino c... |
617 |
struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) |
1da177e4c Linux-2.6.12-rc2 |
618 |
{ |
ef1548ada proc: Use new_ino... |
619 |
struct inode *inode = new_inode(sb); |
1da177e4c Linux-2.6.12-rc2 |
620 |
|
f6ef7b7bb proc: remove a le... |
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 |
if (!inode) { pde_put(de); return NULL; } inode->i_ino = de->low_ino; inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); PROC_I(inode)->pde = de; if (is_empty_pde(de)) { make_empty_dir_inode(inode); return inode; } if (de->mode) { inode->i_mode = de->mode; inode->i_uid = de->uid; inode->i_gid = de->gid; } if (de->size) inode->i_size = de->size; if (de->nlink) set_nlink(inode, de->nlink); if (S_ISREG(inode->i_mode)) { inode->i_op = de->proc_iops; |
fd5a13f48 proc: add a read_... |
646 647 648 649 |
if (de->proc_ops->proc_read_iter) inode->i_fop = &proc_iter_file_ops; else inode->i_fop = &proc_reg_file_ops; |
778f3dd5a Fix procfs compat... |
650 |
#ifdef CONFIG_COMPAT |
fd5a13f48 proc: add a read_... |
651 652 653 654 655 656 |
if (de->proc_ops->proc_compat_ioctl) { if (de->proc_ops->proc_read_iter) inode->i_fop = &proc_iter_file_ops_compat; else inode->i_fop = &proc_reg_file_ops_compat; } |
d56c0d45f proc: decouple pr... |
657 |
#endif |
f6ef7b7bb proc: remove a le... |
658 659 660 661 662 663 664 665 666 |
} else if (S_ISDIR(inode->i_mode)) { inode->i_op = de->proc_iops; inode->i_fop = de->proc_dir_ops; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = de->proc_iops; inode->i_fop = NULL; } else { BUG(); } |
1da177e4c Linux-2.6.12-rc2 |
667 |
return inode; |
d3d009cb9 saner proc_get_in... |
668 |
} |