|
@@ -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);
|
|
|
}
|