diff options
Diffstat (limited to 'fs/proc/generic.c')
-rw-r--r-- | fs/proc/generic.c | 149 |
1 files changed, 82 insertions, 67 deletions
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 | } |