diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2008-04-29 04:01:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:06:17 -0400 |
commit | f649d6d32605c7573884613289fb3b9fbd4f99a1 (patch) | |
tree | 3fe52e6e5e93edc2f011d8047a8e3ac2eee71930 /fs/proc/generic.c | |
parent | 638fa202cdb207083a12d6f73e313605a8fc1037 (diff) |
proc: simplify locking in remove_proc_entry()
proc_subdir_lock protects only modifying and walking through PDE lists, so
after we've found PDE to remove and actually removed it from lists, there is
no need to hold proc_subdir_lock for the rest of operation.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc/generic.c')
-rw-r--r-- | fs/proc/generic.c | 82 |
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) | |||
734 | void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | 734 | void 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 | |||
776 | continue_removing: | 779 | continue_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)) |
791 | out: | 790 | free_proc_entry(de); |
792 | return; | ||
793 | } | 791 | } |