proc: simplify locking in remove_proc_entry()
authorAlexey Dobriyan <adobriyan@gmail.com>
Tue, 29 Apr 2008 08:01:39 +0000 (01:01 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 29 Apr 2008 15:06:17 +0000 (08:06 -0700)
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>
fs/proc/generic.c

index f501f3211abc5a87d64020c88c624a69447a4678..45d0076bc08e887ca3ff1d07879ef90d8d3de4cf 100644 (file)
@@ -734,60 +734,58 @@ void free_proc_entry(struct proc_dir_entry *de)
 void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
 {
        struct proc_dir_entry **p;
-       struct proc_dir_entry *de;
+       struct proc_dir_entry *de = NULL;
        const char *fn = name;
        int len;
 
        if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
-               goto out;
+               return;
        len = strlen(fn);
 
        spin_lock(&proc_subdir_lock);
        for (p = &parent->subdir; *p; p=&(*p)->next ) {
-               if (!proc_match(len, fn, *p))
-                       continue;
-               de = *p;
-               *p = de->next;
-               de->next = NULL;
-
-               spin_lock(&de->pde_unload_lock);
-               /*
-                * Stop accepting new callers into module. If you're
-                * dynamically allocating ->proc_fops, save a pointer somewhere.
-                */
-               de->proc_fops = NULL;
-               /* Wait until all existing callers into module are done. */
-               if (de->pde_users > 0) {
-                       DECLARE_COMPLETION_ONSTACK(c);
-
-                       if (!de->pde_unload_completion)
-                               de->pde_unload_completion = &c;
-
-                       spin_unlock(&de->pde_unload_lock);
-                       spin_unlock(&proc_subdir_lock);
+               if (proc_match(len, fn, *p)) {
+                       de = *p;
+                       *p = de->next;
+                       de->next = NULL;
+                       break;
+               }
+       }
+       spin_unlock(&proc_subdir_lock);
+       if (!de)
+               return;
 
-                       wait_for_completion(de->pde_unload_completion);
+       spin_lock(&de->pde_unload_lock);
+       /*
+        * Stop accepting new callers into module. If you're
+        * dynamically allocating ->proc_fops, save a pointer somewhere.
+        */
+       de->proc_fops = NULL;
+       /* Wait until all existing callers into module are done. */
+       if (de->pde_users > 0) {
+               DECLARE_COMPLETION_ONSTACK(c);
+
+               if (!de->pde_unload_completion)
+                       de->pde_unload_completion = &c;
 
-                       spin_lock(&proc_subdir_lock);
-                       goto continue_removing;
-               }
                spin_unlock(&de->pde_unload_lock);
 
+               wait_for_completion(de->pde_unload_completion);
+
+               goto continue_removing;
+       }
+       spin_unlock(&de->pde_unload_lock);
+
 continue_removing:
-               if (S_ISDIR(de->mode))
-                       parent->nlink--;
-               de->nlink = 0;
-               if (de->subdir) {
-                       printk(KERN_WARNING "%s: removing non-empty directory "
-                              "'%s/%s', leaking at least '%s'\n", __func__,
-                              de->parent->name, de->name, de->subdir->name);
-                       WARN_ON(1);
-               }
-               if (atomic_dec_and_test(&de->count))
-                       free_proc_entry(de);
-               break;
+       if (S_ISDIR(de->mode))
+               parent->nlink--;
+       de->nlink = 0;
+       if (de->subdir) {
+               printk(KERN_WARNING "%s: removing non-empty directory "
+                       "'%s/%s', leaking at least '%s'\n", __func__,
+                       de->parent->name, de->name, de->subdir->name);
+               WARN_ON(1);
        }
-       spin_unlock(&proc_subdir_lock);
-out:
-       return;
+       if (atomic_dec_and_test(&de->count))
+               free_proc_entry(de);
 }