Blame view
fs/proc/inode.c
11.7 KB
1da177e4c
|
1 2 3 4 5 6 7 8 9 |
/* * linux/fs/proc/inode.c * * Copyright (C) 1991, 1992 Linus Torvalds */ #include <linux/time.h> #include <linux/proc_fs.h> #include <linux/kernel.h> |
97412950b
|
10 |
#include <linux/pid_namespace.h> |
1da177e4c
|
11 12 13 |
#include <linux/mm.h> #include <linux/string.h> #include <linux/stat.h> |
786d7e161
|
14 |
#include <linux/completion.h> |
dd23aae4f
|
15 |
#include <linux/poll.h> |
87ebdc00e
|
16 |
#include <linux/printk.h> |
1da177e4c
|
17 18 19 20 |
#include <linux/file.h> #include <linux/limits.h> #include <linux/init.h> #include <linux/module.h> |
9043476f7
|
21 |
#include <linux/sysctl.h> |
97412950b
|
22 |
#include <linux/seq_file.h> |
5a0e3ad6a
|
23 |
#include <linux/slab.h> |
97412950b
|
24 |
#include <linux/mount.h> |
303eb7e2c
|
25 |
#include <linux/magic.h> |
1da177e4c
|
26 |
|
1da177e4c
|
27 |
#include <asm/uaccess.h> |
fee781e6c
|
28 |
#include "internal.h" |
1da177e4c
|
29 |
|
8267952b3
|
30 |
static void proc_evict_inode(struct inode *inode) |
1da177e4c
|
31 32 |
{ struct proc_dir_entry *de; |
dfef6dcd3
|
33 |
struct ctl_table_header *head; |
1da177e4c
|
34 |
|
91b0abe36
|
35 |
truncate_inode_pages_final(&inode->i_data); |
dbd5768f8
|
36 |
clear_inode(inode); |
fef266580
|
37 |
|
99f895518
|
38 |
/* Stop tracking associated processes */ |
13b41b094
|
39 |
put_pid(PROC_I(inode)->pid); |
1da177e4c
|
40 41 |
/* Let go of any associated proc directory entry */ |
6bee55f94
|
42 |
de = PDE(inode); |
99b762338
|
43 |
if (de) |
135d5655d
|
44 |
pde_put(de); |
dfef6dcd3
|
45 46 |
head = PROC_I(inode)->sysctl; if (head) { |
1c44dbc82
|
47 |
RCU_INIT_POINTER(PROC_I(inode)->sysctl, NULL); |
dfef6dcd3
|
48 49 |
sysctl_head_put(head); } |
1da177e4c
|
50 |
} |
e18b890bb
|
51 |
static struct kmem_cache * proc_inode_cachep; |
1da177e4c
|
52 53 54 55 56 |
static struct inode *proc_alloc_inode(struct super_block *sb) { struct proc_inode *ei; struct inode *inode; |
e94b17660
|
57 |
ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, GFP_KERNEL); |
1da177e4c
|
58 59 |
if (!ei) return NULL; |
13b41b094
|
60 |
ei->pid = NULL; |
aed7a6c47
|
61 |
ei->fd = 0; |
1da177e4c
|
62 63 |
ei->op.proc_get_link = NULL; ei->pde = NULL; |
9043476f7
|
64 65 |
ei->sysctl = NULL; ei->sysctl_entry = NULL; |
3d3d35b1e
|
66 |
ei->ns_ops = NULL; |
1da177e4c
|
67 68 69 70 |
inode = &ei->vfs_inode; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; return inode; } |
fa0d7e3de
|
71 |
static void proc_i_callback(struct rcu_head *head) |
1da177e4c
|
72 |
{ |
fa0d7e3de
|
73 |
struct inode *inode = container_of(head, struct inode, i_rcu); |
1da177e4c
|
74 75 |
kmem_cache_free(proc_inode_cachep, PROC_I(inode)); } |
fa0d7e3de
|
76 77 78 79 |
static void proc_destroy_inode(struct inode *inode) { call_rcu(&inode->i_rcu, proc_i_callback); } |
51cc50685
|
80 |
static void init_once(void *foo) |
1da177e4c
|
81 82 |
{ struct proc_inode *ei = (struct proc_inode *) foo; |
a35afb830
|
83 |
inode_init_once(&ei->vfs_inode); |
1da177e4c
|
84 |
} |
20c2df83d
|
85 |
|
5bcd7ff9e
|
86 |
void __init proc_init_inodecache(void) |
1da177e4c
|
87 88 89 |
{ proc_inode_cachep = kmem_cache_create("proc_inode_cache", sizeof(struct proc_inode), |
fffb60f93
|
90 |
0, (SLAB_RECLAIM_ACCOUNT| |
5d097056c
|
91 92 |
SLAB_MEM_SPREAD|SLAB_ACCOUNT| SLAB_PANIC), |
20c2df83d
|
93 |
init_once); |
1da177e4c
|
94 |
} |
97412950b
|
95 96 |
static int proc_show_options(struct seq_file *seq, struct dentry *root) { |
0499680a4
|
97 98 |
struct super_block *sb = root->d_sb; struct pid_namespace *pid = sb->s_fs_info; |
dcb0f2228
|
99 100 |
if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID)) seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid)); |
0499680a4
|
101 102 |
if (pid->hide_pid != 0) seq_printf(seq, ",hidepid=%u", pid->hide_pid); |
97412950b
|
103 104 |
return 0; } |
ee9b6d61a
|
105 |
static const struct super_operations proc_sops = { |
1da177e4c
|
106 107 |
.alloc_inode = proc_alloc_inode, .destroy_inode = proc_destroy_inode, |
1da177e4c
|
108 |
.drop_inode = generic_delete_inode, |
8267952b3
|
109 |
.evict_inode = proc_evict_inode, |
1da177e4c
|
110 |
.statfs = simple_statfs, |
97412950b
|
111 112 |
.remount_fs = proc_remount, .show_options = proc_show_options, |
1da177e4c
|
113 |
}; |
866ad9a74
|
114 115 116 117 |
enum {BIAS = -1U<<31}; static inline int use_pde(struct proc_dir_entry *pde) { |
05c0ae21c
|
118 |
return atomic_inc_unless_negative(&pde->in_use); |
881adb853
|
119 |
} |
866ad9a74
|
120 |
static void unuse_pde(struct proc_dir_entry *pde) |
881adb853
|
121 |
{ |
05c0ae21c
|
122 123 |
if (atomic_dec_return(&pde->in_use) == BIAS) complete(pde->pde_unload_completion); |
786d7e161
|
124 |
} |
ca469f35a
|
125 126 127 |
/* pde is locked */ static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) { |
05c0ae21c
|
128 |
if (pdeo->closing) { |
ca469f35a
|
129 |
/* somebody else is doing that, just wait */ |
05c0ae21c
|
130 131 |
DECLARE_COMPLETION_ONSTACK(c); pdeo->c = &c; |
ca469f35a
|
132 |
spin_unlock(&pde->pde_unload_lock); |
05c0ae21c
|
133 |
wait_for_completion(&c); |
ca469f35a
|
134 |
spin_lock(&pde->pde_unload_lock); |
ca469f35a
|
135 136 |
} else { struct file *file; |
05c0ae21c
|
137 |
pdeo->closing = 1; |
ca469f35a
|
138 139 140 141 142 |
spin_unlock(&pde->pde_unload_lock); file = pdeo->file; pde->proc_fops->release(file_inode(file), file); spin_lock(&pde->pde_unload_lock); list_del_init(&pdeo->lh); |
05c0ae21c
|
143 144 |
if (pdeo->c) complete(pdeo->c); |
ca469f35a
|
145 |
kfree(pdeo); |
05c0ae21c
|
146 |
} |
ca469f35a
|
147 |
} |
866ad9a74
|
148 |
void proc_entry_rundown(struct proc_dir_entry *de) |
786d7e161
|
149 |
{ |
05c0ae21c
|
150 |
DECLARE_COMPLETION_ONSTACK(c); |
866ad9a74
|
151 |
/* Wait until all existing callers into module are done. */ |
05c0ae21c
|
152 153 154 |
de->pde_unload_completion = &c; if (atomic_add_return(BIAS, &de->in_use) != BIAS) wait_for_completion(&c); |
786d7e161
|
155 |
|
05c0ae21c
|
156 |
spin_lock(&de->pde_unload_lock); |
866ad9a74
|
157 158 |
while (!list_empty(&de->pde_openers)) { struct pde_opener *pdeo; |
866ad9a74
|
159 |
pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh); |
ca469f35a
|
160 |
close_pdeo(de, pdeo); |
866ad9a74
|
161 162 |
} spin_unlock(&de->pde_unload_lock); |
786d7e161
|
163 |
} |
866ad9a74
|
164 165 166 167 168 169 170 171 172 173 174 175 |
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; if (use_pde(pde)) { loff_t (*llseek)(struct file *, loff_t, int); llseek = pde->proc_fops->llseek; if (!llseek) llseek = default_llseek; rv = llseek(file, offset, whence); unuse_pde(pde); } |
786d7e161
|
176 177 |
return rv; } |
866ad9a74
|
178 |
static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) |
786d7e161
|
179 |
{ |
866ad9a74
|
180 |
ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); |
496ad9aa8
|
181 |
struct proc_dir_entry *pde = PDE(file_inode(file)); |
786d7e161
|
182 |
ssize_t rv = -EIO; |
866ad9a74
|
183 184 185 186 187 |
if (use_pde(pde)) { read = pde->proc_fops->read; if (read) rv = read(file, buf, count, ppos); unuse_pde(pde); |
786d7e161
|
188 |
} |
866ad9a74
|
189 190 |
return rv; } |
786d7e161
|
191 |
|
866ad9a74
|
192 193 194 195 196 197 198 199 200 201 202 |
static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); struct proc_dir_entry *pde = PDE(file_inode(file)); ssize_t rv = -EIO; if (use_pde(pde)) { write = pde->proc_fops->write; if (write) rv = write(file, buf, count, ppos); unuse_pde(pde); } |
786d7e161
|
203 204 205 206 207 |
return rv; } static unsigned int proc_reg_poll(struct file *file, struct poll_table_struct *pts) { |
496ad9aa8
|
208 |
struct proc_dir_entry *pde = PDE(file_inode(file)); |
dd23aae4f
|
209 |
unsigned int rv = DEFAULT_POLLMASK; |
786d7e161
|
210 |
unsigned int (*poll)(struct file *, struct poll_table_struct *); |
866ad9a74
|
211 212 213 214 215 |
if (use_pde(pde)) { poll = pde->proc_fops->poll; if (poll) rv = poll(file, pts); unuse_pde(pde); |
786d7e161
|
216 |
} |
786d7e161
|
217 218 219 220 221 |
return rv; } static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { |
496ad9aa8
|
222 |
struct proc_dir_entry *pde = PDE(file_inode(file)); |
786d7e161
|
223 |
long rv = -ENOTTY; |
b19dd42fa
|
224 |
long (*ioctl)(struct file *, unsigned int, unsigned long); |
866ad9a74
|
225 226 227 228 229 |
if (use_pde(pde)) { ioctl = pde->proc_fops->unlocked_ioctl; if (ioctl) rv = ioctl(file, cmd, arg); unuse_pde(pde); |
786d7e161
|
230 |
} |
786d7e161
|
231 232 233 234 235 236 |
return rv; } #ifdef CONFIG_COMPAT static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { |
496ad9aa8
|
237 |
struct proc_dir_entry *pde = PDE(file_inode(file)); |
786d7e161
|
238 239 |
long rv = -ENOTTY; long (*compat_ioctl)(struct file *, unsigned int, unsigned long); |
866ad9a74
|
240 241 242 243 244 |
if (use_pde(pde)) { compat_ioctl = pde->proc_fops->compat_ioctl; if (compat_ioctl) rv = compat_ioctl(file, cmd, arg); unuse_pde(pde); |
786d7e161
|
245 |
} |
786d7e161
|
246 247 248 249 250 251 |
return rv; } #endif static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma) { |
496ad9aa8
|
252 |
struct proc_dir_entry *pde = PDE(file_inode(file)); |
786d7e161
|
253 254 |
int rv = -EIO; int (*mmap)(struct file *, struct vm_area_struct *); |
866ad9a74
|
255 256 257 258 259 |
if (use_pde(pde)) { mmap = pde->proc_fops->mmap; if (mmap) rv = mmap(file, vma); unuse_pde(pde); |
786d7e161
|
260 |
} |
786d7e161
|
261 262 |
return rv; } |
5721cf84d
|
263 264 265 266 |
static unsigned long proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags) |
c4fe24485
|
267 268 |
{ struct proc_dir_entry *pde = PDE(file_inode(file)); |
2cbe3b0af
|
269 |
unsigned long rv = -EIO; |
ae5758a1a
|
270 |
|
c4fe24485
|
271 |
if (use_pde(pde)) { |
ae5758a1a
|
272 273 274 |
typeof(proc_reg_get_unmapped_area) *get_area; get_area = pde->proc_fops->get_unmapped_area; |
fad1a86e2
|
275 |
#ifdef CONFIG_MMU |
ae5758a1a
|
276 277 |
if (!get_area) get_area = current->mm->get_unmapped_area; |
fad1a86e2
|
278 |
#endif |
ae5758a1a
|
279 |
|
5721cf84d
|
280 281 |
if (get_area) rv = get_area(file, orig_addr, len, pgoff, flags); |
ae5758a1a
|
282 283 |
else rv = orig_addr; |
c4fe24485
|
284 285 286 287 |
unuse_pde(pde); } return rv; } |
786d7e161
|
288 289 290 291 292 |
static int proc_reg_open(struct inode *inode, struct file *file) { struct proc_dir_entry *pde = PDE(inode); int rv = 0; int (*open)(struct inode *, struct file *); |
881adb853
|
293 294 295 296 297 298 299 300 301 302 303 304 305 |
int (*release)(struct inode *, struct file *); struct pde_opener *pdeo; /* * What for, you ask? Well, we can have open, rmmod, remove_proc_entry * sequence. ->release won't be called because ->proc_fops will be * cleared. Depending on complexity of ->release, consequences vary. * * We can't wait for mercy when close will be done for real, it's * deadlockable: rmmod foo </proc/foo . So, we're going to do ->release * by hand in remove_proc_entry(). For this, save opener's credentials * for later. */ |
05c0ae21c
|
306 |
pdeo = kzalloc(sizeof(struct pde_opener), GFP_KERNEL); |
881adb853
|
307 308 |
if (!pdeo) return -ENOMEM; |
786d7e161
|
309 |
|
866ad9a74
|
310 |
if (!use_pde(pde)) { |
881adb853
|
311 |
kfree(pdeo); |
d2857e79a
|
312 |
return -ENOENT; |
786d7e161
|
313 |
} |
786d7e161
|
314 |
open = pde->proc_fops->open; |
881adb853
|
315 |
release = pde->proc_fops->release; |
786d7e161
|
316 317 318 |
if (open) rv = open(inode, file); |
881adb853
|
319 320 |
if (rv == 0 && release) { /* To know what to release. */ |
881adb853
|
321 322 |
pdeo->file = file; /* Strictly for "too late" ->release in proc_reg_release(). */ |
05c0ae21c
|
323 |
spin_lock(&pde->pde_unload_lock); |
881adb853
|
324 |
list_add(&pdeo->lh, &pde->pde_openers); |
05c0ae21c
|
325 |
spin_unlock(&pde->pde_unload_lock); |
881adb853
|
326 327 |
} else kfree(pdeo); |
05c0ae21c
|
328 329 |
unuse_pde(pde); |
786d7e161
|
330 331 332 333 334 335 |
return rv; } static int proc_reg_release(struct inode *inode, struct file *file) { struct proc_dir_entry *pde = PDE(inode); |
881adb853
|
336 |
struct pde_opener *pdeo; |
786d7e161
|
337 |
spin_lock(&pde->pde_unload_lock); |
ca469f35a
|
338 339 340 341 342 |
list_for_each_entry(pdeo, &pde->pde_openers, lh) { if (pdeo->file == file) { close_pdeo(pde, pdeo); break; } |
881adb853
|
343 |
} |
786d7e161
|
344 |
spin_unlock(&pde->pde_unload_lock); |
ca469f35a
|
345 |
return 0; |
786d7e161
|
346 347 348 349 350 351 352 353 354 355 356 357 |
} 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, #ifdef CONFIG_COMPAT .compat_ioctl = proc_reg_compat_ioctl, #endif .mmap = proc_reg_mmap, |
c4fe24485
|
358 |
.get_unmapped_area = proc_reg_get_unmapped_area, |
786d7e161
|
359 360 361 |
.open = proc_reg_open, .release = proc_reg_release, }; |
778f3dd5a
|
362 363 364 365 366 367 368 369 |
#ifdef CONFIG_COMPAT static const struct file_operations proc_reg_file_ops_no_compat = { .llseek = proc_reg_llseek, .read = proc_reg_read, .write = proc_reg_write, .poll = proc_reg_poll, .unlocked_ioctl = proc_reg_unlocked_ioctl, .mmap = proc_reg_mmap, |
c4fe24485
|
370 |
.get_unmapped_area = proc_reg_get_unmapped_area, |
778f3dd5a
|
371 372 373 374 |
.open = proc_reg_open, .release = proc_reg_release, }; #endif |
fceef393a
|
375 376 377 378 |
static void proc_put_link(void *p) { unuse_pde(p); } |
6b2553918
|
379 |
static const char *proc_get_link(struct dentry *dentry, |
fceef393a
|
380 381 |
struct inode *inode, struct delayed_call *done) |
7e0e953bb
|
382 |
{ |
6b2553918
|
383 |
struct proc_dir_entry *pde = PDE(inode); |
7e0e953bb
|
384 385 |
if (unlikely(!use_pde(pde))) return ERR_PTR(-EINVAL); |
fceef393a
|
386 |
set_delayed_call(done, proc_put_link, pde); |
680baacbc
|
387 |
return pde->data; |
7e0e953bb
|
388 |
} |
7e0e953bb
|
389 390 |
const struct inode_operations proc_link_inode_operations = { .readlink = generic_readlink, |
6b2553918
|
391 |
.get_link = proc_get_link, |
7e0e953bb
|
392 |
}; |
6d1b6e4ef
|
393 |
struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) |
1da177e4c
|
394 |
{ |
51f0885e5
|
395 |
struct inode *inode = new_inode_pseudo(sb); |
1da177e4c
|
396 |
|
51f0885e5
|
397 398 |
if (inode) { inode->i_ino = de->low_ino; |
a1d4aebbf
|
399 |
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
a1d4aebbf
|
400 |
PROC_I(inode)->pde = de; |
5e971dce0
|
401 |
|
eb6d38d54
|
402 403 404 405 |
if (is_empty_pde(de)) { make_empty_dir_inode(inode); return inode; } |
5e971dce0
|
406 407 408 409 410 411 412 413 |
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) |
bfe868486
|
414 |
set_nlink(inode, de->nlink); |
b6cdc7310
|
415 416 |
WARN_ON(!de->proc_iops); inode->i_op = de->proc_iops; |
5e971dce0
|
417 418 |
if (de->proc_fops) { if (S_ISREG(inode->i_mode)) { |
778f3dd5a
|
419 |
#ifdef CONFIG_COMPAT |
5e971dce0
|
420 421 422 423 |
if (!de->proc_fops->compat_ioctl) inode->i_fop = &proc_reg_file_ops_no_compat; else |
778f3dd5a
|
424 |
#endif |
5e971dce0
|
425 426 427 |
inode->i_fop = &proc_reg_file_ops; } else { inode->i_fop = de->proc_fops; |
778f3dd5a
|
428 |
} |
786d7e161
|
429 |
} |
99b762338
|
430 |
} else |
135d5655d
|
431 |
pde_put(de); |
1da177e4c
|
432 |
return inode; |
d3d009cb9
|
433 |
} |
1da177e4c
|
434 |
|
07543f5c7
|
435 |
int proc_fill_super(struct super_block *s) |
1da177e4c
|
436 |
{ |
87e0aab37
|
437 |
struct inode *root_inode; |
0097875bd
|
438 |
int ret; |
87e0aab37
|
439 |
|
92d032855
|
440 |
s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC; |
1da177e4c
|
441 442 443 444 445 446 |
s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = PROC_SUPER_MAGIC; s->s_op = &proc_sops; s->s_time_gran = 1; |
135d5655d
|
447 |
pde_get(&proc_root); |
87e0aab37
|
448 449 |
root_inode = proc_get_inode(s, &proc_root); if (!root_inode) { |
87ebdc00e
|
450 451 |
pr_err("proc_fill_super: get root inode failed "); |
87e0aab37
|
452 453 |
return -ENOMEM; } |
1da177e4c
|
454 |
|
87e0aab37
|
455 456 |
s->s_root = d_make_root(root_inode); if (!s->s_root) { |
87ebdc00e
|
457 458 |
pr_err("proc_fill_super: allocate dentry failed "); |
87e0aab37
|
459 460 |
return -ENOMEM; } |
0097875bd
|
461 462 463 464 465 |
ret = proc_setup_self(s); if (ret) { return ret; } return proc_setup_thread_self(s); |
1da177e4c
|
466 |
} |