diff options
author | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2008-05-19 01:09:05 -0400 |
---|---|---|
committer | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2008-05-19 01:09:05 -0400 |
commit | c203e45f069af47ca7623e4dcd8c00bfba2722e4 (patch) | |
tree | 4563115b6565dcfd97015c1c9366fb3d07cabf19 /fs/proc | |
parent | a94477da38e0b261a7ecea71f4c95a3bcd5be69c (diff) | |
parent | b8291ad07a7f3b5b990900f0001198ac23ba893e (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into for-linus
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 8 | ||||
-rw-r--r-- | fs/proc/base.c | 114 | ||||
-rw-r--r-- | fs/proc/generic.c | 149 | ||||
-rw-r--r-- | fs/proc/inode.c | 69 | ||||
-rw-r--r-- | fs/proc/internal.h | 4 | ||||
-rw-r--r-- | fs/proc/nommu.c | 2 | ||||
-rw-r--r-- | fs/proc/proc_misc.c | 68 | ||||
-rw-r--r-- | fs/proc/proc_net.c | 11 | ||||
-rw-r--r-- | fs/proc/proc_sysctl.c | 52 | ||||
-rw-r--r-- | fs/proc/proc_tty.c | 87 | ||||
-rw-r--r-- | fs/proc/root.c | 14 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 36 | ||||
-rw-r--r-- | fs/proc/task_nommu.c | 35 |
13 files changed, 315 insertions, 334 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 07d6c4853fe8..9e3b8c33c24b 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -73,6 +73,7 @@ | |||
73 | #include <linux/signal.h> | 73 | #include <linux/signal.h> |
74 | #include <linux/highmem.h> | 74 | #include <linux/highmem.h> |
75 | #include <linux/file.h> | 75 | #include <linux/file.h> |
76 | #include <linux/fdtable.h> | ||
76 | #include <linux/times.h> | 77 | #include <linux/times.h> |
77 | #include <linux/cpuset.h> | 78 | #include <linux/cpuset.h> |
78 | #include <linux/rcupdate.h> | 79 | #include <linux/rcupdate.h> |
@@ -297,6 +298,7 @@ static inline void task_cap(struct seq_file *m, struct task_struct *p) | |||
297 | render_cap_t(m, "CapInh:\t", &p->cap_inheritable); | 298 | render_cap_t(m, "CapInh:\t", &p->cap_inheritable); |
298 | render_cap_t(m, "CapPrm:\t", &p->cap_permitted); | 299 | render_cap_t(m, "CapPrm:\t", &p->cap_permitted); |
299 | render_cap_t(m, "CapEff:\t", &p->cap_effective); | 300 | render_cap_t(m, "CapEff:\t", &p->cap_effective); |
301 | render_cap_t(m, "CapBnd:\t", &p->cap_bset); | ||
300 | } | 302 | } |
301 | 303 | ||
302 | static inline void task_context_switch_counts(struct seq_file *m, | 304 | static inline void task_context_switch_counts(struct seq_file *m, |
@@ -425,12 +427,13 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
425 | cutime = cstime = utime = stime = cputime_zero; | 427 | cutime = cstime = utime = stime = cputime_zero; |
426 | cgtime = gtime = cputime_zero; | 428 | cgtime = gtime = cputime_zero; |
427 | 429 | ||
428 | rcu_read_lock(); | ||
429 | if (lock_task_sighand(task, &flags)) { | 430 | if (lock_task_sighand(task, &flags)) { |
430 | struct signal_struct *sig = task->signal; | 431 | struct signal_struct *sig = task->signal; |
431 | 432 | ||
432 | if (sig->tty) { | 433 | if (sig->tty) { |
433 | tty_pgrp = pid_nr_ns(sig->tty->pgrp, ns); | 434 | struct pid *pgrp = tty_get_pgrp(sig->tty); |
435 | tty_pgrp = pid_nr_ns(pgrp, ns); | ||
436 | put_pid(pgrp); | ||
434 | tty_nr = new_encode_dev(tty_devnum(sig->tty)); | 437 | tty_nr = new_encode_dev(tty_devnum(sig->tty)); |
435 | } | 438 | } |
436 | 439 | ||
@@ -469,7 +472,6 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
469 | 472 | ||
470 | unlock_task_sighand(task, &flags); | 473 | unlock_task_sighand(task, &flags); |
471 | } | 474 | } |
472 | rcu_read_unlock(); | ||
473 | 475 | ||
474 | if (!whole || num_threads < 2) | 476 | if (!whole || num_threads < 2) |
475 | wchan = get_wchan(task); | 477 | wchan = get_wchan(task); |
diff --git a/fs/proc/base.c b/fs/proc/base.c index c5e412a00b17..808cbdc193d3 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <linux/init.h> | 56 | #include <linux/init.h> |
57 | #include <linux/capability.h> | 57 | #include <linux/capability.h> |
58 | #include <linux/file.h> | 58 | #include <linux/file.h> |
59 | #include <linux/fdtable.h> | ||
59 | #include <linux/string.h> | 60 | #include <linux/string.h> |
60 | #include <linux/seq_file.h> | 61 | #include <linux/seq_file.h> |
61 | #include <linux/namei.h> | 62 | #include <linux/namei.h> |
@@ -195,12 +196,32 @@ static int proc_root_link(struct inode *inode, struct path *path) | |||
195 | return result; | 196 | return result; |
196 | } | 197 | } |
197 | 198 | ||
198 | #define MAY_PTRACE(task) \ | 199 | /* |
199 | (task == current || \ | 200 | * Return zero if current may access user memory in @task, -error if not. |
200 | (task->parent == current && \ | 201 | */ |
201 | (task->ptrace & PT_PTRACED) && \ | 202 | static int check_mem_permission(struct task_struct *task) |
202 | (task_is_stopped_or_traced(task)) && \ | 203 | { |
203 | security_ptrace(current,task) == 0)) | 204 | /* |
205 | * A task can always look at itself, in case it chooses | ||
206 | * to use system calls instead of load instructions. | ||
207 | */ | ||
208 | if (task == current) | ||
209 | return 0; | ||
210 | |||
211 | /* | ||
212 | * If current is actively ptrace'ing, and would also be | ||
213 | * permitted to freshly attach with ptrace now, permit it. | ||
214 | */ | ||
215 | if (task->parent == current && (task->ptrace & PT_PTRACED) && | ||
216 | task_is_stopped_or_traced(task) && | ||
217 | ptrace_may_attach(task)) | ||
218 | return 0; | ||
219 | |||
220 | /* | ||
221 | * Noone else is allowed. | ||
222 | */ | ||
223 | return -EPERM; | ||
224 | } | ||
204 | 225 | ||
205 | struct mm_struct *mm_for_maps(struct task_struct *task) | 226 | struct mm_struct *mm_for_maps(struct task_struct *task) |
206 | { | 227 | { |
@@ -722,7 +743,7 @@ static ssize_t mem_read(struct file * file, char __user * buf, | |||
722 | if (!task) | 743 | if (!task) |
723 | goto out_no_task; | 744 | goto out_no_task; |
724 | 745 | ||
725 | if (!MAY_PTRACE(task) || !ptrace_may_attach(task)) | 746 | if (check_mem_permission(task)) |
726 | goto out; | 747 | goto out; |
727 | 748 | ||
728 | ret = -ENOMEM; | 749 | ret = -ENOMEM; |
@@ -748,7 +769,7 @@ static ssize_t mem_read(struct file * file, char __user * buf, | |||
748 | 769 | ||
749 | this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; | 770 | this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; |
750 | retval = access_process_vm(task, src, page, this_len, 0); | 771 | retval = access_process_vm(task, src, page, this_len, 0); |
751 | if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) { | 772 | if (!retval || check_mem_permission(task)) { |
752 | if (!ret) | 773 | if (!ret) |
753 | ret = -EIO; | 774 | ret = -EIO; |
754 | break; | 775 | break; |
@@ -792,7 +813,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf, | |||
792 | if (!task) | 813 | if (!task) |
793 | goto out_no_task; | 814 | goto out_no_task; |
794 | 815 | ||
795 | if (!MAY_PTRACE(task) || !ptrace_may_attach(task)) | 816 | if (check_mem_permission(task)) |
796 | goto out; | 817 | goto out; |
797 | 818 | ||
798 | copied = -ENOMEM; | 819 | copied = -ENOMEM; |
@@ -1181,6 +1202,81 @@ static const struct file_operations proc_pid_sched_operations = { | |||
1181 | 1202 | ||
1182 | #endif | 1203 | #endif |
1183 | 1204 | ||
1205 | /* | ||
1206 | * We added or removed a vma mapping the executable. The vmas are only mapped | ||
1207 | * during exec and are not mapped with the mmap system call. | ||
1208 | * Callers must hold down_write() on the mm's mmap_sem for these | ||
1209 | */ | ||
1210 | void added_exe_file_vma(struct mm_struct *mm) | ||
1211 | { | ||
1212 | mm->num_exe_file_vmas++; | ||
1213 | } | ||
1214 | |||
1215 | void removed_exe_file_vma(struct mm_struct *mm) | ||
1216 | { | ||
1217 | mm->num_exe_file_vmas--; | ||
1218 | if ((mm->num_exe_file_vmas == 0) && mm->exe_file){ | ||
1219 | fput(mm->exe_file); | ||
1220 | mm->exe_file = NULL; | ||
1221 | } | ||
1222 | |||
1223 | } | ||
1224 | |||
1225 | void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file) | ||
1226 | { | ||
1227 | if (new_exe_file) | ||
1228 | get_file(new_exe_file); | ||
1229 | if (mm->exe_file) | ||
1230 | fput(mm->exe_file); | ||
1231 | mm->exe_file = new_exe_file; | ||
1232 | mm->num_exe_file_vmas = 0; | ||
1233 | } | ||
1234 | |||
1235 | struct file *get_mm_exe_file(struct mm_struct *mm) | ||
1236 | { | ||
1237 | struct file *exe_file; | ||
1238 | |||
1239 | /* We need mmap_sem to protect against races with removal of | ||
1240 | * VM_EXECUTABLE vmas */ | ||
1241 | down_read(&mm->mmap_sem); | ||
1242 | exe_file = mm->exe_file; | ||
1243 | if (exe_file) | ||
1244 | get_file(exe_file); | ||
1245 | up_read(&mm->mmap_sem); | ||
1246 | return exe_file; | ||
1247 | } | ||
1248 | |||
1249 | void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm) | ||
1250 | { | ||
1251 | /* It's safe to write the exe_file pointer without exe_file_lock because | ||
1252 | * this is called during fork when the task is not yet in /proc */ | ||
1253 | newmm->exe_file = get_mm_exe_file(oldmm); | ||
1254 | } | ||
1255 | |||
1256 | static int proc_exe_link(struct inode *inode, struct path *exe_path) | ||
1257 | { | ||
1258 | struct task_struct *task; | ||
1259 | struct mm_struct *mm; | ||
1260 | struct file *exe_file; | ||
1261 | |||
1262 | task = get_proc_task(inode); | ||
1263 | if (!task) | ||
1264 | return -ENOENT; | ||
1265 | mm = get_task_mm(task); | ||
1266 | put_task_struct(task); | ||
1267 | if (!mm) | ||
1268 | return -ENOENT; | ||
1269 | exe_file = get_mm_exe_file(mm); | ||
1270 | mmput(mm); | ||
1271 | if (exe_file) { | ||
1272 | *exe_path = exe_file->f_path; | ||
1273 | path_get(&exe_file->f_path); | ||
1274 | fput(exe_file); | ||
1275 | return 0; | ||
1276 | } else | ||
1277 | return -ENOENT; | ||
1278 | } | ||
1279 | |||
1184 | static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) | 1280 | static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) |
1185 | { | 1281 | { |
1186 | struct inode *inode = dentry->d_inode; | 1282 | struct inode *inode = dentry->d_inode; |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index a36ad3c75cf4..43e54e86cefd 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -69,12 +69,7 @@ proc_file_read(struct file *file, char __user *buf, size_t nbytes, | |||
69 | count = min_t(size_t, PROC_BLOCK_SIZE, nbytes); | 69 | count = min_t(size_t, PROC_BLOCK_SIZE, nbytes); |
70 | 70 | ||
71 | start = NULL; | 71 | start = NULL; |
72 | if (dp->get_info) { | 72 | if (dp->read_proc) { |
73 | /* Handle old net routines */ | ||
74 | n = dp->get_info(page, &start, *ppos, count); | ||
75 | if (n < count) | ||
76 | eof = 1; | ||
77 | } else if (dp->read_proc) { | ||
78 | /* | 73 | /* |
79 | * How to be a proc read function | 74 | * How to be a proc read function |
80 | * ------------------------------ | 75 | * ------------------------------ |
@@ -277,8 +272,11 @@ static int xlate_proc_name(const char *name, | |||
277 | int len; | 272 | int len; |
278 | int rtn = 0; | 273 | int rtn = 0; |
279 | 274 | ||
275 | de = *ret; | ||
276 | if (!de) | ||
277 | de = &proc_root; | ||
278 | |||
280 | spin_lock(&proc_subdir_lock); | 279 | spin_lock(&proc_subdir_lock); |
281 | de = &proc_root; | ||
282 | while (1) { | 280 | while (1) { |
283 | next = strchr(cp, '/'); | 281 | next = strchr(cp, '/'); |
284 | if (!next) | 282 | if (!next) |
@@ -385,20 +383,18 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, | |||
385 | 383 | ||
386 | lock_kernel(); | 384 | lock_kernel(); |
387 | spin_lock(&proc_subdir_lock); | 385 | spin_lock(&proc_subdir_lock); |
388 | if (de) { | 386 | for (de = de->subdir; de ; de = de->next) { |
389 | for (de = de->subdir; de ; de = de->next) { | 387 | if (de->namelen != dentry->d_name.len) |
390 | if (de->namelen != dentry->d_name.len) | 388 | continue; |
391 | continue; | 389 | if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { |
392 | if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { | 390 | unsigned int ino; |
393 | unsigned int ino; | ||
394 | 391 | ||
395 | ino = de->low_ino; | 392 | ino = de->low_ino; |
396 | de_get(de); | 393 | de_get(de); |
397 | spin_unlock(&proc_subdir_lock); | 394 | spin_unlock(&proc_subdir_lock); |
398 | error = -EINVAL; | 395 | error = -EINVAL; |
399 | inode = proc_get_inode(dir->i_sb, ino, de); | 396 | inode = proc_get_inode(dir->i_sb, ino, de); |
400 | goto out_unlock; | 397 | goto out_unlock; |
401 | } | ||
402 | } | 398 | } |
403 | } | 399 | } |
404 | spin_unlock(&proc_subdir_lock); | 400 | spin_unlock(&proc_subdir_lock); |
@@ -410,7 +406,8 @@ out_unlock: | |||
410 | d_add(dentry, inode); | 406 | d_add(dentry, inode); |
411 | return NULL; | 407 | return NULL; |
412 | } | 408 | } |
413 | de_put(de); | 409 | if (de) |
410 | de_put(de); | ||
414 | return ERR_PTR(error); | 411 | return ERR_PTR(error); |
415 | } | 412 | } |
416 | 413 | ||
@@ -440,10 +437,6 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent, | |||
440 | lock_kernel(); | 437 | lock_kernel(); |
441 | 438 | ||
442 | ino = inode->i_ino; | 439 | ino = inode->i_ino; |
443 | if (!de) { | ||
444 | ret = -EINVAL; | ||
445 | goto out; | ||
446 | } | ||
447 | i = filp->f_pos; | 440 | i = filp->f_pos; |
448 | switch (i) { | 441 | switch (i) { |
449 | case 0: | 442 | case 0: |
@@ -582,7 +575,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, | |||
582 | /* make sure name is valid */ | 575 | /* make sure name is valid */ |
583 | if (!name || !strlen(name)) goto out; | 576 | if (!name || !strlen(name)) goto out; |
584 | 577 | ||
585 | if (!(*parent) && xlate_proc_name(name, parent, &fn) != 0) | 578 | if (xlate_proc_name(name, parent, &fn) != 0) |
586 | goto out; | 579 | goto out; |
587 | 580 | ||
588 | /* At this point there must not be any '/' characters beyond *fn */ | 581 | /* At this point there must not be any '/' characters beyond *fn */ |
@@ -648,6 +641,23 @@ struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode, | |||
648 | return ent; | 641 | return ent; |
649 | } | 642 | } |
650 | 643 | ||
644 | struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name, | ||
645 | struct proc_dir_entry *parent) | ||
646 | { | ||
647 | struct proc_dir_entry *ent; | ||
648 | |||
649 | ent = __proc_create(&parent, name, S_IFDIR | S_IRUGO | S_IXUGO, 2); | ||
650 | if (ent) { | ||
651 | ent->data = net; | ||
652 | if (proc_register(parent, ent) < 0) { | ||
653 | kfree(ent); | ||
654 | ent = NULL; | ||
655 | } | ||
656 | } | ||
657 | return ent; | ||
658 | } | ||
659 | EXPORT_SYMBOL_GPL(proc_net_mkdir); | ||
660 | |||
651 | struct proc_dir_entry *proc_mkdir(const char *name, | 661 | struct proc_dir_entry *proc_mkdir(const char *name, |
652 | struct proc_dir_entry *parent) | 662 | struct proc_dir_entry *parent) |
653 | { | 663 | { |
@@ -682,9 +692,10 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, | |||
682 | return ent; | 692 | return ent; |
683 | } | 693 | } |
684 | 694 | ||
685 | struct proc_dir_entry *proc_create(const char *name, mode_t mode, | 695 | struct proc_dir_entry *proc_create_data(const char *name, mode_t mode, |
686 | struct proc_dir_entry *parent, | 696 | struct proc_dir_entry *parent, |
687 | const struct file_operations *proc_fops) | 697 | const struct file_operations *proc_fops, |
698 | void *data) | ||
688 | { | 699 | { |
689 | struct proc_dir_entry *pde; | 700 | struct proc_dir_entry *pde; |
690 | nlink_t nlink; | 701 | nlink_t nlink; |
@@ -705,6 +716,7 @@ struct proc_dir_entry *proc_create(const char *name, mode_t mode, | |||
705 | if (!pde) | 716 | if (!pde) |
706 | goto out; | 717 | goto out; |
707 | pde->proc_fops = proc_fops; | 718 | pde->proc_fops = proc_fops; |
719 | pde->data = data; | ||
708 | if (proc_register(parent, pde) < 0) | 720 | if (proc_register(parent, pde) < 0) |
709 | goto out_free; | 721 | goto out_free; |
710 | return pde; | 722 | return pde; |
@@ -734,55 +746,58 @@ void free_proc_entry(struct proc_dir_entry *de) | |||
734 | void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | 746 | void remove_proc_entry(const char *name, struct proc_dir_entry *parent) |
735 | { | 747 | { |
736 | struct proc_dir_entry **p; | 748 | struct proc_dir_entry **p; |
737 | struct proc_dir_entry *de; | 749 | struct proc_dir_entry *de = NULL; |
738 | const char *fn = name; | 750 | const char *fn = name; |
739 | int len; | 751 | int len; |
740 | 752 | ||
741 | if (!parent && xlate_proc_name(name, &parent, &fn) != 0) | 753 | if (xlate_proc_name(name, &parent, &fn) != 0) |
742 | goto out; | 754 | return; |
743 | len = strlen(fn); | 755 | len = strlen(fn); |
744 | 756 | ||
745 | spin_lock(&proc_subdir_lock); | 757 | spin_lock(&proc_subdir_lock); |
746 | for (p = &parent->subdir; *p; p=&(*p)->next ) { | 758 | for (p = &parent->subdir; *p; p=&(*p)->next ) { |
747 | if (!proc_match(len, fn, *p)) | 759 | if (proc_match(len, fn, *p)) { |
748 | continue; | 760 | de = *p; |
749 | de = *p; | 761 | *p = de->next; |
750 | *p = de->next; | 762 | de->next = NULL; |
751 | de->next = NULL; | 763 | break; |
752 | 764 | } | |
753 | spin_lock(&de->pde_unload_lock); | 765 | } |
754 | /* | 766 | spin_unlock(&proc_subdir_lock); |
755 | * Stop accepting new callers into module. If you're | 767 | if (!de) |
756 | * dynamically allocating ->proc_fops, save a pointer somewhere. | 768 | return; |
757 | */ | ||
758 | de->proc_fops = NULL; | ||
759 | /* Wait until all existing callers into module are done. */ | ||
760 | if (de->pde_users > 0) { | ||
761 | DECLARE_COMPLETION_ONSTACK(c); | ||
762 | |||
763 | if (!de->pde_unload_completion) | ||
764 | de->pde_unload_completion = &c; | ||
765 | |||
766 | spin_unlock(&de->pde_unload_lock); | ||
767 | spin_unlock(&proc_subdir_lock); | ||
768 | 769 | ||
769 | wait_for_completion(de->pde_unload_completion); | 770 | spin_lock(&de->pde_unload_lock); |
771 | /* | ||
772 | * Stop accepting new callers into module. If you're | ||
773 | * dynamically allocating ->proc_fops, save a pointer somewhere. | ||
774 | */ | ||
775 | de->proc_fops = NULL; | ||
776 | /* Wait until all existing callers into module are done. */ | ||
777 | if (de->pde_users > 0) { | ||
778 | DECLARE_COMPLETION_ONSTACK(c); | ||
779 | |||
780 | if (!de->pde_unload_completion) | ||
781 | de->pde_unload_completion = &c; | ||
770 | 782 | ||
771 | spin_lock(&proc_subdir_lock); | ||
772 | goto continue_removing; | ||
773 | } | ||
774 | spin_unlock(&de->pde_unload_lock); | 783 | spin_unlock(&de->pde_unload_lock); |
775 | 784 | ||
785 | wait_for_completion(de->pde_unload_completion); | ||
786 | |||
787 | goto continue_removing; | ||
788 | } | ||
789 | spin_unlock(&de->pde_unload_lock); | ||
790 | |||
776 | continue_removing: | 791 | continue_removing: |
777 | if (S_ISDIR(de->mode)) | 792 | if (S_ISDIR(de->mode)) |
778 | parent->nlink--; | 793 | parent->nlink--; |
779 | de->nlink = 0; | 794 | de->nlink = 0; |
780 | WARN_ON(de->subdir); | 795 | if (de->subdir) { |
781 | if (atomic_dec_and_test(&de->count)) | 796 | printk(KERN_WARNING "%s: removing non-empty directory " |
782 | free_proc_entry(de); | 797 | "'%s/%s', leaking at least '%s'\n", __func__, |
783 | break; | 798 | de->parent->name, de->name, de->subdir->name); |
799 | WARN_ON(1); | ||
784 | } | 800 | } |
785 | spin_unlock(&proc_subdir_lock); | 801 | if (atomic_dec_and_test(&de->count)) |
786 | out: | 802 | free_proc_entry(de); |
787 | return; | ||
788 | } | 803 | } |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 82b3a1b5a70b..6f4e8dc97da1 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -25,8 +25,7 @@ | |||
25 | 25 | ||
26 | struct proc_dir_entry *de_get(struct proc_dir_entry *de) | 26 | struct proc_dir_entry *de_get(struct proc_dir_entry *de) |
27 | { | 27 | { |
28 | if (de) | 28 | atomic_inc(&de->count); |
29 | atomic_inc(&de->count); | ||
30 | return de; | 29 | return de; |
31 | } | 30 | } |
32 | 31 | ||
@@ -35,18 +34,16 @@ struct proc_dir_entry *de_get(struct proc_dir_entry *de) | |||
35 | */ | 34 | */ |
36 | void de_put(struct proc_dir_entry *de) | 35 | void de_put(struct proc_dir_entry *de) |
37 | { | 36 | { |
38 | if (de) { | 37 | lock_kernel(); |
39 | lock_kernel(); | 38 | if (!atomic_read(&de->count)) { |
40 | if (!atomic_read(&de->count)) { | 39 | printk("de_put: entry %s already free!\n", de->name); |
41 | printk("de_put: entry %s already free!\n", de->name); | ||
42 | unlock_kernel(); | ||
43 | return; | ||
44 | } | ||
45 | |||
46 | if (atomic_dec_and_test(&de->count)) | ||
47 | free_proc_entry(de); | ||
48 | unlock_kernel(); | 40 | unlock_kernel(); |
41 | return; | ||
49 | } | 42 | } |
43 | |||
44 | if (atomic_dec_and_test(&de->count)) | ||
45 | free_proc_entry(de); | ||
46 | unlock_kernel(); | ||
50 | } | 47 | } |
51 | 48 | ||
52 | /* | 49 | /* |
@@ -392,7 +389,7 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | |||
392 | { | 389 | { |
393 | struct inode * inode; | 390 | struct inode * inode; |
394 | 391 | ||
395 | if (de != NULL && !try_module_get(de->owner)) | 392 | if (!try_module_get(de->owner)) |
396 | goto out_mod; | 393 | goto out_mod; |
397 | 394 | ||
398 | inode = iget_locked(sb, ino); | 395 | inode = iget_locked(sb, ino); |
@@ -402,30 +399,29 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | |||
402 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 399 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
403 | PROC_I(inode)->fd = 0; | 400 | PROC_I(inode)->fd = 0; |
404 | PROC_I(inode)->pde = de; | 401 | PROC_I(inode)->pde = de; |
405 | if (de) { | 402 | |
406 | if (de->mode) { | 403 | if (de->mode) { |
407 | inode->i_mode = de->mode; | 404 | inode->i_mode = de->mode; |
408 | inode->i_uid = de->uid; | 405 | inode->i_uid = de->uid; |
409 | inode->i_gid = de->gid; | 406 | inode->i_gid = de->gid; |
410 | } | 407 | } |
411 | if (de->size) | 408 | if (de->size) |
412 | inode->i_size = de->size; | 409 | inode->i_size = de->size; |
413 | if (de->nlink) | 410 | if (de->nlink) |
414 | inode->i_nlink = de->nlink; | 411 | inode->i_nlink = de->nlink; |
415 | if (de->proc_iops) | 412 | if (de->proc_iops) |
416 | inode->i_op = de->proc_iops; | 413 | inode->i_op = de->proc_iops; |
417 | if (de->proc_fops) { | 414 | if (de->proc_fops) { |
418 | if (S_ISREG(inode->i_mode)) { | 415 | if (S_ISREG(inode->i_mode)) { |
419 | #ifdef CONFIG_COMPAT | 416 | #ifdef CONFIG_COMPAT |
420 | if (!de->proc_fops->compat_ioctl) | 417 | if (!de->proc_fops->compat_ioctl) |
421 | inode->i_fop = | 418 | inode->i_fop = |
422 | &proc_reg_file_ops_no_compat; | 419 | &proc_reg_file_ops_no_compat; |
423 | else | 420 | else |
424 | #endif | 421 | #endif |
425 | inode->i_fop = &proc_reg_file_ops; | 422 | inode->i_fop = &proc_reg_file_ops; |
426 | } else { | 423 | } else { |
427 | inode->i_fop = de->proc_fops; | 424 | inode->i_fop = de->proc_fops; |
428 | } | ||
429 | } | 425 | } |
430 | } | 426 | } |
431 | unlock_new_inode(inode); | 427 | unlock_new_inode(inode); |
@@ -433,8 +429,7 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | |||
433 | return inode; | 429 | return inode; |
434 | 430 | ||
435 | out_ino: | 431 | out_ino: |
436 | if (de != NULL) | 432 | module_put(de->owner); |
437 | module_put(de->owner); | ||
438 | out_mod: | 433 | out_mod: |
439 | return NULL; | 434 | return NULL; |
440 | } | 435 | } |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index bc72f5c8c47d..28cbca805905 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/proc_fs.h> | 12 | #include <linux/proc_fs.h> |
13 | 13 | ||
14 | extern struct proc_dir_entry proc_root; | ||
14 | #ifdef CONFIG_PROC_SYSCTL | 15 | #ifdef CONFIG_PROC_SYSCTL |
15 | extern int proc_sys_init(void); | 16 | extern int proc_sys_init(void); |
16 | #else | 17 | #else |
@@ -46,9 +47,6 @@ extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *); | |||
46 | 47 | ||
47 | extern int maps_protect; | 48 | extern int maps_protect; |
48 | 49 | ||
49 | extern void create_seq_entry(char *name, mode_t mode, | ||
50 | const struct file_operations *f); | ||
51 | extern int proc_exe_link(struct inode *, struct path *); | ||
52 | extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns, | 50 | extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns, |
53 | struct pid *pid, struct task_struct *task); | 51 | struct pid *pid, struct task_struct *task); |
54 | extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns, | 52 | extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns, |
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index 941e95114b5a..79ecd281d2cb 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c | |||
@@ -137,7 +137,7 @@ static const struct file_operations proc_nommu_vma_list_operations = { | |||
137 | 137 | ||
138 | static int __init proc_nommu_init(void) | 138 | static int __init proc_nommu_init(void) |
139 | { | 139 | { |
140 | create_seq_entry("maps", S_IRUGO, &proc_nommu_vma_list_operations); | 140 | proc_create("maps", S_IRUGO, NULL, &proc_nommu_vma_list_operations); |
141 | return 0; | 141 | return 0; |
142 | } | 142 | } |
143 | 143 | ||
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 441a32f0e5f2..74a323d2b850 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c | |||
@@ -179,6 +179,7 @@ static int meminfo_read_proc(char *page, char **start, off_t off, | |||
179 | "PageTables: %8lu kB\n" | 179 | "PageTables: %8lu kB\n" |
180 | "NFS_Unstable: %8lu kB\n" | 180 | "NFS_Unstable: %8lu kB\n" |
181 | "Bounce: %8lu kB\n" | 181 | "Bounce: %8lu kB\n" |
182 | "WritebackTmp: %8lu kB\n" | ||
182 | "CommitLimit: %8lu kB\n" | 183 | "CommitLimit: %8lu kB\n" |
183 | "Committed_AS: %8lu kB\n" | 184 | "Committed_AS: %8lu kB\n" |
184 | "VmallocTotal: %8lu kB\n" | 185 | "VmallocTotal: %8lu kB\n" |
@@ -210,6 +211,7 @@ static int meminfo_read_proc(char *page, char **start, off_t off, | |||
210 | K(global_page_state(NR_PAGETABLE)), | 211 | K(global_page_state(NR_PAGETABLE)), |
211 | K(global_page_state(NR_UNSTABLE_NFS)), | 212 | K(global_page_state(NR_UNSTABLE_NFS)), |
212 | K(global_page_state(NR_BOUNCE)), | 213 | K(global_page_state(NR_BOUNCE)), |
214 | K(global_page_state(NR_WRITEBACK_TEMP)), | ||
213 | K(allowed), | 215 | K(allowed), |
214 | K(committed), | 216 | K(committed), |
215 | (unsigned long)VMALLOC_TOTAL >> 10, | 217 | (unsigned long)VMALLOC_TOTAL >> 10, |
@@ -826,14 +828,6 @@ static struct file_operations proc_kpageflags_operations = { | |||
826 | 828 | ||
827 | struct proc_dir_entry *proc_root_kcore; | 829 | struct proc_dir_entry *proc_root_kcore; |
828 | 830 | ||
829 | void create_seq_entry(char *name, mode_t mode, const struct file_operations *f) | ||
830 | { | ||
831 | struct proc_dir_entry *entry; | ||
832 | entry = create_proc_entry(name, mode, NULL); | ||
833 | if (entry) | ||
834 | entry->proc_fops = f; | ||
835 | } | ||
836 | |||
837 | void __init proc_misc_init(void) | 831 | void __init proc_misc_init(void) |
838 | { | 832 | { |
839 | static struct { | 833 | static struct { |
@@ -862,66 +856,52 @@ void __init proc_misc_init(void) | |||
862 | 856 | ||
863 | /* And now for trickier ones */ | 857 | /* And now for trickier ones */ |
864 | #ifdef CONFIG_PRINTK | 858 | #ifdef CONFIG_PRINTK |
865 | { | 859 | proc_create("kmsg", S_IRUSR, NULL, &proc_kmsg_operations); |
866 | struct proc_dir_entry *entry; | ||
867 | entry = create_proc_entry("kmsg", S_IRUSR, &proc_root); | ||
868 | if (entry) | ||
869 | entry->proc_fops = &proc_kmsg_operations; | ||
870 | } | ||
871 | #endif | 860 | #endif |
872 | create_seq_entry("locks", 0, &proc_locks_operations); | 861 | proc_create("locks", 0, NULL, &proc_locks_operations); |
873 | create_seq_entry("devices", 0, &proc_devinfo_operations); | 862 | proc_create("devices", 0, NULL, &proc_devinfo_operations); |
874 | create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); | 863 | proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations); |
875 | #ifdef CONFIG_BLOCK | 864 | #ifdef CONFIG_BLOCK |
876 | create_seq_entry("partitions", 0, &proc_partitions_operations); | 865 | proc_create("partitions", 0, NULL, &proc_partitions_operations); |
877 | #endif | 866 | #endif |
878 | create_seq_entry("stat", 0, &proc_stat_operations); | 867 | proc_create("stat", 0, NULL, &proc_stat_operations); |
879 | create_seq_entry("interrupts", 0, &proc_interrupts_operations); | 868 | proc_create("interrupts", 0, NULL, &proc_interrupts_operations); |
880 | #ifdef CONFIG_SLABINFO | 869 | #ifdef CONFIG_SLABINFO |
881 | create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations); | 870 | proc_create("slabinfo",S_IWUSR|S_IRUGO,NULL,&proc_slabinfo_operations); |
882 | #ifdef CONFIG_DEBUG_SLAB_LEAK | 871 | #ifdef CONFIG_DEBUG_SLAB_LEAK |
883 | create_seq_entry("slab_allocators", 0 ,&proc_slabstats_operations); | 872 | proc_create("slab_allocators", 0, NULL, &proc_slabstats_operations); |
884 | #endif | 873 | #endif |
885 | #endif | 874 | #endif |
886 | #ifdef CONFIG_MMU | 875 | #ifdef CONFIG_MMU |
887 | proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations); | 876 | proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations); |
888 | #endif | 877 | #endif |
889 | create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations); | 878 | proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations); |
890 | create_seq_entry("pagetypeinfo", S_IRUGO, &pagetypeinfo_file_ops); | 879 | proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops); |
891 | create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations); | 880 | proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations); |
892 | create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations); | 881 | proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations); |
893 | #ifdef CONFIG_BLOCK | 882 | #ifdef CONFIG_BLOCK |
894 | create_seq_entry("diskstats", 0, &proc_diskstats_operations); | 883 | proc_create("diskstats", 0, NULL, &proc_diskstats_operations); |
895 | #endif | 884 | #endif |
896 | #ifdef CONFIG_MODULES | 885 | #ifdef CONFIG_MODULES |
897 | create_seq_entry("modules", 0, &proc_modules_operations); | 886 | proc_create("modules", 0, NULL, &proc_modules_operations); |
898 | #endif | 887 | #endif |
899 | #ifdef CONFIG_SCHEDSTATS | 888 | #ifdef CONFIG_SCHEDSTATS |
900 | create_seq_entry("schedstat", 0, &proc_schedstat_operations); | 889 | proc_create("schedstat", 0, NULL, &proc_schedstat_operations); |
901 | #endif | 890 | #endif |
902 | #ifdef CONFIG_PROC_KCORE | 891 | #ifdef CONFIG_PROC_KCORE |
903 | proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL); | 892 | proc_root_kcore = proc_create("kcore", S_IRUSR, NULL, &proc_kcore_operations); |
904 | if (proc_root_kcore) { | 893 | if (proc_root_kcore) |
905 | proc_root_kcore->proc_fops = &proc_kcore_operations; | ||
906 | proc_root_kcore->size = | 894 | proc_root_kcore->size = |
907 | (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE; | 895 | (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE; |
908 | } | ||
909 | #endif | 896 | #endif |
910 | #ifdef CONFIG_PROC_PAGE_MONITOR | 897 | #ifdef CONFIG_PROC_PAGE_MONITOR |
911 | create_seq_entry("kpagecount", S_IRUSR, &proc_kpagecount_operations); | 898 | proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations); |
912 | create_seq_entry("kpageflags", S_IRUSR, &proc_kpageflags_operations); | 899 | proc_create("kpageflags", S_IRUSR, NULL, &proc_kpageflags_operations); |
913 | #endif | 900 | #endif |
914 | #ifdef CONFIG_PROC_VMCORE | 901 | #ifdef CONFIG_PROC_VMCORE |
915 | proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL); | 902 | proc_vmcore = proc_create("vmcore", S_IRUSR, NULL, &proc_vmcore_operations); |
916 | if (proc_vmcore) | ||
917 | proc_vmcore->proc_fops = &proc_vmcore_operations; | ||
918 | #endif | 903 | #endif |
919 | #ifdef CONFIG_MAGIC_SYSRQ | 904 | #ifdef CONFIG_MAGIC_SYSRQ |
920 | { | 905 | proc_create("sysrq-trigger", S_IWUSR, NULL, &proc_sysrq_trigger_operations); |
921 | struct proc_dir_entry *entry; | ||
922 | entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL); | ||
923 | if (entry) | ||
924 | entry->proc_fops = &proc_sysrq_trigger_operations; | ||
925 | } | ||
926 | #endif | 906 | #endif |
927 | } | 907 | } |
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 13cd7835d0df..83f357b30d71 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c | |||
@@ -159,17 +159,6 @@ struct net *get_proc_net(const struct inode *inode) | |||
159 | } | 159 | } |
160 | EXPORT_SYMBOL_GPL(get_proc_net); | 160 | EXPORT_SYMBOL_GPL(get_proc_net); |
161 | 161 | ||
162 | struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name, | ||
163 | struct proc_dir_entry *parent) | ||
164 | { | ||
165 | struct proc_dir_entry *pde; | ||
166 | pde = proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent); | ||
167 | if (pde != NULL) | ||
168 | pde->data = net; | ||
169 | return pde; | ||
170 | } | ||
171 | EXPORT_SYMBOL_GPL(proc_net_mkdir); | ||
172 | |||
173 | static __net_init int proc_net_ns_init(struct net *net) | 162 | static __net_init int proc_net_ns_init(struct net *net) |
174 | { | 163 | { |
175 | struct proc_dir_entry *netd, *net_statd; | 164 | struct proc_dir_entry *netd, *net_statd; |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 614c34b6d1c2..5acc001d49f6 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -165,8 +165,8 @@ out: | |||
165 | return err; | 165 | return err; |
166 | } | 166 | } |
167 | 167 | ||
168 | static ssize_t proc_sys_read(struct file *filp, char __user *buf, | 168 | static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf, |
169 | size_t count, loff_t *ppos) | 169 | size_t count, loff_t *ppos, int write) |
170 | { | 170 | { |
171 | struct dentry *dentry = filp->f_dentry; | 171 | struct dentry *dentry = filp->f_dentry; |
172 | struct ctl_table_header *head; | 172 | struct ctl_table_header *head; |
@@ -190,12 +190,12 @@ static ssize_t proc_sys_read(struct file *filp, char __user *buf, | |||
190 | * and won't be until we finish. | 190 | * and won't be until we finish. |
191 | */ | 191 | */ |
192 | error = -EPERM; | 192 | error = -EPERM; |
193 | if (sysctl_perm(table, MAY_READ)) | 193 | if (sysctl_perm(head->root, table, write ? MAY_WRITE : MAY_READ)) |
194 | goto out; | 194 | goto out; |
195 | 195 | ||
196 | /* careful: calling conventions are nasty here */ | 196 | /* careful: calling conventions are nasty here */ |
197 | res = count; | 197 | res = count; |
198 | error = table->proc_handler(table, 0, filp, buf, &res, ppos); | 198 | error = table->proc_handler(table, write, filp, buf, &res, ppos); |
199 | if (!error) | 199 | if (!error) |
200 | error = res; | 200 | error = res; |
201 | out: | 201 | out: |
@@ -204,44 +204,16 @@ out: | |||
204 | return error; | 204 | return error; |
205 | } | 205 | } |
206 | 206 | ||
207 | static ssize_t proc_sys_write(struct file *filp, const char __user *buf, | 207 | static ssize_t proc_sys_read(struct file *filp, char __user *buf, |
208 | size_t count, loff_t *ppos) | 208 | size_t count, loff_t *ppos) |
209 | { | 209 | { |
210 | struct dentry *dentry = filp->f_dentry; | 210 | return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 0); |
211 | struct ctl_table_header *head; | 211 | } |
212 | struct ctl_table *table; | ||
213 | ssize_t error; | ||
214 | size_t res; | ||
215 | |||
216 | table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head); | ||
217 | /* Has the sysctl entry disappeared on us? */ | ||
218 | error = -ENOENT; | ||
219 | if (!table) | ||
220 | goto out; | ||
221 | |||
222 | /* Has the sysctl entry been replaced by a directory? */ | ||
223 | error = -EISDIR; | ||
224 | if (!table->proc_handler) | ||
225 | goto out; | ||
226 | |||
227 | /* | ||
228 | * At this point we know that the sysctl was not unregistered | ||
229 | * and won't be until we finish. | ||
230 | */ | ||
231 | error = -EPERM; | ||
232 | if (sysctl_perm(table, MAY_WRITE)) | ||
233 | goto out; | ||
234 | |||
235 | /* careful: calling conventions are nasty here */ | ||
236 | res = count; | ||
237 | error = table->proc_handler(table, 1, filp, (char __user *)buf, | ||
238 | &res, ppos); | ||
239 | if (!error) | ||
240 | error = res; | ||
241 | out: | ||
242 | sysctl_head_finish(head); | ||
243 | 212 | ||
244 | return error; | 213 | static ssize_t proc_sys_write(struct file *filp, const char __user *buf, |
214 | size_t count, loff_t *ppos) | ||
215 | { | ||
216 | return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1); | ||
245 | } | 217 | } |
246 | 218 | ||
247 | 219 | ||
@@ -416,7 +388,7 @@ static int proc_sys_permission(struct inode *inode, int mask, struct nameidata * | |||
416 | goto out; | 388 | goto out; |
417 | 389 | ||
418 | /* Use the permissions on the sysctl table entry */ | 390 | /* Use the permissions on the sysctl table entry */ |
419 | error = sysctl_perm(table, mask); | 391 | error = sysctl_perm(head->root, table, mask); |
420 | out: | 392 | out: |
421 | sysctl_head_finish(head); | 393 | sysctl_head_finish(head); |
422 | return error; | 394 | return error; |
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index 49816e00b51a..21f490f5d65c 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c | |||
@@ -5,7 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <asm/uaccess.h> | 7 | #include <asm/uaccess.h> |
8 | 8 | #include <linux/module.h> | |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
11 | #include <linux/time.h> | 11 | #include <linux/time.h> |
@@ -136,39 +136,54 @@ static const struct file_operations proc_tty_drivers_operations = { | |||
136 | .release = seq_release, | 136 | .release = seq_release, |
137 | }; | 137 | }; |
138 | 138 | ||
139 | /* | 139 | static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) |
140 | * This is the handler for /proc/tty/ldiscs | ||
141 | */ | ||
142 | static int tty_ldiscs_read_proc(char *page, char **start, off_t off, | ||
143 | int count, int *eof, void *data) | ||
144 | { | 140 | { |
145 | int i; | 141 | return (*pos < NR_LDISCS) ? pos : NULL; |
146 | int len = 0; | 142 | } |
147 | off_t begin = 0; | 143 | |
144 | static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos) | ||
145 | { | ||
146 | (*pos)++; | ||
147 | return (*pos < NR_LDISCS) ? pos : NULL; | ||
148 | } | ||
149 | |||
150 | static void tty_ldiscs_seq_stop(struct seq_file *m, void *v) | ||
151 | { | ||
152 | } | ||
153 | |||
154 | static int tty_ldiscs_seq_show(struct seq_file *m, void *v) | ||
155 | { | ||
156 | int i = *(loff_t *)v; | ||
148 | struct tty_ldisc *ld; | 157 | struct tty_ldisc *ld; |
149 | 158 | ||
150 | for (i=0; i < NR_LDISCS; i++) { | 159 | ld = tty_ldisc_get(i); |
151 | ld = tty_ldisc_get(i); | 160 | if (ld == NULL) |
152 | if (ld == NULL) | ||
153 | continue; | ||
154 | len += sprintf(page+len, "%-10s %2d\n", | ||
155 | ld->name ? ld->name : "???", i); | ||
156 | tty_ldisc_put(i); | ||
157 | if (len+begin > off+count) | ||
158 | break; | ||
159 | if (len+begin < off) { | ||
160 | begin += len; | ||
161 | len = 0; | ||
162 | } | ||
163 | } | ||
164 | if (i >= NR_LDISCS) | ||
165 | *eof = 1; | ||
166 | if (off >= len+begin) | ||
167 | return 0; | 161 | return 0; |
168 | *start = page + (off-begin); | 162 | seq_printf(m, "%-10s %2d\n", ld->name ? ld->name : "???", i); |
169 | return ((count < begin+len-off) ? count : begin+len-off); | 163 | tty_ldisc_put(i); |
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static const struct seq_operations tty_ldiscs_seq_ops = { | ||
168 | .start = tty_ldiscs_seq_start, | ||
169 | .next = tty_ldiscs_seq_next, | ||
170 | .stop = tty_ldiscs_seq_stop, | ||
171 | .show = tty_ldiscs_seq_show, | ||
172 | }; | ||
173 | |||
174 | static int proc_tty_ldiscs_open(struct inode *inode, struct file *file) | ||
175 | { | ||
176 | return seq_open(file, &tty_ldiscs_seq_ops); | ||
170 | } | 177 | } |
171 | 178 | ||
179 | static const struct file_operations tty_ldiscs_proc_fops = { | ||
180 | .owner = THIS_MODULE, | ||
181 | .open = proc_tty_ldiscs_open, | ||
182 | .read = seq_read, | ||
183 | .llseek = seq_lseek, | ||
184 | .release = seq_release, | ||
185 | }; | ||
186 | |||
172 | /* | 187 | /* |
173 | * This function is called by tty_register_driver() to handle | 188 | * This function is called by tty_register_driver() to handle |
174 | * registering the driver's /proc handler into /proc/tty/driver/<foo> | 189 | * registering the driver's /proc handler into /proc/tty/driver/<foo> |
@@ -177,16 +192,14 @@ void proc_tty_register_driver(struct tty_driver *driver) | |||
177 | { | 192 | { |
178 | struct proc_dir_entry *ent; | 193 | struct proc_dir_entry *ent; |
179 | 194 | ||
180 | if ((!driver->read_proc && !driver->write_proc) || | 195 | if (!driver->ops->read_proc || !driver->driver_name || |
181 | !driver->driver_name || | ||
182 | driver->proc_entry) | 196 | driver->proc_entry) |
183 | return; | 197 | return; |
184 | 198 | ||
185 | ent = create_proc_entry(driver->driver_name, 0, proc_tty_driver); | 199 | ent = create_proc_entry(driver->driver_name, 0, proc_tty_driver); |
186 | if (!ent) | 200 | if (!ent) |
187 | return; | 201 | return; |
188 | ent->read_proc = driver->read_proc; | 202 | ent->read_proc = driver->ops->read_proc; |
189 | ent->write_proc = driver->write_proc; | ||
190 | ent->owner = driver->owner; | 203 | ent->owner = driver->owner; |
191 | ent->data = driver; | 204 | ent->data = driver; |
192 | 205 | ||
@@ -214,7 +227,6 @@ void proc_tty_unregister_driver(struct tty_driver *driver) | |||
214 | */ | 227 | */ |
215 | void __init proc_tty_init(void) | 228 | void __init proc_tty_init(void) |
216 | { | 229 | { |
217 | struct proc_dir_entry *entry; | ||
218 | if (!proc_mkdir("tty", NULL)) | 230 | if (!proc_mkdir("tty", NULL)) |
219 | return; | 231 | return; |
220 | proc_tty_ldisc = proc_mkdir("tty/ldisc", NULL); | 232 | proc_tty_ldisc = proc_mkdir("tty/ldisc", NULL); |
@@ -224,10 +236,7 @@ void __init proc_tty_init(void) | |||
224 | * password lengths and inter-keystroke timings during password | 236 | * password lengths and inter-keystroke timings during password |
225 | * entry. | 237 | * entry. |
226 | */ | 238 | */ |
227 | proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR | S_IXUSR, NULL); | 239 | proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL); |
228 | 240 | proc_create("tty/ldiscs", 0, NULL, &tty_ldiscs_proc_fops); | |
229 | create_proc_read_entry("tty/ldiscs", 0, NULL, tty_ldiscs_read_proc, NULL); | 241 | proc_create("tty/drivers", 0, NULL, &proc_tty_drivers_operations); |
230 | entry = create_proc_entry("tty/drivers", 0, NULL); | ||
231 | if (entry) | ||
232 | entry->proc_fops = &proc_tty_drivers_operations; | ||
233 | } | 242 | } |
diff --git a/fs/proc/root.c b/fs/proc/root.c index ef0fb57fc9ef..95117538a4f6 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
@@ -22,8 +22,6 @@ | |||
22 | 22 | ||
23 | #include "internal.h" | 23 | #include "internal.h" |
24 | 24 | ||
25 | struct proc_dir_entry *proc_bus, *proc_root_fs, *proc_root_driver; | ||
26 | |||
27 | static int proc_test_super(struct super_block *sb, void *data) | 25 | static int proc_test_super(struct super_block *sb, void *data) |
28 | { | 26 | { |
29 | return sb->s_fs_info == data; | 27 | return sb->s_fs_info == data; |
@@ -126,8 +124,8 @@ void __init proc_root_init(void) | |||
126 | #ifdef CONFIG_SYSVIPC | 124 | #ifdef CONFIG_SYSVIPC |
127 | proc_mkdir("sysvipc", NULL); | 125 | proc_mkdir("sysvipc", NULL); |
128 | #endif | 126 | #endif |
129 | proc_root_fs = proc_mkdir("fs", NULL); | 127 | proc_mkdir("fs", NULL); |
130 | proc_root_driver = proc_mkdir("driver", NULL); | 128 | proc_mkdir("driver", NULL); |
131 | proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */ | 129 | proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */ |
132 | #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) | 130 | #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) |
133 | /* just give it a mountpoint */ | 131 | /* just give it a mountpoint */ |
@@ -137,7 +135,7 @@ void __init proc_root_init(void) | |||
137 | #ifdef CONFIG_PROC_DEVICETREE | 135 | #ifdef CONFIG_PROC_DEVICETREE |
138 | proc_device_tree_init(); | 136 | proc_device_tree_init(); |
139 | #endif | 137 | #endif |
140 | proc_bus = proc_mkdir("bus", NULL); | 138 | proc_mkdir("bus", NULL); |
141 | proc_sys_init(); | 139 | proc_sys_init(); |
142 | } | 140 | } |
143 | 141 | ||
@@ -232,9 +230,5 @@ void pid_ns_release_proc(struct pid_namespace *ns) | |||
232 | EXPORT_SYMBOL(proc_symlink); | 230 | EXPORT_SYMBOL(proc_symlink); |
233 | EXPORT_SYMBOL(proc_mkdir); | 231 | EXPORT_SYMBOL(proc_mkdir); |
234 | EXPORT_SYMBOL(create_proc_entry); | 232 | EXPORT_SYMBOL(create_proc_entry); |
235 | EXPORT_SYMBOL(proc_create); | 233 | EXPORT_SYMBOL(proc_create_data); |
236 | EXPORT_SYMBOL(remove_proc_entry); | 234 | EXPORT_SYMBOL(remove_proc_entry); |
237 | EXPORT_SYMBOL(proc_root); | ||
238 | EXPORT_SYMBOL(proc_root_fs); | ||
239 | EXPORT_SYMBOL(proc_bus); | ||
240 | EXPORT_SYMBOL(proc_root_driver); | ||
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 7415eeb7cc3a..88717c0f941b 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -5,11 +5,9 @@ | |||
5 | #include <linux/highmem.h> | 5 | #include <linux/highmem.h> |
6 | #include <linux/ptrace.h> | 6 | #include <linux/ptrace.h> |
7 | #include <linux/pagemap.h> | 7 | #include <linux/pagemap.h> |
8 | #include <linux/ptrace.h> | ||
9 | #include <linux/mempolicy.h> | 8 | #include <linux/mempolicy.h> |
10 | #include <linux/swap.h> | 9 | #include <linux/swap.h> |
11 | #include <linux/swapops.h> | 10 | #include <linux/swapops.h> |
12 | #include <linux/seq_file.h> | ||
13 | 11 | ||
14 | #include <asm/elf.h> | 12 | #include <asm/elf.h> |
15 | #include <asm/uaccess.h> | 13 | #include <asm/uaccess.h> |
@@ -75,40 +73,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text, | |||
75 | return mm->total_vm; | 73 | return mm->total_vm; |
76 | } | 74 | } |
77 | 75 | ||
78 | int proc_exe_link(struct inode *inode, struct path *path) | ||
79 | { | ||
80 | struct vm_area_struct * vma; | ||
81 | int result = -ENOENT; | ||
82 | struct task_struct *task = get_proc_task(inode); | ||
83 | struct mm_struct * mm = NULL; | ||
84 | |||
85 | if (task) { | ||
86 | mm = get_task_mm(task); | ||
87 | put_task_struct(task); | ||
88 | } | ||
89 | if (!mm) | ||
90 | goto out; | ||
91 | down_read(&mm->mmap_sem); | ||
92 | |||
93 | vma = mm->mmap; | ||
94 | while (vma) { | ||
95 | if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) | ||
96 | break; | ||
97 | vma = vma->vm_next; | ||
98 | } | ||
99 | |||
100 | if (vma) { | ||
101 | *path = vma->vm_file->f_path; | ||
102 | path_get(&vma->vm_file->f_path); | ||
103 | result = 0; | ||
104 | } | ||
105 | |||
106 | up_read(&mm->mmap_sem); | ||
107 | mmput(mm); | ||
108 | out: | ||
109 | return result; | ||
110 | } | ||
111 | |||
112 | static void pad_len_spaces(struct seq_file *m, int len) | 76 | static void pad_len_spaces(struct seq_file *m, int len) |
113 | { | 77 | { |
114 | len = 25 + sizeof(void*) * 6 - len; | 78 | len = 25 + sizeof(void*) * 6 - len; |
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 8011528518bd..4b4f9cc2f186 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c | |||
@@ -1,6 +1,7 @@ | |||
1 | 1 | ||
2 | #include <linux/mm.h> | 2 | #include <linux/mm.h> |
3 | #include <linux/file.h> | 3 | #include <linux/file.h> |
4 | #include <linux/fdtable.h> | ||
4 | #include <linux/mount.h> | 5 | #include <linux/mount.h> |
5 | #include <linux/ptrace.h> | 6 | #include <linux/ptrace.h> |
6 | #include <linux/seq_file.h> | 7 | #include <linux/seq_file.h> |
@@ -103,40 +104,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text, | |||
103 | return size; | 104 | return size; |
104 | } | 105 | } |
105 | 106 | ||
106 | int proc_exe_link(struct inode *inode, struct path *path) | ||
107 | { | ||
108 | struct vm_list_struct *vml; | ||
109 | struct vm_area_struct *vma; | ||
110 | struct task_struct *task = get_proc_task(inode); | ||
111 | struct mm_struct *mm = get_task_mm(task); | ||
112 | int result = -ENOENT; | ||
113 | |||
114 | if (!mm) | ||
115 | goto out; | ||
116 | down_read(&mm->mmap_sem); | ||
117 | |||
118 | vml = mm->context.vmlist; | ||
119 | vma = NULL; | ||
120 | while (vml) { | ||
121 | if ((vml->vma->vm_flags & VM_EXECUTABLE) && vml->vma->vm_file) { | ||
122 | vma = vml->vma; | ||
123 | break; | ||
124 | } | ||
125 | vml = vml->next; | ||
126 | } | ||
127 | |||
128 | if (vma) { | ||
129 | *path = vma->vm_file->f_path; | ||
130 | path_get(&vma->vm_file->f_path); | ||
131 | result = 0; | ||
132 | } | ||
133 | |||
134 | up_read(&mm->mmap_sem); | ||
135 | mmput(mm); | ||
136 | out: | ||
137 | return result; | ||
138 | } | ||
139 | |||
140 | /* | 107 | /* |
141 | * display mapping lines for a particular process's /proc/pid/maps | 108 | * display mapping lines for a particular process's /proc/pid/maps |
142 | */ | 109 | */ |