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>
This commit is contained in:
Alexey Dobriyan 2008-04-29 01:01:39 -07:00 коммит произвёл Linus Torvalds
Родитель 638fa202cd
Коммит f649d6d326
1 изменённых файлов: 43 добавлений и 45 удалений

Просмотреть файл

@ -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);
wait_for_completion(de->pde_unload_completion);
spin_lock(&proc_subdir_lock);
goto continue_removing;
if (proc_match(len, fn, *p)) {
de = *p;
*p = de->next;
de->next = NULL;
break;
}
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;
}
spin_unlock(&proc_subdir_lock);
out:
return;
if (!de)
return;
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);
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);
}