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:
parent
638fa202cd
commit
f649d6d326
@ -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)
|
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
|
||||||
{
|
{
|
||||||
struct proc_dir_entry **p;
|
struct proc_dir_entry **p;
|
||||||
struct proc_dir_entry *de;
|
struct proc_dir_entry *de = NULL;
|
||||||
const char *fn = name;
|
const char *fn = name;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
|
if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
|
||||||
goto out;
|
return;
|
||||||
len = strlen(fn);
|
len = strlen(fn);
|
||||||
|
|
||||||
spin_lock(&proc_subdir_lock);
|
spin_lock(&proc_subdir_lock);
|
||||||
for (p = &parent->subdir; *p; p=&(*p)->next ) {
|
for (p = &parent->subdir; *p; p=&(*p)->next ) {
|
||||||
if (!proc_match(len, fn, *p))
|
if (proc_match(len, fn, *p)) {
|
||||||
continue;
|
de = *p;
|
||||||
de = *p;
|
*p = de->next;
|
||||||
*p = de->next;
|
de->next = NULL;
|
||||||
de->next = NULL;
|
break;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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);
|
spin_unlock(&proc_subdir_lock);
|
||||||
out:
|
if (!de)
|
||||||
return;
|
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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user