diff options
Diffstat (limited to 'fs/proc/generic.c')
-rw-r--r-- | fs/proc/generic.c | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 8a40e15f5ecb..4f8e53568b22 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/namei.h> | 20 | #include <linux/namei.h> |
21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
22 | #include <linux/spinlock.h> | 22 | #include <linux/spinlock.h> |
23 | #include <linux/completion.h> | ||
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | 25 | ||
25 | #include "internal.h" | 26 | #include "internal.h" |
@@ -613,6 +614,9 @@ static struct proc_dir_entry *proc_create(struct proc_dir_entry **parent, | |||
613 | ent->namelen = len; | 614 | ent->namelen = len; |
614 | ent->mode = mode; | 615 | ent->mode = mode; |
615 | ent->nlink = nlink; | 616 | ent->nlink = nlink; |
617 | ent->pde_users = 0; | ||
618 | spin_lock_init(&ent->pde_unload_lock); | ||
619 | ent->pde_unload_completion = NULL; | ||
616 | out: | 620 | out: |
617 | return ent; | 621 | return ent; |
618 | } | 622 | } |
@@ -734,9 +738,35 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
734 | de = *p; | 738 | de = *p; |
735 | *p = de->next; | 739 | *p = de->next; |
736 | de->next = NULL; | 740 | de->next = NULL; |
741 | |||
742 | spin_lock(&de->pde_unload_lock); | ||
743 | /* | ||
744 | * Stop accepting new callers into module. If you're | ||
745 | * dynamically allocating ->proc_fops, save a pointer somewhere. | ||
746 | */ | ||
747 | de->proc_fops = NULL; | ||
748 | /* Wait until all existing callers into module are done. */ | ||
749 | if (de->pde_users > 0) { | ||
750 | DECLARE_COMPLETION_ONSTACK(c); | ||
751 | |||
752 | if (!de->pde_unload_completion) | ||
753 | de->pde_unload_completion = &c; | ||
754 | |||
755 | spin_unlock(&de->pde_unload_lock); | ||
756 | spin_unlock(&proc_subdir_lock); | ||
757 | |||
758 | wait_for_completion(de->pde_unload_completion); | ||
759 | |||
760 | spin_lock(&proc_subdir_lock); | ||
761 | goto continue_removing; | ||
762 | } | ||
763 | spin_unlock(&de->pde_unload_lock); | ||
764 | |||
765 | continue_removing: | ||
737 | if (S_ISDIR(de->mode)) | 766 | if (S_ISDIR(de->mode)) |
738 | parent->nlink--; | 767 | parent->nlink--; |
739 | proc_kill_inodes(de); | 768 | if (!S_ISREG(de->mode)) |
769 | proc_kill_inodes(de); | ||
740 | de->nlink = 0; | 770 | de->nlink = 0; |
741 | WARN_ON(de->subdir); | 771 | WARN_ON(de->subdir); |
742 | if (!atomic_read(&de->count)) | 772 | if (!atomic_read(&de->count)) |