diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 20:51:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 20:51:54 -0400 |
commit | 20b4fb485227404329e41ad15588afad3df23050 (patch) | |
tree | f3e099f0ab3da8a93b447203e294d2bb22f6dc05 /fs/proc | |
parent | b9394d8a657cd3c064fa432aa0905c1b58b38fe9 (diff) | |
parent | ac3e3c5b1164397656df81b9e9ab4991184d3236 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull VFS updates from Al Viro,
Misc cleanups all over the place, mainly wrt /proc interfaces (switch
create_proc_entry to proc_create(), get rid of the deprecated
create_proc_read_entry() in favor of using proc_create_data() and
seq_file etc).
7kloc removed.
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (204 commits)
don't bother with deferred freeing of fdtables
proc: Move non-public stuff from linux/proc_fs.h to fs/proc/internal.h
proc: Make the PROC_I() and PDE() macros internal to procfs
proc: Supply a function to remove a proc entry by PDE
take cgroup_open() and cpuset_open() to fs/proc/base.c
ppc: Clean up scanlog
ppc: Clean up rtas_flash driver somewhat
hostap: proc: Use remove_proc_subtree()
drm: proc: Use remove_proc_subtree()
drm: proc: Use minor->index to label things, not PDE->name
drm: Constify drm_proc_list[]
zoran: Don't print proc_dir_entry data in debug
reiserfs: Don't access the proc_dir_entry in r_open(), r_start() r_show()
proc: Supply an accessor for getting the data from a PDE's parent
airo: Use remove_proc_subtree()
rtl8192u: Don't need to save device proc dir PDE
rtl8187se: Use a dir under /proc/net/r8180/
proc: Add proc_mkdir_data()
proc: Move some bits from linux/proc_fs.h to linux/{of.h,signal.h,tty.h}
proc: Move PDE_NET() to fs/proc/proc_net.c
...
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/base.c | 56 | ||||
-rw-r--r-- | fs/proc/fd.h | 5 | ||||
-rw-r--r-- | fs/proc/generic.c | 377 | ||||
-rw-r--r-- | fs/proc/inode.c | 283 | ||||
-rw-r--r-- | fs/proc/internal.h | 313 | ||||
-rw-r--r-- | fs/proc/kcore.c | 2 | ||||
-rw-r--r-- | fs/proc/namespaces.c | 17 | ||||
-rw-r--r-- | fs/proc/proc_devtree.c | 2 | ||||
-rw-r--r-- | fs/proc/proc_net.c | 4 | ||||
-rw-r--r-- | fs/proc/root.c | 2 | ||||
-rw-r--r-- | fs/proc/self.c | 47 | ||||
-rw-r--r-- | fs/proc/vmcore.c | 5 |
12 files changed, 501 insertions, 612 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 3861bcec41ff..dd51e50001fe 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -405,6 +405,37 @@ static const struct file_operations proc_lstats_operations = { | |||
405 | 405 | ||
406 | #endif | 406 | #endif |
407 | 407 | ||
408 | #ifdef CONFIG_CGROUPS | ||
409 | static int cgroup_open(struct inode *inode, struct file *file) | ||
410 | { | ||
411 | struct pid *pid = PROC_I(inode)->pid; | ||
412 | return single_open(file, proc_cgroup_show, pid); | ||
413 | } | ||
414 | |||
415 | static const struct file_operations proc_cgroup_operations = { | ||
416 | .open = cgroup_open, | ||
417 | .read = seq_read, | ||
418 | .llseek = seq_lseek, | ||
419 | .release = single_release, | ||
420 | }; | ||
421 | #endif | ||
422 | |||
423 | #ifdef CONFIG_PROC_PID_CPUSET | ||
424 | |||
425 | static int cpuset_open(struct inode *inode, struct file *file) | ||
426 | { | ||
427 | struct pid *pid = PROC_I(inode)->pid; | ||
428 | return single_open(file, proc_cpuset_show, pid); | ||
429 | } | ||
430 | |||
431 | static const struct file_operations proc_cpuset_operations = { | ||
432 | .open = cpuset_open, | ||
433 | .read = seq_read, | ||
434 | .llseek = seq_lseek, | ||
435 | .release = single_release, | ||
436 | }; | ||
437 | #endif | ||
438 | |||
408 | static int proc_oom_score(struct task_struct *task, char *buffer) | 439 | static int proc_oom_score(struct task_struct *task, char *buffer) |
409 | { | 440 | { |
410 | unsigned long totalpages = totalram_pages + total_swap_pages; | 441 | unsigned long totalpages = totalram_pages + total_swap_pages; |
@@ -1621,6 +1652,15 @@ int pid_revalidate(struct dentry *dentry, unsigned int flags) | |||
1621 | return 0; | 1652 | return 0; |
1622 | } | 1653 | } |
1623 | 1654 | ||
1655 | int pid_delete_dentry(const struct dentry *dentry) | ||
1656 | { | ||
1657 | /* Is the task we represent dead? | ||
1658 | * If so, then don't put the dentry on the lru list, | ||
1659 | * kill it immediately. | ||
1660 | */ | ||
1661 | return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first; | ||
1662 | } | ||
1663 | |||
1624 | const struct dentry_operations pid_dentry_operations = | 1664 | const struct dentry_operations pid_dentry_operations = |
1625 | { | 1665 | { |
1626 | .d_revalidate = pid_revalidate, | 1666 | .d_revalidate = pid_revalidate, |
@@ -2893,7 +2933,7 @@ retry: | |||
2893 | return iter; | 2933 | return iter; |
2894 | } | 2934 | } |
2895 | 2935 | ||
2896 | #define TGID_OFFSET (FIRST_PROCESS_ENTRY) | 2936 | #define TGID_OFFSET (FIRST_PROCESS_ENTRY + 1) |
2897 | 2937 | ||
2898 | static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | 2938 | static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir, |
2899 | struct tgid_iter iter) | 2939 | struct tgid_iter iter) |
@@ -2916,13 +2956,21 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
2916 | struct tgid_iter iter; | 2956 | struct tgid_iter iter; |
2917 | struct pid_namespace *ns; | 2957 | struct pid_namespace *ns; |
2918 | filldir_t __filldir; | 2958 | filldir_t __filldir; |
2959 | loff_t pos = filp->f_pos; | ||
2919 | 2960 | ||
2920 | if (filp->f_pos >= PID_MAX_LIMIT + TGID_OFFSET) | 2961 | if (pos >= PID_MAX_LIMIT + TGID_OFFSET) |
2921 | goto out; | 2962 | goto out; |
2922 | 2963 | ||
2923 | ns = filp->f_dentry->d_sb->s_fs_info; | 2964 | if (pos == TGID_OFFSET - 1) { |
2965 | if (proc_fill_cache(filp, dirent, filldir, "self", 4, | ||
2966 | NULL, NULL, NULL) < 0) | ||
2967 | goto out; | ||
2968 | iter.tgid = 0; | ||
2969 | } else { | ||
2970 | iter.tgid = pos - TGID_OFFSET; | ||
2971 | } | ||
2924 | iter.task = NULL; | 2972 | iter.task = NULL; |
2925 | iter.tgid = filp->f_pos - TGID_OFFSET; | 2973 | ns = filp->f_dentry->d_sb->s_fs_info; |
2926 | for (iter = next_tgid(ns, iter); | 2974 | for (iter = next_tgid(ns, iter); |
2927 | iter.task; | 2975 | iter.task; |
2928 | iter.tgid += 1, iter = next_tgid(ns, iter)) { | 2976 | iter.tgid += 1, iter = next_tgid(ns, iter)) { |
diff --git a/fs/proc/fd.h b/fs/proc/fd.h index cbb1d47deda8..7c047f256ae2 100644 --- a/fs/proc/fd.h +++ b/fs/proc/fd.h | |||
@@ -11,4 +11,9 @@ extern const struct inode_operations proc_fdinfo_inode_operations; | |||
11 | 11 | ||
12 | extern int proc_fd_permission(struct inode *inode, int mask); | 12 | extern int proc_fd_permission(struct inode *inode, int mask); |
13 | 13 | ||
14 | static inline int proc_fd(struct inode *inode) | ||
15 | { | ||
16 | return PROC_I(inode)->fd; | ||
17 | } | ||
18 | |||
14 | #endif /* __PROCFS_FD_H__ */ | 19 | #endif /* __PROCFS_FD_H__ */ |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 21e1a8f1659d..a2596afffae6 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -36,212 +36,6 @@ static int proc_match(unsigned int len, const char *name, struct proc_dir_entry | |||
36 | return !memcmp(name, de->name, len); | 36 | return !memcmp(name, de->name, len); |
37 | } | 37 | } |
38 | 38 | ||
39 | /* buffer size is one page but our output routines use some slack for overruns */ | ||
40 | #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024) | ||
41 | |||
42 | static ssize_t | ||
43 | __proc_file_read(struct file *file, char __user *buf, size_t nbytes, | ||
44 | loff_t *ppos) | ||
45 | { | ||
46 | struct inode * inode = file_inode(file); | ||
47 | char *page; | ||
48 | ssize_t retval=0; | ||
49 | int eof=0; | ||
50 | ssize_t n, count; | ||
51 | char *start; | ||
52 | struct proc_dir_entry * dp; | ||
53 | unsigned long long pos; | ||
54 | |||
55 | /* | ||
56 | * Gaah, please just use "seq_file" instead. The legacy /proc | ||
57 | * interfaces cut loff_t down to off_t for reads, and ignore | ||
58 | * the offset entirely for writes.. | ||
59 | */ | ||
60 | pos = *ppos; | ||
61 | if (pos > MAX_NON_LFS) | ||
62 | return 0; | ||
63 | if (nbytes > MAX_NON_LFS - pos) | ||
64 | nbytes = MAX_NON_LFS - pos; | ||
65 | |||
66 | dp = PDE(inode); | ||
67 | if (!(page = (char*) __get_free_page(GFP_TEMPORARY))) | ||
68 | return -ENOMEM; | ||
69 | |||
70 | while ((nbytes > 0) && !eof) { | ||
71 | count = min_t(size_t, PROC_BLOCK_SIZE, nbytes); | ||
72 | |||
73 | start = NULL; | ||
74 | if (dp->read_proc) { | ||
75 | /* | ||
76 | * How to be a proc read function | ||
77 | * ------------------------------ | ||
78 | * Prototype: | ||
79 | * int f(char *buffer, char **start, off_t offset, | ||
80 | * int count, int *peof, void *dat) | ||
81 | * | ||
82 | * Assume that the buffer is "count" bytes in size. | ||
83 | * | ||
84 | * If you know you have supplied all the data you | ||
85 | * have, set *peof. | ||
86 | * | ||
87 | * You have three ways to return data: | ||
88 | * 0) Leave *start = NULL. (This is the default.) | ||
89 | * Put the data of the requested offset at that | ||
90 | * offset within the buffer. Return the number (n) | ||
91 | * of bytes there are from the beginning of the | ||
92 | * buffer up to the last byte of data. If the | ||
93 | * number of supplied bytes (= n - offset) is | ||
94 | * greater than zero and you didn't signal eof | ||
95 | * and the reader is prepared to take more data | ||
96 | * you will be called again with the requested | ||
97 | * offset advanced by the number of bytes | ||
98 | * absorbed. This interface is useful for files | ||
99 | * no larger than the buffer. | ||
100 | * 1) Set *start = an unsigned long value less than | ||
101 | * the buffer address but greater than zero. | ||
102 | * Put the data of the requested offset at the | ||
103 | * beginning of the buffer. Return the number of | ||
104 | * bytes of data placed there. If this number is | ||
105 | * greater than zero and you didn't signal eof | ||
106 | * and the reader is prepared to take more data | ||
107 | * you will be called again with the requested | ||
108 | * offset advanced by *start. This interface is | ||
109 | * useful when you have a large file consisting | ||
110 | * of a series of blocks which you want to count | ||
111 | * and return as wholes. | ||
112 | * (Hack by Paul.Russell@rustcorp.com.au) | ||
113 | * 2) Set *start = an address within the buffer. | ||
114 | * Put the data of the requested offset at *start. | ||
115 | * Return the number of bytes of data placed there. | ||
116 | * If this number is greater than zero and you | ||
117 | * didn't signal eof and the reader is prepared to | ||
118 | * take more data you will be called again with the | ||
119 | * requested offset advanced by the number of bytes | ||
120 | * absorbed. | ||
121 | */ | ||
122 | n = dp->read_proc(page, &start, *ppos, | ||
123 | count, &eof, dp->data); | ||
124 | } else | ||
125 | break; | ||
126 | |||
127 | if (n == 0) /* end of file */ | ||
128 | break; | ||
129 | if (n < 0) { /* error */ | ||
130 | if (retval == 0) | ||
131 | retval = n; | ||
132 | break; | ||
133 | } | ||
134 | |||
135 | if (start == NULL) { | ||
136 | if (n > PAGE_SIZE) /* Apparent buffer overflow */ | ||
137 | n = PAGE_SIZE; | ||
138 | n -= *ppos; | ||
139 | if (n <= 0) | ||
140 | break; | ||
141 | if (n > count) | ||
142 | n = count; | ||
143 | start = page + *ppos; | ||
144 | } else if (start < page) { | ||
145 | if (n > PAGE_SIZE) /* Apparent buffer overflow */ | ||
146 | n = PAGE_SIZE; | ||
147 | if (n > count) { | ||
148 | /* | ||
149 | * Don't reduce n because doing so might | ||
150 | * cut off part of a data block. | ||
151 | */ | ||
152 | pr_warn("proc_file_read: count exceeded\n"); | ||
153 | } | ||
154 | } else /* start >= page */ { | ||
155 | unsigned long startoff = (unsigned long)(start - page); | ||
156 | if (n > (PAGE_SIZE - startoff)) /* buffer overflow? */ | ||
157 | n = PAGE_SIZE - startoff; | ||
158 | if (n > count) | ||
159 | n = count; | ||
160 | } | ||
161 | |||
162 | n -= copy_to_user(buf, start < page ? page : start, n); | ||
163 | if (n == 0) { | ||
164 | if (retval == 0) | ||
165 | retval = -EFAULT; | ||
166 | break; | ||
167 | } | ||
168 | |||
169 | *ppos += start < page ? (unsigned long)start : n; | ||
170 | nbytes -= n; | ||
171 | buf += n; | ||
172 | retval += n; | ||
173 | } | ||
174 | free_page((unsigned long) page); | ||
175 | return retval; | ||
176 | } | ||
177 | |||
178 | static ssize_t | ||
179 | proc_file_read(struct file *file, char __user *buf, size_t nbytes, | ||
180 | loff_t *ppos) | ||
181 | { | ||
182 | struct proc_dir_entry *pde = PDE(file_inode(file)); | ||
183 | ssize_t rv = -EIO; | ||
184 | |||
185 | spin_lock(&pde->pde_unload_lock); | ||
186 | if (!pde->proc_fops) { | ||
187 | spin_unlock(&pde->pde_unload_lock); | ||
188 | return rv; | ||
189 | } | ||
190 | pde->pde_users++; | ||
191 | spin_unlock(&pde->pde_unload_lock); | ||
192 | |||
193 | rv = __proc_file_read(file, buf, nbytes, ppos); | ||
194 | |||
195 | pde_users_dec(pde); | ||
196 | return rv; | ||
197 | } | ||
198 | |||
199 | static ssize_t | ||
200 | proc_file_write(struct file *file, const char __user *buffer, | ||
201 | size_t count, loff_t *ppos) | ||
202 | { | ||
203 | struct proc_dir_entry *pde = PDE(file_inode(file)); | ||
204 | ssize_t rv = -EIO; | ||
205 | |||
206 | if (pde->write_proc) { | ||
207 | spin_lock(&pde->pde_unload_lock); | ||
208 | if (!pde->proc_fops) { | ||
209 | spin_unlock(&pde->pde_unload_lock); | ||
210 | return rv; | ||
211 | } | ||
212 | pde->pde_users++; | ||
213 | spin_unlock(&pde->pde_unload_lock); | ||
214 | |||
215 | /* FIXME: does this routine need ppos? probably... */ | ||
216 | rv = pde->write_proc(file, buffer, count, pde->data); | ||
217 | pde_users_dec(pde); | ||
218 | } | ||
219 | return rv; | ||
220 | } | ||
221 | |||
222 | |||
223 | static loff_t | ||
224 | proc_file_lseek(struct file *file, loff_t offset, int orig) | ||
225 | { | ||
226 | loff_t retval = -EINVAL; | ||
227 | switch (orig) { | ||
228 | case 1: | ||
229 | offset += file->f_pos; | ||
230 | /* fallthrough */ | ||
231 | case 0: | ||
232 | if (offset < 0 || offset > MAX_NON_LFS) | ||
233 | break; | ||
234 | file->f_pos = retval = offset; | ||
235 | } | ||
236 | return retval; | ||
237 | } | ||
238 | |||
239 | static const struct file_operations proc_file_operations = { | ||
240 | .llseek = proc_file_lseek, | ||
241 | .read = proc_file_read, | ||
242 | .write = proc_file_write, | ||
243 | }; | ||
244 | |||
245 | static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) | 39 | static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) |
246 | { | 40 | { |
247 | struct inode *inode = dentry->d_inode; | 41 | struct inode *inode = dentry->d_inode; |
@@ -371,7 +165,7 @@ void proc_free_inum(unsigned int inum) | |||
371 | 165 | ||
372 | static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd) | 166 | static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd) |
373 | { | 167 | { |
374 | nd_set_link(nd, PDE(dentry->d_inode)->data); | 168 | nd_set_link(nd, __PDE_DATA(dentry->d_inode)); |
375 | return NULL; | 169 | return NULL; |
376 | } | 170 | } |
377 | 171 | ||
@@ -541,19 +335,17 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp | |||
541 | return ret; | 335 | return ret; |
542 | 336 | ||
543 | if (S_ISDIR(dp->mode)) { | 337 | if (S_ISDIR(dp->mode)) { |
544 | if (dp->proc_iops == NULL) { | 338 | dp->proc_fops = &proc_dir_operations; |
545 | dp->proc_fops = &proc_dir_operations; | 339 | dp->proc_iops = &proc_dir_inode_operations; |
546 | dp->proc_iops = &proc_dir_inode_operations; | ||
547 | } | ||
548 | dir->nlink++; | 340 | dir->nlink++; |
549 | } else if (S_ISLNK(dp->mode)) { | 341 | } else if (S_ISLNK(dp->mode)) { |
550 | if (dp->proc_iops == NULL) | 342 | dp->proc_iops = &proc_link_inode_operations; |
551 | dp->proc_iops = &proc_link_inode_operations; | ||
552 | } else if (S_ISREG(dp->mode)) { | 343 | } else if (S_ISREG(dp->mode)) { |
553 | if (dp->proc_fops == NULL) | 344 | BUG_ON(dp->proc_fops == NULL); |
554 | dp->proc_fops = &proc_file_operations; | 345 | dp->proc_iops = &proc_file_inode_operations; |
555 | if (dp->proc_iops == NULL) | 346 | } else { |
556 | dp->proc_iops = &proc_file_inode_operations; | 347 | WARN_ON(1); |
348 | return -EINVAL; | ||
557 | } | 349 | } |
558 | 350 | ||
559 | spin_lock(&proc_subdir_lock); | 351 | spin_lock(&proc_subdir_lock); |
@@ -636,13 +428,17 @@ struct proc_dir_entry *proc_symlink(const char *name, | |||
636 | } | 428 | } |
637 | EXPORT_SYMBOL(proc_symlink); | 429 | EXPORT_SYMBOL(proc_symlink); |
638 | 430 | ||
639 | struct proc_dir_entry *proc_mkdir_mode(const char *name, umode_t mode, | 431 | struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, |
640 | struct proc_dir_entry *parent) | 432 | struct proc_dir_entry *parent, void *data) |
641 | { | 433 | { |
642 | struct proc_dir_entry *ent; | 434 | struct proc_dir_entry *ent; |
643 | 435 | ||
436 | if (mode == 0) | ||
437 | mode = S_IRUGO | S_IXUGO; | ||
438 | |||
644 | ent = __proc_create(&parent, name, S_IFDIR | mode, 2); | 439 | ent = __proc_create(&parent, name, S_IFDIR | mode, 2); |
645 | if (ent) { | 440 | if (ent) { |
441 | ent->data = data; | ||
646 | if (proc_register(parent, ent) < 0) { | 442 | if (proc_register(parent, ent) < 0) { |
647 | kfree(ent); | 443 | kfree(ent); |
648 | ent = NULL; | 444 | ent = NULL; |
@@ -650,82 +446,39 @@ struct proc_dir_entry *proc_mkdir_mode(const char *name, umode_t mode, | |||
650 | } | 446 | } |
651 | return ent; | 447 | return ent; |
652 | } | 448 | } |
653 | EXPORT_SYMBOL(proc_mkdir_mode); | 449 | EXPORT_SYMBOL_GPL(proc_mkdir_data); |
654 | 450 | ||
655 | struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name, | 451 | struct proc_dir_entry *proc_mkdir_mode(const char *name, umode_t mode, |
656 | struct proc_dir_entry *parent) | 452 | struct proc_dir_entry *parent) |
657 | { | 453 | { |
658 | struct proc_dir_entry *ent; | 454 | return proc_mkdir_data(name, mode, parent, NULL); |
659 | |||
660 | ent = __proc_create(&parent, name, S_IFDIR | S_IRUGO | S_IXUGO, 2); | ||
661 | if (ent) { | ||
662 | ent->data = net; | ||
663 | if (proc_register(parent, ent) < 0) { | ||
664 | kfree(ent); | ||
665 | ent = NULL; | ||
666 | } | ||
667 | } | ||
668 | return ent; | ||
669 | } | 455 | } |
670 | EXPORT_SYMBOL_GPL(proc_net_mkdir); | 456 | EXPORT_SYMBOL(proc_mkdir_mode); |
671 | 457 | ||
672 | struct proc_dir_entry *proc_mkdir(const char *name, | 458 | struct proc_dir_entry *proc_mkdir(const char *name, |
673 | struct proc_dir_entry *parent) | 459 | struct proc_dir_entry *parent) |
674 | { | 460 | { |
675 | return proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent); | 461 | return proc_mkdir_data(name, 0, parent, NULL); |
676 | } | 462 | } |
677 | EXPORT_SYMBOL(proc_mkdir); | 463 | EXPORT_SYMBOL(proc_mkdir); |
678 | 464 | ||
679 | struct proc_dir_entry *create_proc_entry(const char *name, umode_t mode, | ||
680 | struct proc_dir_entry *parent) | ||
681 | { | ||
682 | struct proc_dir_entry *ent; | ||
683 | nlink_t nlink; | ||
684 | |||
685 | if (S_ISDIR(mode)) { | ||
686 | if ((mode & S_IALLUGO) == 0) | ||
687 | mode |= S_IRUGO | S_IXUGO; | ||
688 | nlink = 2; | ||
689 | } else { | ||
690 | if ((mode & S_IFMT) == 0) | ||
691 | mode |= S_IFREG; | ||
692 | if ((mode & S_IALLUGO) == 0) | ||
693 | mode |= S_IRUGO; | ||
694 | nlink = 1; | ||
695 | } | ||
696 | |||
697 | ent = __proc_create(&parent, name, mode, nlink); | ||
698 | if (ent) { | ||
699 | if (proc_register(parent, ent) < 0) { | ||
700 | kfree(ent); | ||
701 | ent = NULL; | ||
702 | } | ||
703 | } | ||
704 | return ent; | ||
705 | } | ||
706 | EXPORT_SYMBOL(create_proc_entry); | ||
707 | |||
708 | struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, | 465 | struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, |
709 | struct proc_dir_entry *parent, | 466 | struct proc_dir_entry *parent, |
710 | const struct file_operations *proc_fops, | 467 | const struct file_operations *proc_fops, |
711 | void *data) | 468 | void *data) |
712 | { | 469 | { |
713 | struct proc_dir_entry *pde; | 470 | struct proc_dir_entry *pde; |
714 | nlink_t nlink; | 471 | if ((mode & S_IFMT) == 0) |
472 | mode |= S_IFREG; | ||
715 | 473 | ||
716 | if (S_ISDIR(mode)) { | 474 | if (!S_ISREG(mode)) { |
717 | if ((mode & S_IALLUGO) == 0) | 475 | WARN_ON(1); /* use proc_mkdir() */ |
718 | mode |= S_IRUGO | S_IXUGO; | 476 | return NULL; |
719 | nlink = 2; | ||
720 | } else { | ||
721 | if ((mode & S_IFMT) == 0) | ||
722 | mode |= S_IFREG; | ||
723 | if ((mode & S_IALLUGO) == 0) | ||
724 | mode |= S_IRUGO; | ||
725 | nlink = 1; | ||
726 | } | 477 | } |
727 | 478 | ||
728 | pde = __proc_create(&parent, name, mode, nlink); | 479 | if ((mode & S_IALLUGO) == 0) |
480 | mode |= S_IRUGO; | ||
481 | pde = __proc_create(&parent, name, mode, 1); | ||
729 | if (!pde) | 482 | if (!pde) |
730 | goto out; | 483 | goto out; |
731 | pde->proc_fops = proc_fops; | 484 | pde->proc_fops = proc_fops; |
@@ -739,6 +492,19 @@ out: | |||
739 | return NULL; | 492 | return NULL; |
740 | } | 493 | } |
741 | EXPORT_SYMBOL(proc_create_data); | 494 | EXPORT_SYMBOL(proc_create_data); |
495 | |||
496 | void proc_set_size(struct proc_dir_entry *de, loff_t size) | ||
497 | { | ||
498 | de->size = size; | ||
499 | } | ||
500 | EXPORT_SYMBOL(proc_set_size); | ||
501 | |||
502 | void proc_set_user(struct proc_dir_entry *de, kuid_t uid, kgid_t gid) | ||
503 | { | ||
504 | de->uid = uid; | ||
505 | de->gid = gid; | ||
506 | } | ||
507 | EXPORT_SYMBOL(proc_set_user); | ||
742 | 508 | ||
743 | static void free_proc_entry(struct proc_dir_entry *de) | 509 | static void free_proc_entry(struct proc_dir_entry *de) |
744 | { | 510 | { |
@@ -755,41 +521,6 @@ void pde_put(struct proc_dir_entry *pde) | |||
755 | free_proc_entry(pde); | 521 | free_proc_entry(pde); |
756 | } | 522 | } |
757 | 523 | ||
758 | static void entry_rundown(struct proc_dir_entry *de) | ||
759 | { | ||
760 | spin_lock(&de->pde_unload_lock); | ||
761 | /* | ||
762 | * Stop accepting new callers into module. If you're | ||
763 | * dynamically allocating ->proc_fops, save a pointer somewhere. | ||
764 | */ | ||
765 | de->proc_fops = NULL; | ||
766 | /* Wait until all existing callers into module are done. */ | ||
767 | if (de->pde_users > 0) { | ||
768 | DECLARE_COMPLETION_ONSTACK(c); | ||
769 | |||
770 | if (!de->pde_unload_completion) | ||
771 | de->pde_unload_completion = &c; | ||
772 | |||
773 | spin_unlock(&de->pde_unload_lock); | ||
774 | |||
775 | wait_for_completion(de->pde_unload_completion); | ||
776 | |||
777 | spin_lock(&de->pde_unload_lock); | ||
778 | } | ||
779 | |||
780 | while (!list_empty(&de->pde_openers)) { | ||
781 | struct pde_opener *pdeo; | ||
782 | |||
783 | pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh); | ||
784 | list_del(&pdeo->lh); | ||
785 | spin_unlock(&de->pde_unload_lock); | ||
786 | pdeo->release(pdeo->inode, pdeo->file); | ||
787 | kfree(pdeo); | ||
788 | spin_lock(&de->pde_unload_lock); | ||
789 | } | ||
790 | spin_unlock(&de->pde_unload_lock); | ||
791 | } | ||
792 | |||
793 | /* | 524 | /* |
794 | * Remove a /proc entry and free it if it's not currently in use. | 525 | * Remove a /proc entry and free it if it's not currently in use. |
795 | */ | 526 | */ |
@@ -821,7 +552,7 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
821 | return; | 552 | return; |
822 | } | 553 | } |
823 | 554 | ||
824 | entry_rundown(de); | 555 | proc_entry_rundown(de); |
825 | 556 | ||
826 | if (S_ISDIR(de->mode)) | 557 | if (S_ISDIR(de->mode)) |
827 | parent->nlink--; | 558 | parent->nlink--; |
@@ -870,7 +601,7 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) | |||
870 | } | 601 | } |
871 | spin_unlock(&proc_subdir_lock); | 602 | spin_unlock(&proc_subdir_lock); |
872 | 603 | ||
873 | entry_rundown(de); | 604 | proc_entry_rundown(de); |
874 | next = de->parent; | 605 | next = de->parent; |
875 | if (S_ISDIR(de->mode)) | 606 | if (S_ISDIR(de->mode)) |
876 | next->nlink--; | 607 | next->nlink--; |
@@ -886,3 +617,23 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) | |||
886 | return 0; | 617 | return 0; |
887 | } | 618 | } |
888 | EXPORT_SYMBOL(remove_proc_subtree); | 619 | EXPORT_SYMBOL(remove_proc_subtree); |
620 | |||
621 | void *proc_get_parent_data(const struct inode *inode) | ||
622 | { | ||
623 | struct proc_dir_entry *de = PDE(inode); | ||
624 | return de->parent->data; | ||
625 | } | ||
626 | EXPORT_SYMBOL_GPL(proc_get_parent_data); | ||
627 | |||
628 | void proc_remove(struct proc_dir_entry *de) | ||
629 | { | ||
630 | if (de) | ||
631 | remove_proc_subtree(de->name, de->parent); | ||
632 | } | ||
633 | EXPORT_SYMBOL(proc_remove); | ||
634 | |||
635 | void *PDE_DATA(const struct inode *inode) | ||
636 | { | ||
637 | return __PDE_DATA(inode); | ||
638 | } | ||
639 | EXPORT_SYMBOL(PDE_DATA); | ||
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 869116c2afbe..073aea60cf8f 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/mount.h> | 24 | #include <linux/mount.h> |
25 | #include <linux/magic.h> | ||
25 | 26 | ||
26 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
27 | 28 | ||
@@ -50,8 +51,8 @@ static void proc_evict_inode(struct inode *inode) | |||
50 | sysctl_head_put(head); | 51 | sysctl_head_put(head); |
51 | } | 52 | } |
52 | /* Release any associated namespace */ | 53 | /* Release any associated namespace */ |
53 | ns_ops = PROC_I(inode)->ns_ops; | 54 | ns_ops = PROC_I(inode)->ns.ns_ops; |
54 | ns = PROC_I(inode)->ns; | 55 | ns = PROC_I(inode)->ns.ns; |
55 | if (ns_ops && ns) | 56 | if (ns_ops && ns) |
56 | ns_ops->put(ns); | 57 | ns_ops->put(ns); |
57 | } | 58 | } |
@@ -72,8 +73,8 @@ static struct inode *proc_alloc_inode(struct super_block *sb) | |||
72 | ei->pde = NULL; | 73 | ei->pde = NULL; |
73 | ei->sysctl = NULL; | 74 | ei->sysctl = NULL; |
74 | ei->sysctl_entry = NULL; | 75 | ei->sysctl_entry = NULL; |
75 | ei->ns = NULL; | 76 | ei->ns.ns = NULL; |
76 | ei->ns_ops = NULL; | 77 | ei->ns.ns_ops = NULL; |
77 | inode = &ei->vfs_inode; | 78 | inode = &ei->vfs_inode; |
78 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 79 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
79 | return inode; | 80 | return inode; |
@@ -129,96 +130,100 @@ static const struct super_operations proc_sops = { | |||
129 | .show_options = proc_show_options, | 130 | .show_options = proc_show_options, |
130 | }; | 131 | }; |
131 | 132 | ||
132 | static void __pde_users_dec(struct proc_dir_entry *pde) | 133 | enum {BIAS = -1U<<31}; |
134 | |||
135 | static inline int use_pde(struct proc_dir_entry *pde) | ||
136 | { | ||
137 | return atomic_inc_unless_negative(&pde->in_use); | ||
138 | } | ||
139 | |||
140 | static void unuse_pde(struct proc_dir_entry *pde) | ||
133 | { | 141 | { |
134 | pde->pde_users--; | 142 | if (atomic_dec_return(&pde->in_use) == BIAS) |
135 | if (pde->pde_unload_completion && pde->pde_users == 0) | ||
136 | complete(pde->pde_unload_completion); | 143 | complete(pde->pde_unload_completion); |
137 | } | 144 | } |
138 | 145 | ||
139 | void pde_users_dec(struct proc_dir_entry *pde) | 146 | /* pde is locked */ |
147 | static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) | ||
140 | { | 148 | { |
141 | spin_lock(&pde->pde_unload_lock); | 149 | if (pdeo->closing) { |
142 | __pde_users_dec(pde); | 150 | /* somebody else is doing that, just wait */ |
143 | spin_unlock(&pde->pde_unload_lock); | 151 | DECLARE_COMPLETION_ONSTACK(c); |
152 | pdeo->c = &c; | ||
153 | spin_unlock(&pde->pde_unload_lock); | ||
154 | wait_for_completion(&c); | ||
155 | spin_lock(&pde->pde_unload_lock); | ||
156 | } else { | ||
157 | struct file *file; | ||
158 | pdeo->closing = 1; | ||
159 | spin_unlock(&pde->pde_unload_lock); | ||
160 | file = pdeo->file; | ||
161 | pde->proc_fops->release(file_inode(file), file); | ||
162 | spin_lock(&pde->pde_unload_lock); | ||
163 | list_del_init(&pdeo->lh); | ||
164 | if (pdeo->c) | ||
165 | complete(pdeo->c); | ||
166 | kfree(pdeo); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | void proc_entry_rundown(struct proc_dir_entry *de) | ||
171 | { | ||
172 | DECLARE_COMPLETION_ONSTACK(c); | ||
173 | /* Wait until all existing callers into module are done. */ | ||
174 | de->pde_unload_completion = &c; | ||
175 | if (atomic_add_return(BIAS, &de->in_use) != BIAS) | ||
176 | wait_for_completion(&c); | ||
177 | |||
178 | spin_lock(&de->pde_unload_lock); | ||
179 | while (!list_empty(&de->pde_openers)) { | ||
180 | struct pde_opener *pdeo; | ||
181 | pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh); | ||
182 | close_pdeo(de, pdeo); | ||
183 | } | ||
184 | spin_unlock(&de->pde_unload_lock); | ||
144 | } | 185 | } |
145 | 186 | ||
146 | static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence) | 187 | static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence) |
147 | { | 188 | { |
148 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 189 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
149 | loff_t rv = -EINVAL; | 190 | loff_t rv = -EINVAL; |
150 | loff_t (*llseek)(struct file *, loff_t, int); | 191 | if (use_pde(pde)) { |
151 | 192 | loff_t (*llseek)(struct file *, loff_t, int); | |
152 | spin_lock(&pde->pde_unload_lock); | 193 | llseek = pde->proc_fops->llseek; |
153 | /* | 194 | if (!llseek) |
154 | * remove_proc_entry() is going to delete PDE (as part of module | 195 | llseek = default_llseek; |
155 | * cleanup sequence). No new callers into module allowed. | 196 | rv = llseek(file, offset, whence); |
156 | */ | 197 | unuse_pde(pde); |
157 | if (!pde->proc_fops) { | ||
158 | spin_unlock(&pde->pde_unload_lock); | ||
159 | return rv; | ||
160 | } | 198 | } |
161 | /* | ||
162 | * Bump refcount so that remove_proc_entry will wail for ->llseek to | ||
163 | * complete. | ||
164 | */ | ||
165 | pde->pde_users++; | ||
166 | /* | ||
167 | * Save function pointer under lock, to protect against ->proc_fops | ||
168 | * NULL'ifying right after ->pde_unload_lock is dropped. | ||
169 | */ | ||
170 | llseek = pde->proc_fops->llseek; | ||
171 | spin_unlock(&pde->pde_unload_lock); | ||
172 | |||
173 | if (!llseek) | ||
174 | llseek = default_llseek; | ||
175 | rv = llseek(file, offset, whence); | ||
176 | |||
177 | pde_users_dec(pde); | ||
178 | return rv; | 199 | return rv; |
179 | } | 200 | } |
180 | 201 | ||
181 | static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | 202 | static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) |
182 | { | 203 | { |
204 | ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); | ||
183 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 205 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
184 | ssize_t rv = -EIO; | 206 | ssize_t rv = -EIO; |
185 | ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); | 207 | if (use_pde(pde)) { |
186 | 208 | read = pde->proc_fops->read; | |
187 | spin_lock(&pde->pde_unload_lock); | 209 | if (read) |
188 | if (!pde->proc_fops) { | 210 | rv = read(file, buf, count, ppos); |
189 | spin_unlock(&pde->pde_unload_lock); | 211 | unuse_pde(pde); |
190 | return rv; | ||
191 | } | 212 | } |
192 | pde->pde_users++; | ||
193 | read = pde->proc_fops->read; | ||
194 | spin_unlock(&pde->pde_unload_lock); | ||
195 | |||
196 | if (read) | ||
197 | rv = read(file, buf, count, ppos); | ||
198 | |||
199 | pde_users_dec(pde); | ||
200 | return rv; | 213 | return rv; |
201 | } | 214 | } |
202 | 215 | ||
203 | static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 216 | static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) |
204 | { | 217 | { |
218 | ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); | ||
205 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 219 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
206 | ssize_t rv = -EIO; | 220 | ssize_t rv = -EIO; |
207 | ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); | 221 | if (use_pde(pde)) { |
208 | 222 | write = pde->proc_fops->write; | |
209 | spin_lock(&pde->pde_unload_lock); | 223 | if (write) |
210 | if (!pde->proc_fops) { | 224 | rv = write(file, buf, count, ppos); |
211 | spin_unlock(&pde->pde_unload_lock); | 225 | unuse_pde(pde); |
212 | return rv; | ||
213 | } | 226 | } |
214 | pde->pde_users++; | ||
215 | write = pde->proc_fops->write; | ||
216 | spin_unlock(&pde->pde_unload_lock); | ||
217 | |||
218 | if (write) | ||
219 | rv = write(file, buf, count, ppos); | ||
220 | |||
221 | pde_users_dec(pde); | ||
222 | return rv; | 227 | return rv; |
223 | } | 228 | } |
224 | 229 | ||
@@ -227,20 +232,12 @@ static unsigned int proc_reg_poll(struct file *file, struct poll_table_struct *p | |||
227 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 232 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
228 | unsigned int rv = DEFAULT_POLLMASK; | 233 | unsigned int rv = DEFAULT_POLLMASK; |
229 | unsigned int (*poll)(struct file *, struct poll_table_struct *); | 234 | unsigned int (*poll)(struct file *, struct poll_table_struct *); |
230 | 235 | if (use_pde(pde)) { | |
231 | spin_lock(&pde->pde_unload_lock); | 236 | poll = pde->proc_fops->poll; |
232 | if (!pde->proc_fops) { | 237 | if (poll) |
233 | spin_unlock(&pde->pde_unload_lock); | 238 | rv = poll(file, pts); |
234 | return rv; | 239 | unuse_pde(pde); |
235 | } | 240 | } |
236 | pde->pde_users++; | ||
237 | poll = pde->proc_fops->poll; | ||
238 | spin_unlock(&pde->pde_unload_lock); | ||
239 | |||
240 | if (poll) | ||
241 | rv = poll(file, pts); | ||
242 | |||
243 | pde_users_dec(pde); | ||
244 | return rv; | 241 | return rv; |
245 | } | 242 | } |
246 | 243 | ||
@@ -249,20 +246,12 @@ static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigne | |||
249 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 246 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
250 | long rv = -ENOTTY; | 247 | long rv = -ENOTTY; |
251 | long (*ioctl)(struct file *, unsigned int, unsigned long); | 248 | long (*ioctl)(struct file *, unsigned int, unsigned long); |
252 | 249 | if (use_pde(pde)) { | |
253 | spin_lock(&pde->pde_unload_lock); | 250 | ioctl = pde->proc_fops->unlocked_ioctl; |
254 | if (!pde->proc_fops) { | 251 | if (ioctl) |
255 | spin_unlock(&pde->pde_unload_lock); | 252 | rv = ioctl(file, cmd, arg); |
256 | return rv; | 253 | unuse_pde(pde); |
257 | } | 254 | } |
258 | pde->pde_users++; | ||
259 | ioctl = pde->proc_fops->unlocked_ioctl; | ||
260 | spin_unlock(&pde->pde_unload_lock); | ||
261 | |||
262 | if (ioctl) | ||
263 | rv = ioctl(file, cmd, arg); | ||
264 | |||
265 | pde_users_dec(pde); | ||
266 | return rv; | 255 | return rv; |
267 | } | 256 | } |
268 | 257 | ||
@@ -272,20 +261,12 @@ static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned | |||
272 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 261 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
273 | long rv = -ENOTTY; | 262 | long rv = -ENOTTY; |
274 | long (*compat_ioctl)(struct file *, unsigned int, unsigned long); | 263 | long (*compat_ioctl)(struct file *, unsigned int, unsigned long); |
275 | 264 | if (use_pde(pde)) { | |
276 | spin_lock(&pde->pde_unload_lock); | 265 | compat_ioctl = pde->proc_fops->compat_ioctl; |
277 | if (!pde->proc_fops) { | 266 | if (compat_ioctl) |
278 | spin_unlock(&pde->pde_unload_lock); | 267 | rv = compat_ioctl(file, cmd, arg); |
279 | return rv; | 268 | unuse_pde(pde); |
280 | } | 269 | } |
281 | pde->pde_users++; | ||
282 | compat_ioctl = pde->proc_fops->compat_ioctl; | ||
283 | spin_unlock(&pde->pde_unload_lock); | ||
284 | |||
285 | if (compat_ioctl) | ||
286 | rv = compat_ioctl(file, cmd, arg); | ||
287 | |||
288 | pde_users_dec(pde); | ||
289 | return rv; | 270 | return rv; |
290 | } | 271 | } |
291 | #endif | 272 | #endif |
@@ -295,20 +276,12 @@ static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma) | |||
295 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 276 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
296 | int rv = -EIO; | 277 | int rv = -EIO; |
297 | int (*mmap)(struct file *, struct vm_area_struct *); | 278 | int (*mmap)(struct file *, struct vm_area_struct *); |
298 | 279 | if (use_pde(pde)) { | |
299 | spin_lock(&pde->pde_unload_lock); | 280 | mmap = pde->proc_fops->mmap; |
300 | if (!pde->proc_fops) { | 281 | if (mmap) |
301 | spin_unlock(&pde->pde_unload_lock); | 282 | rv = mmap(file, vma); |
302 | return rv; | 283 | unuse_pde(pde); |
303 | } | 284 | } |
304 | pde->pde_users++; | ||
305 | mmap = pde->proc_fops->mmap; | ||
306 | spin_unlock(&pde->pde_unload_lock); | ||
307 | |||
308 | if (mmap) | ||
309 | rv = mmap(file, vma); | ||
310 | |||
311 | pde_users_dec(pde); | ||
312 | return rv; | 285 | return rv; |
313 | } | 286 | } |
314 | 287 | ||
@@ -330,91 +303,47 @@ static int proc_reg_open(struct inode *inode, struct file *file) | |||
330 | * by hand in remove_proc_entry(). For this, save opener's credentials | 303 | * by hand in remove_proc_entry(). For this, save opener's credentials |
331 | * for later. | 304 | * for later. |
332 | */ | 305 | */ |
333 | pdeo = kmalloc(sizeof(struct pde_opener), GFP_KERNEL); | 306 | pdeo = kzalloc(sizeof(struct pde_opener), GFP_KERNEL); |
334 | if (!pdeo) | 307 | if (!pdeo) |
335 | return -ENOMEM; | 308 | return -ENOMEM; |
336 | 309 | ||
337 | spin_lock(&pde->pde_unload_lock); | 310 | if (!use_pde(pde)) { |
338 | if (!pde->proc_fops) { | ||
339 | spin_unlock(&pde->pde_unload_lock); | ||
340 | kfree(pdeo); | 311 | kfree(pdeo); |
341 | return -ENOENT; | 312 | return -ENOENT; |
342 | } | 313 | } |
343 | pde->pde_users++; | ||
344 | open = pde->proc_fops->open; | 314 | open = pde->proc_fops->open; |
345 | release = pde->proc_fops->release; | 315 | release = pde->proc_fops->release; |
346 | spin_unlock(&pde->pde_unload_lock); | ||
347 | 316 | ||
348 | if (open) | 317 | if (open) |
349 | rv = open(inode, file); | 318 | rv = open(inode, file); |
350 | 319 | ||
351 | spin_lock(&pde->pde_unload_lock); | ||
352 | if (rv == 0 && release) { | 320 | if (rv == 0 && release) { |
353 | /* To know what to release. */ | 321 | /* To know what to release. */ |
354 | pdeo->inode = inode; | ||
355 | pdeo->file = file; | 322 | pdeo->file = file; |
356 | /* Strictly for "too late" ->release in proc_reg_release(). */ | 323 | /* Strictly for "too late" ->release in proc_reg_release(). */ |
357 | pdeo->release = release; | 324 | spin_lock(&pde->pde_unload_lock); |
358 | list_add(&pdeo->lh, &pde->pde_openers); | 325 | list_add(&pdeo->lh, &pde->pde_openers); |
326 | spin_unlock(&pde->pde_unload_lock); | ||
359 | } else | 327 | } else |
360 | kfree(pdeo); | 328 | kfree(pdeo); |
361 | __pde_users_dec(pde); | ||
362 | spin_unlock(&pde->pde_unload_lock); | ||
363 | return rv; | ||
364 | } | ||
365 | |||
366 | static struct pde_opener *find_pde_opener(struct proc_dir_entry *pde, | ||
367 | struct inode *inode, struct file *file) | ||
368 | { | ||
369 | struct pde_opener *pdeo; | ||
370 | 329 | ||
371 | list_for_each_entry(pdeo, &pde->pde_openers, lh) { | 330 | unuse_pde(pde); |
372 | if (pdeo->inode == inode && pdeo->file == file) | 331 | return rv; |
373 | return pdeo; | ||
374 | } | ||
375 | return NULL; | ||
376 | } | 332 | } |
377 | 333 | ||
378 | static int proc_reg_release(struct inode *inode, struct file *file) | 334 | static int proc_reg_release(struct inode *inode, struct file *file) |
379 | { | 335 | { |
380 | struct proc_dir_entry *pde = PDE(inode); | 336 | struct proc_dir_entry *pde = PDE(inode); |
381 | int rv = 0; | ||
382 | int (*release)(struct inode *, struct file *); | ||
383 | struct pde_opener *pdeo; | 337 | struct pde_opener *pdeo; |
384 | |||
385 | spin_lock(&pde->pde_unload_lock); | 338 | spin_lock(&pde->pde_unload_lock); |
386 | pdeo = find_pde_opener(pde, inode, file); | 339 | list_for_each_entry(pdeo, &pde->pde_openers, lh) { |
387 | if (!pde->proc_fops) { | 340 | if (pdeo->file == file) { |
388 | /* | 341 | close_pdeo(pde, pdeo); |
389 | * Can't simply exit, __fput() will think that everything is OK, | 342 | break; |
390 | * and move on to freeing struct file. remove_proc_entry() will | 343 | } |
391 | * find slacker in opener's list and will try to do non-trivial | ||
392 | * things with struct file. Therefore, remove opener from list. | ||
393 | * | ||
394 | * But if opener is removed from list, who will ->release it? | ||
395 | */ | ||
396 | if (pdeo) { | ||
397 | list_del(&pdeo->lh); | ||
398 | spin_unlock(&pde->pde_unload_lock); | ||
399 | rv = pdeo->release(inode, file); | ||
400 | kfree(pdeo); | ||
401 | } else | ||
402 | spin_unlock(&pde->pde_unload_lock); | ||
403 | return rv; | ||
404 | } | ||
405 | pde->pde_users++; | ||
406 | release = pde->proc_fops->release; | ||
407 | if (pdeo) { | ||
408 | list_del(&pdeo->lh); | ||
409 | kfree(pdeo); | ||
410 | } | 344 | } |
411 | spin_unlock(&pde->pde_unload_lock); | 345 | spin_unlock(&pde->pde_unload_lock); |
412 | 346 | return 0; | |
413 | if (release) | ||
414 | rv = release(inode, file); | ||
415 | |||
416 | pde_users_dec(pde); | ||
417 | return rv; | ||
418 | } | 347 | } |
419 | 348 | ||
420 | static const struct file_operations proc_reg_file_ops = { | 349 | static const struct file_operations proc_reg_file_ops = { |
@@ -462,8 +391,8 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) | |||
462 | inode->i_size = de->size; | 391 | inode->i_size = de->size; |
463 | if (de->nlink) | 392 | if (de->nlink) |
464 | set_nlink(inode, de->nlink); | 393 | set_nlink(inode, de->nlink); |
465 | if (de->proc_iops) | 394 | WARN_ON(!de->proc_iops); |
466 | inode->i_op = de->proc_iops; | 395 | inode->i_op = de->proc_iops; |
467 | if (de->proc_fops) { | 396 | if (de->proc_fops) { |
468 | if (S_ISREG(inode->i_mode)) { | 397 | if (S_ISREG(inode->i_mode)) { |
469 | #ifdef CONFIG_COMPAT | 398 | #ifdef CONFIG_COMPAT |
@@ -506,5 +435,5 @@ int proc_fill_super(struct super_block *s) | |||
506 | return -ENOMEM; | 435 | return -ENOMEM; |
507 | } | 436 | } |
508 | 437 | ||
509 | return 0; | 438 | return proc_setup_self(s); |
510 | } | 439 | } |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 75710357a517..d600fb098b6a 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* internal.h: internal procfs definitions | 1 | /* Internal procfs definitions |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
@@ -9,62 +9,83 @@ | |||
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/proc_fs.h> | 12 | #include <linux/proc_fs.h> |
13 | #include <linux/proc_ns.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/atomic.h> | ||
14 | #include <linux/binfmts.h> | 16 | #include <linux/binfmts.h> |
15 | struct ctl_table_header; | ||
16 | struct mempolicy; | ||
17 | 17 | ||
18 | extern struct proc_dir_entry proc_root; | 18 | struct ctl_table_header; |
19 | extern void proc_self_init(void); | 19 | struct mempolicy; |
20 | #ifdef CONFIG_PROC_SYSCTL | ||
21 | extern int proc_sys_init(void); | ||
22 | extern void sysctl_head_put(struct ctl_table_header *head); | ||
23 | #else | ||
24 | static inline void proc_sys_init(void) { } | ||
25 | static inline void sysctl_head_put(struct ctl_table_header *head) { } | ||
26 | #endif | ||
27 | #ifdef CONFIG_NET | ||
28 | extern int proc_net_init(void); | ||
29 | #else | ||
30 | static inline int proc_net_init(void) { return 0; } | ||
31 | #endif | ||
32 | 20 | ||
33 | extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns, | 21 | /* |
34 | struct pid *pid, struct task_struct *task); | 22 | * This is not completely implemented yet. The idea is to |
35 | extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns, | 23 | * create an in-memory tree (like the actual /proc filesystem |
36 | struct pid *pid, struct task_struct *task); | 24 | * tree) of these proc_dir_entries, so that we can dynamically |
37 | extern int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, | 25 | * add new files to /proc. |
38 | struct pid *pid, struct task_struct *task); | 26 | * |
39 | extern int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns, | 27 | * The "next" pointer creates a linked list of one /proc directory, |
40 | struct pid *pid, struct task_struct *task); | 28 | * while parent/subdir create the directory structure (every |
41 | extern loff_t mem_lseek(struct file *file, loff_t offset, int orig); | 29 | * /proc file has a parent, but "subdir" is NULL for all |
30 | * non-directory entries). | ||
31 | */ | ||
32 | struct proc_dir_entry { | ||
33 | unsigned int low_ino; | ||
34 | umode_t mode; | ||
35 | nlink_t nlink; | ||
36 | kuid_t uid; | ||
37 | kgid_t gid; | ||
38 | loff_t size; | ||
39 | const struct inode_operations *proc_iops; | ||
40 | const struct file_operations *proc_fops; | ||
41 | struct proc_dir_entry *next, *parent, *subdir; | ||
42 | void *data; | ||
43 | atomic_t count; /* use count */ | ||
44 | atomic_t in_use; /* number of callers into module in progress; */ | ||
45 | /* negative -> it's going away RSN */ | ||
46 | struct completion *pde_unload_completion; | ||
47 | struct list_head pde_openers; /* who did ->open, but not ->release */ | ||
48 | spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */ | ||
49 | u8 namelen; | ||
50 | char name[]; | ||
51 | }; | ||
42 | 52 | ||
43 | extern const struct file_operations proc_tid_children_operations; | 53 | union proc_op { |
44 | extern const struct file_operations proc_pid_maps_operations; | 54 | int (*proc_get_link)(struct dentry *, struct path *); |
45 | extern const struct file_operations proc_tid_maps_operations; | 55 | int (*proc_read)(struct task_struct *task, char *page); |
46 | extern const struct file_operations proc_pid_numa_maps_operations; | 56 | int (*proc_show)(struct seq_file *m, |
47 | extern const struct file_operations proc_tid_numa_maps_operations; | 57 | struct pid_namespace *ns, struct pid *pid, |
48 | extern const struct file_operations proc_pid_smaps_operations; | 58 | struct task_struct *task); |
49 | extern const struct file_operations proc_tid_smaps_operations; | 59 | }; |
50 | extern const struct file_operations proc_clear_refs_operations; | ||
51 | extern const struct file_operations proc_pagemap_operations; | ||
52 | extern const struct file_operations proc_net_operations; | ||
53 | extern const struct inode_operations proc_net_inode_operations; | ||
54 | extern const struct inode_operations proc_pid_link_inode_operations; | ||
55 | 60 | ||
56 | struct proc_maps_private { | 61 | struct proc_inode { |
57 | struct pid *pid; | 62 | struct pid *pid; |
58 | struct task_struct *task; | 63 | int fd; |
59 | #ifdef CONFIG_MMU | 64 | union proc_op op; |
60 | struct vm_area_struct *tail_vma; | 65 | struct proc_dir_entry *pde; |
61 | #endif | 66 | struct ctl_table_header *sysctl; |
62 | #ifdef CONFIG_NUMA | 67 | struct ctl_table *sysctl_entry; |
63 | struct mempolicy *task_mempolicy; | 68 | struct proc_ns ns; |
64 | #endif | 69 | struct inode vfs_inode; |
65 | }; | 70 | }; |
66 | 71 | ||
67 | void proc_init_inodecache(void); | 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 | } | ||
68 | 89 | ||
69 | static inline struct pid *proc_pid(struct inode *inode) | 90 | static inline struct pid *proc_pid(struct inode *inode) |
70 | { | 91 | { |
@@ -76,11 +97,6 @@ static inline struct task_struct *get_proc_task(struct inode *inode) | |||
76 | return get_pid_task(proc_pid(inode), PIDTYPE_PID); | 97 | return get_pid_task(proc_pid(inode), PIDTYPE_PID); |
77 | } | 98 | } |
78 | 99 | ||
79 | static inline int proc_fd(struct inode *inode) | ||
80 | { | ||
81 | return PROC_I(inode)->fd; | ||
82 | } | ||
83 | |||
84 | static inline int task_dumpable(struct task_struct *task) | 100 | static inline int task_dumpable(struct task_struct *task) |
85 | { | 101 | { |
86 | int dumpable = 0; | 102 | int dumpable = 0; |
@@ -96,15 +112,6 @@ static inline int task_dumpable(struct task_struct *task) | |||
96 | return 0; | 112 | return 0; |
97 | } | 113 | } |
98 | 114 | ||
99 | static inline int pid_delete_dentry(const struct dentry * dentry) | ||
100 | { | ||
101 | /* Is the task we represent dead? | ||
102 | * If so, then don't put the dentry on the lru list, | ||
103 | * kill it immediately. | ||
104 | */ | ||
105 | return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first; | ||
106 | } | ||
107 | |||
108 | static inline unsigned name_to_int(struct dentry *dentry) | 115 | static inline unsigned name_to_int(struct dentry *dentry) |
109 | { | 116 | { |
110 | const char *name = dentry->d_name.name; | 117 | const char *name = dentry->d_name.name; |
@@ -127,63 +134,165 @@ out: | |||
127 | return ~0U; | 134 | return ~0U; |
128 | } | 135 | } |
129 | 136 | ||
130 | struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *ino, | 137 | /* |
131 | struct dentry *dentry); | 138 | * Offset of the first process in the /proc root directory.. |
132 | int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent, | 139 | */ |
133 | filldir_t filldir); | 140 | #define FIRST_PROCESS_ENTRY 256 |
141 | |||
142 | /* Worst case buffer size needed for holding an integer. */ | ||
143 | #define PROC_NUMBUF 13 | ||
134 | 144 | ||
135 | struct pde_opener { | 145 | /* |
136 | struct inode *inode; | 146 | * array.c |
137 | struct file *file; | 147 | */ |
138 | int (*release)(struct inode *, struct file *); | 148 | extern const struct file_operations proc_tid_children_operations; |
139 | struct list_head lh; | ||
140 | }; | ||
141 | void pde_users_dec(struct proc_dir_entry *pde); | ||
142 | 149 | ||
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 *); | ||
168 | extern int proc_pid_readdir(struct file *, void *, filldir_t); | ||
169 | extern struct dentry *proc_pid_lookup(struct inode *, struct dentry *, unsigned int); | ||
170 | extern loff_t mem_lseek(struct file *, loff_t, int); | ||
171 | |||
172 | /* Lookups */ | ||
173 | typedef struct dentry *instantiate_t(struct inode *, struct dentry *, | ||
174 | struct task_struct *, const void *); | ||
175 | extern int proc_fill_cache(struct file *, void *, filldir_t, const char *, int, | ||
176 | instantiate_t, struct task_struct *, const void *); | ||
177 | |||
178 | /* | ||
179 | * generic.c | ||
180 | */ | ||
143 | extern spinlock_t proc_subdir_lock; | 181 | extern spinlock_t proc_subdir_lock; |
144 | 182 | ||
145 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int); | 183 | extern struct dentry *proc_lookup(struct inode *, struct dentry *, unsigned int); |
146 | int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir); | 184 | extern struct dentry *proc_lookup_de(struct proc_dir_entry *, struct inode *, |
147 | unsigned long task_vsize(struct mm_struct *); | 185 | struct dentry *); |
148 | unsigned long task_statm(struct mm_struct *, | 186 | extern int proc_readdir(struct file *, void *, filldir_t); |
149 | unsigned long *, unsigned long *, unsigned long *, unsigned long *); | 187 | extern int proc_readdir_de(struct proc_dir_entry *, struct file *, void *, filldir_t); |
150 | void task_mem(struct seq_file *, struct mm_struct *); | ||
151 | 188 | ||
152 | static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) | 189 | static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) |
153 | { | 190 | { |
154 | atomic_inc(&pde->count); | 191 | atomic_inc(&pde->count); |
155 | return pde; | 192 | return pde; |
156 | } | 193 | } |
157 | void pde_put(struct proc_dir_entry *pde); | 194 | extern void pde_put(struct proc_dir_entry *); |
158 | |||
159 | int proc_fill_super(struct super_block *); | ||
160 | struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); | ||
161 | int proc_remount(struct super_block *sb, int *flags, char *data); | ||
162 | 195 | ||
163 | /* | 196 | /* |
164 | * These are generic /proc routines that use the internal | 197 | * inode.c |
165 | * "struct proc_dir_entry" tree to traverse the filesystem. | ||
166 | * | ||
167 | * The /proc root directory has extended versions to take care | ||
168 | * of the /proc/<pid> subdirectories. | ||
169 | */ | 198 | */ |
170 | int proc_readdir(struct file *, void *, filldir_t); | 199 | struct pde_opener { |
171 | struct dentry *proc_lookup(struct inode *, struct dentry *, unsigned int); | 200 | struct file *file; |
201 | struct list_head lh; | ||
202 | int closing; | ||
203 | struct completion *c; | ||
204 | }; | ||
172 | 205 | ||
206 | extern const struct inode_operations proc_pid_link_inode_operations; | ||
173 | 207 | ||
208 | extern void proc_init_inodecache(void); | ||
209 | extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); | ||
210 | extern int proc_fill_super(struct super_block *); | ||
211 | extern void proc_entry_rundown(struct proc_dir_entry *); | ||
174 | 212 | ||
175 | /* Lookups */ | 213 | /* |
176 | typedef struct dentry *instantiate_t(struct inode *, struct dentry *, | 214 | * proc_devtree.c |
177 | struct task_struct *, const void *); | 215 | */ |
178 | int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | 216 | #ifdef CONFIG_PROC_DEVICETREE |
179 | const char *name, int len, | 217 | extern void proc_device_tree_init(void); |
180 | instantiate_t instantiate, struct task_struct *task, const void *ptr); | 218 | #endif |
181 | int pid_revalidate(struct dentry *dentry, unsigned int flags); | ||
182 | struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task); | ||
183 | extern const struct dentry_operations pid_dentry_operations; | ||
184 | int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); | ||
185 | int proc_setattr(struct dentry *dentry, struct iattr *attr); | ||
186 | 219 | ||
220 | /* | ||
221 | * proc_namespaces.c | ||
222 | */ | ||
187 | extern const struct inode_operations proc_ns_dir_inode_operations; | 223 | extern const struct inode_operations proc_ns_dir_inode_operations; |
188 | extern const struct file_operations proc_ns_dir_operations; | 224 | extern const struct file_operations proc_ns_dir_operations; |
189 | 225 | ||
226 | /* | ||
227 | * proc_net.c | ||
228 | */ | ||
229 | extern const struct file_operations proc_net_operations; | ||
230 | extern const struct inode_operations proc_net_inode_operations; | ||
231 | |||
232 | #ifdef CONFIG_NET | ||
233 | extern int proc_net_init(void); | ||
234 | #else | ||
235 | static inline int proc_net_init(void) { return 0; } | ||
236 | #endif | ||
237 | |||
238 | /* | ||
239 | * proc_self.c | ||
240 | */ | ||
241 | extern int proc_setup_self(struct super_block *); | ||
242 | |||
243 | /* | ||
244 | * proc_sysctl.c | ||
245 | */ | ||
246 | #ifdef CONFIG_PROC_SYSCTL | ||
247 | extern int proc_sys_init(void); | ||
248 | extern void sysctl_head_put(struct ctl_table_header *); | ||
249 | #else | ||
250 | static inline void proc_sys_init(void) { } | ||
251 | static inline void sysctl_head_put(struct ctl_table_header *head) { } | ||
252 | #endif | ||
253 | |||
254 | /* | ||
255 | * proc_tty.c | ||
256 | */ | ||
257 | #ifdef CONFIG_TTY | ||
258 | extern void proc_tty_init(void); | ||
259 | #else | ||
260 | static inline void proc_tty_init(void) {} | ||
261 | #endif | ||
262 | |||
263 | /* | ||
264 | * root.c | ||
265 | */ | ||
266 | extern struct proc_dir_entry proc_root; | ||
267 | |||
268 | extern void proc_self_init(void); | ||
269 | extern int proc_remount(struct super_block *, int *, char *); | ||
270 | |||
271 | /* | ||
272 | * task_[no]mmu.c | ||
273 | */ | ||
274 | struct proc_maps_private { | ||
275 | struct pid *pid; | ||
276 | struct task_struct *task; | ||
277 | #ifdef CONFIG_MMU | ||
278 | struct vm_area_struct *tail_vma; | ||
279 | #endif | ||
280 | #ifdef CONFIG_NUMA | ||
281 | struct mempolicy *task_mempolicy; | ||
282 | #endif | ||
283 | }; | ||
284 | |||
285 | extern const struct file_operations proc_pid_maps_operations; | ||
286 | extern const struct file_operations proc_tid_maps_operations; | ||
287 | extern const struct file_operations proc_pid_numa_maps_operations; | ||
288 | extern const struct file_operations proc_tid_numa_maps_operations; | ||
289 | extern const struct file_operations proc_pid_smaps_operations; | ||
290 | extern const struct file_operations proc_tid_smaps_operations; | ||
291 | extern const struct file_operations proc_clear_refs_operations; | ||
292 | extern const struct file_operations proc_pagemap_operations; | ||
293 | |||
294 | extern unsigned long task_vsize(struct mm_struct *); | ||
295 | extern unsigned long task_statm(struct mm_struct *, | ||
296 | unsigned long *, unsigned long *, | ||
297 | unsigned long *, unsigned long *); | ||
298 | extern void task_mem(struct seq_file *, struct mm_struct *); | ||
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index f6a13f489e30..0a22194e5d58 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
13 | #include <linux/proc_fs.h> | 13 | #include <linux/proc_fs.h> |
14 | #include <linux/kcore.h> | ||
14 | #include <linux/user.h> | 15 | #include <linux/user.h> |
15 | #include <linux/capability.h> | 16 | #include <linux/capability.h> |
16 | #include <linux/elf.h> | 17 | #include <linux/elf.h> |
@@ -28,6 +29,7 @@ | |||
28 | #include <linux/ioport.h> | 29 | #include <linux/ioport.h> |
29 | #include <linux/memory.h> | 30 | #include <linux/memory.h> |
30 | #include <asm/sections.h> | 31 | #include <asm/sections.h> |
32 | #include "internal.h" | ||
31 | 33 | ||
32 | #define CORE_STR "CORE" | 34 | #define CORE_STR "CORE" |
33 | 35 | ||
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 66b51c0383da..54bdc6701e9f 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c | |||
@@ -51,7 +51,7 @@ static int ns_delete_dentry(const struct dentry *dentry) | |||
51 | static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) | 51 | static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) |
52 | { | 52 | { |
53 | struct inode *inode = dentry->d_inode; | 53 | struct inode *inode = dentry->d_inode; |
54 | const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; | 54 | const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops; |
55 | 55 | ||
56 | return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]", | 56 | return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]", |
57 | ns_ops->name, inode->i_ino); | 57 | ns_ops->name, inode->i_ino); |
@@ -95,8 +95,8 @@ static struct dentry *proc_ns_get_dentry(struct super_block *sb, | |||
95 | inode->i_op = &ns_inode_operations; | 95 | inode->i_op = &ns_inode_operations; |
96 | inode->i_mode = S_IFREG | S_IRUGO; | 96 | inode->i_mode = S_IFREG | S_IRUGO; |
97 | inode->i_fop = &ns_file_operations; | 97 | inode->i_fop = &ns_file_operations; |
98 | ei->ns_ops = ns_ops; | 98 | ei->ns.ns_ops = ns_ops; |
99 | ei->ns = ns; | 99 | ei->ns.ns = ns; |
100 | unlock_new_inode(inode); | 100 | unlock_new_inode(inode); |
101 | } else { | 101 | } else { |
102 | ns_ops->put(ns); | 102 | ns_ops->put(ns); |
@@ -128,7 +128,7 @@ static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
128 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | 128 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) |
129 | goto out_put_task; | 129 | goto out_put_task; |
130 | 130 | ||
131 | ns_path.dentry = proc_ns_get_dentry(sb, task, ei->ns_ops); | 131 | ns_path.dentry = proc_ns_get_dentry(sb, task, ei->ns.ns_ops); |
132 | if (IS_ERR(ns_path.dentry)) { | 132 | if (IS_ERR(ns_path.dentry)) { |
133 | error = ERR_CAST(ns_path.dentry); | 133 | error = ERR_CAST(ns_path.dentry); |
134 | goto out_put_task; | 134 | goto out_put_task; |
@@ -148,7 +148,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl | |||
148 | { | 148 | { |
149 | struct inode *inode = dentry->d_inode; | 149 | struct inode *inode = dentry->d_inode; |
150 | struct proc_inode *ei = PROC_I(inode); | 150 | struct proc_inode *ei = PROC_I(inode); |
151 | const struct proc_ns_operations *ns_ops = ei->ns_ops; | 151 | const struct proc_ns_operations *ns_ops = ei->ns.ns_ops; |
152 | struct task_struct *task; | 152 | struct task_struct *task; |
153 | void *ns; | 153 | void *ns; |
154 | char name[50]; | 154 | char name[50]; |
@@ -202,7 +202,7 @@ static struct dentry *proc_ns_instantiate(struct inode *dir, | |||
202 | ei = PROC_I(inode); | 202 | ei = PROC_I(inode); |
203 | inode->i_mode = S_IFLNK|S_IRWXUGO; | 203 | inode->i_mode = S_IFLNK|S_IRWXUGO; |
204 | inode->i_op = &proc_ns_link_inode_operations; | 204 | inode->i_op = &proc_ns_link_inode_operations; |
205 | ei->ns_ops = ns_ops; | 205 | ei->ns.ns_ops = ns_ops; |
206 | 206 | ||
207 | d_set_d_op(dentry, &pid_dentry_operations); | 207 | d_set_d_op(dentry, &pid_dentry_operations); |
208 | d_add(dentry, inode); | 208 | d_add(dentry, inode); |
@@ -337,6 +337,11 @@ out_invalid: | |||
337 | return ERR_PTR(-EINVAL); | 337 | return ERR_PTR(-EINVAL); |
338 | } | 338 | } |
339 | 339 | ||
340 | struct proc_ns *get_proc_ns(struct inode *inode) | ||
341 | { | ||
342 | return &PROC_I(inode)->ns; | ||
343 | } | ||
344 | |||
340 | bool proc_ns_inode(struct inode *inode) | 345 | bool proc_ns_inode(struct inode *inode) |
341 | { | 346 | { |
342 | return inode->i_fop == &ns_file_operations; | 347 | return inode->i_fop == &ns_file_operations; |
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 30b590f5bd35..505afc950e0a 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c | |||
@@ -41,7 +41,7 @@ static int property_proc_show(struct seq_file *m, void *v) | |||
41 | 41 | ||
42 | static int property_proc_open(struct inode *inode, struct file *file) | 42 | static int property_proc_open(struct inode *inode, struct file *file) |
43 | { | 43 | { |
44 | return single_open(file, property_proc_show, PDE(inode)->data); | 44 | return single_open(file, property_proc_show, __PDE_DATA(inode)); |
45 | } | 45 | } |
46 | 46 | ||
47 | static const struct file_operations property_proc_fops = { | 47 | static const struct file_operations property_proc_fops = { |
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index b4ac6572474f..986e83220d56 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c | |||
@@ -26,6 +26,10 @@ | |||
26 | 26 | ||
27 | #include "internal.h" | 27 | #include "internal.h" |
28 | 28 | ||
29 | static inline struct net *PDE_NET(struct proc_dir_entry *pde) | ||
30 | { | ||
31 | return pde->parent->data; | ||
32 | } | ||
29 | 33 | ||
30 | static struct net *get_proc_net(const struct inode *inode) | 34 | static struct net *get_proc_net(const struct inode *inode) |
31 | { | 35 | { |
diff --git a/fs/proc/root.c b/fs/proc/root.c index 9c7fab1d23f0..41a6ea93f486 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
@@ -141,6 +141,8 @@ static void proc_kill_sb(struct super_block *sb) | |||
141 | struct pid_namespace *ns; | 141 | struct pid_namespace *ns; |
142 | 142 | ||
143 | ns = (struct pid_namespace *)sb->s_fs_info; | 143 | ns = (struct pid_namespace *)sb->s_fs_info; |
144 | if (ns->proc_self) | ||
145 | dput(ns->proc_self); | ||
144 | kill_anon_super(sb); | 146 | kill_anon_super(sb); |
145 | put_pid_ns(ns); | 147 | put_pid_ns(ns); |
146 | } | 148 | } |
diff --git a/fs/proc/self.c b/fs/proc/self.c index aa5cc3bff140..6b6a993b5c25 100644 --- a/fs/proc/self.c +++ b/fs/proc/self.c | |||
@@ -1,6 +1,8 @@ | |||
1 | #include <linux/proc_fs.h> | ||
2 | #include <linux/sched.h> | 1 | #include <linux/sched.h> |
3 | #include <linux/namei.h> | 2 | #include <linux/namei.h> |
3 | #include <linux/slab.h> | ||
4 | #include <linux/pid_namespace.h> | ||
5 | #include "internal.h" | ||
4 | 6 | ||
5 | /* | 7 | /* |
6 | * /proc/self: | 8 | * /proc/self: |
@@ -48,12 +50,43 @@ static const struct inode_operations proc_self_inode_operations = { | |||
48 | .put_link = proc_self_put_link, | 50 | .put_link = proc_self_put_link, |
49 | }; | 51 | }; |
50 | 52 | ||
51 | void __init proc_self_init(void) | 53 | static unsigned self_inum; |
54 | |||
55 | int proc_setup_self(struct super_block *s) | ||
52 | { | 56 | { |
53 | struct proc_dir_entry *proc_self_symlink; | 57 | struct inode *root_inode = s->s_root->d_inode; |
54 | mode_t mode; | 58 | struct pid_namespace *ns = s->s_fs_info; |
59 | struct dentry *self; | ||
60 | |||
61 | mutex_lock(&root_inode->i_mutex); | ||
62 | self = d_alloc_name(s->s_root, "self"); | ||
63 | if (self) { | ||
64 | struct inode *inode = new_inode_pseudo(s); | ||
65 | if (inode) { | ||
66 | inode->i_ino = self_inum; | ||
67 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | ||
68 | inode->i_mode = S_IFLNK | S_IRWXUGO; | ||
69 | inode->i_uid = GLOBAL_ROOT_UID; | ||
70 | inode->i_gid = GLOBAL_ROOT_GID; | ||
71 | inode->i_op = &proc_self_inode_operations; | ||
72 | d_add(self, inode); | ||
73 | } else { | ||
74 | dput(self); | ||
75 | self = ERR_PTR(-ENOMEM); | ||
76 | } | ||
77 | } else { | ||
78 | self = ERR_PTR(-ENOMEM); | ||
79 | } | ||
80 | mutex_unlock(&root_inode->i_mutex); | ||
81 | if (IS_ERR(self)) { | ||
82 | pr_err("proc_fill_super: can't allocate /proc/self\n"); | ||
83 | return PTR_ERR(self); | ||
84 | } | ||
85 | ns->proc_self = self; | ||
86 | return 0; | ||
87 | } | ||
55 | 88 | ||
56 | mode = S_IFLNK | S_IRWXUGO; | 89 | void __init proc_self_init(void) |
57 | proc_self_symlink = proc_create("self", mode, NULL, NULL ); | 90 | { |
58 | proc_self_symlink->proc_iops = &proc_self_inode_operations; | 91 | proc_alloc_inum(&self_inum); |
59 | } | 92 | } |
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index b870f740ab5a..17f7e080d7ff 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c | |||
@@ -8,7 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
11 | #include <linux/proc_fs.h> | 11 | #include <linux/kcore.h> |
12 | #include <linux/user.h> | 12 | #include <linux/user.h> |
13 | #include <linux/elf.h> | 13 | #include <linux/elf.h> |
14 | #include <linux/elfcore.h> | 14 | #include <linux/elfcore.h> |
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/list.h> | 22 | #include <linux/list.h> |
23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
24 | #include <asm/io.h> | 24 | #include <asm/io.h> |
25 | #include "internal.h" | ||
25 | 26 | ||
26 | /* List representing chunks of contiguous memory areas and their offsets in | 27 | /* List representing chunks of contiguous memory areas and their offsets in |
27 | * vmcore file. | 28 | * vmcore file. |
@@ -698,7 +699,7 @@ void vmcore_cleanup(void) | |||
698 | struct list_head *pos, *next; | 699 | struct list_head *pos, *next; |
699 | 700 | ||
700 | if (proc_vmcore) { | 701 | if (proc_vmcore) { |
701 | remove_proc_entry(proc_vmcore->name, proc_vmcore->parent); | 702 | proc_remove(proc_vmcore); |
702 | proc_vmcore = NULL; | 703 | proc_vmcore = NULL; |
703 | } | 704 | } |
704 | 705 | ||