aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc')
-rw-r--r--fs/proc/generic.c82
1 files changed, 40 insertions, 42 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index f501f3211abc..45d0076bc08e 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -734,60 +734,58 @@ void free_proc_entry(struct proc_dir_entry *de)
734void remove_proc_entry(const char *name, struct proc_dir_entry *parent) 734void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
735{ 735{
736 struct proc_dir_entry **p; 736 struct proc_dir_entry **p;
737 struct proc_dir_entry *de; 737 struct proc_dir_entry *de = NULL;
738 const char *fn = name; 738 const char *fn = name;
739 int len; 739 int len;
740 740
741 if (!parent && xlate_proc_name(name, &parent, &fn) != 0) 741 if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
742 goto out; 742 return;
743 len = strlen(fn); 743 len = strlen(fn);
744 744
745 spin_lock(&proc_subdir_lock); 745 spin_lock(&proc_subdir_lock);
746 for (p = &parent->subdir; *p; p=&(*p)->next ) { 746 for (p = &parent->subdir; *p; p=&(*p)->next ) {
747 if (!proc_match(len, fn, *p)) 747 if (proc_match(len, fn, *p)) {
748 continue; 748 de = *p;
749 de = *p; 749 *p = de->next;
750 *p = de->next; 750 de->next = NULL;
751 de->next = NULL; 751 break;
752 752 }
753 spin_lock(&de->pde_unload_lock); 753 }
754 /* 754 spin_unlock(&proc_subdir_lock);
755 * Stop accepting new callers into module. If you're 755 if (!de)
756 * dynamically allocating ->proc_fops, save a pointer somewhere. 756 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 757
769 wait_for_completion(de->pde_unload_completion); 758 spin_lock(&de->pde_unload_lock);
759 /*
760 * Stop accepting new callers into module. If you're
761 * dynamically allocating ->proc_fops, save a pointer somewhere.
762 */
763 de->proc_fops = NULL;
764 /* Wait until all existing callers into module are done. */
765 if (de->pde_users > 0) {
766 DECLARE_COMPLETION_ONSTACK(c);
767
768 if (!de->pde_unload_completion)
769 de->pde_unload_completion = &c;
770 770
771 spin_lock(&proc_subdir_lock);
772 goto continue_removing;
773 }
774 spin_unlock(&de->pde_unload_lock); 771 spin_unlock(&de->pde_unload_lock);
775 772
773 wait_for_completion(de->pde_unload_completion);
774
775 goto continue_removing;
776 }
777 spin_unlock(&de->pde_unload_lock);
778
776continue_removing: 779continue_removing:
777 if (S_ISDIR(de->mode)) 780 if (S_ISDIR(de->mode))
778 parent->nlink--; 781 parent->nlink--;
779 de->nlink = 0; 782 de->nlink = 0;
780 if (de->subdir) { 783 if (de->subdir) {
781 printk(KERN_WARNING "%s: removing non-empty directory " 784 printk(KERN_WARNING "%s: removing non-empty directory "
782 "'%s/%s', leaking at least '%s'\n", __func__, 785 "'%s/%s', leaking at least '%s'\n", __func__,
783 de->parent->name, de->name, de->subdir->name); 786 de->parent->name, de->name, de->subdir->name);
784 WARN_ON(1); 787 WARN_ON(1);
785 }
786 if (atomic_dec_and_test(&de->count))
787 free_proc_entry(de);
788 break;
789 } 788 }
790 spin_unlock(&proc_subdir_lock); 789 if (atomic_dec_and_test(&de->count))
791out: 790 free_proc_entry(de);
792 return;
793} 791}