Commit e8f2b548de7ae65e17ee911e54712a3f26f69c60
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro: "A nasty bug in fs/namespace.c caught by Andrey + a couple of less serious unpleasantness - ecryptfs misc device playing hopeless games with try_module_get() and palinfo procfs support being... not quite correctly done, to be polite." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: mnt: release locks on error path in do_loopback palinfo fixes procfs: add proc_remove_subtree() ecryptfs: close rmmod race
Showing 5 changed files Side-by-side Diff
arch/ia64/kernel/palinfo.c
... | ... | @@ -849,17 +849,6 @@ |
849 | 849 | |
850 | 850 | #define NR_PALINFO_ENTRIES (int) ARRAY_SIZE(palinfo_entries) |
851 | 851 | |
852 | -/* | |
853 | - * this array is used to keep track of the proc entries we create. This is | |
854 | - * required in the module mode when we need to remove all entries. The procfs code | |
855 | - * does not do recursion of deletion | |
856 | - * | |
857 | - * Notes: | |
858 | - * - +1 accounts for the cpuN directory entry in /proc/pal | |
859 | - */ | |
860 | -#define NR_PALINFO_PROC_ENTRIES (NR_CPUS*(NR_PALINFO_ENTRIES+1)) | |
861 | - | |
862 | -static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES]; | |
863 | 852 | static struct proc_dir_entry *palinfo_dir; |
864 | 853 | |
865 | 854 | /* |
866 | 855 | |
867 | 856 | |
868 | 857 | |
869 | 858 | |
870 | 859 | |
871 | 860 | |
872 | 861 | |
... | ... | @@ -971,60 +960,32 @@ |
971 | 960 | static void __cpuinit |
972 | 961 | create_palinfo_proc_entries(unsigned int cpu) |
973 | 962 | { |
974 | -# define CPUSTR "cpu%d" | |
975 | - | |
976 | 963 | pal_func_cpu_u_t f; |
977 | - struct proc_dir_entry **pdir; | |
978 | 964 | struct proc_dir_entry *cpu_dir; |
979 | 965 | int j; |
980 | - char cpustr[sizeof(CPUSTR)]; | |
966 | + char cpustr[3+4+1]; /* cpu numbers are up to 4095 on itanic */ | |
967 | + sprintf(cpustr, "cpu%d", cpu); | |
981 | 968 | |
982 | - | |
983 | - /* | |
984 | - * we keep track of created entries in a depth-first order for | |
985 | - * cleanup purposes. Each entry is stored into palinfo_proc_entries | |
986 | - */ | |
987 | - sprintf(cpustr,CPUSTR, cpu); | |
988 | - | |
989 | 969 | cpu_dir = proc_mkdir(cpustr, palinfo_dir); |
970 | + if (!cpu_dir) | |
971 | + return; | |
990 | 972 | |
991 | 973 | f.req_cpu = cpu; |
992 | 974 | |
993 | - /* | |
994 | - * Compute the location to store per cpu entries | |
995 | - * We dont store the top level entry in this list, but | |
996 | - * remove it finally after removing all cpu entries. | |
997 | - */ | |
998 | - pdir = &palinfo_proc_entries[cpu*(NR_PALINFO_ENTRIES+1)]; | |
999 | - *pdir++ = cpu_dir; | |
1000 | 975 | for (j=0; j < NR_PALINFO_ENTRIES; j++) { |
1001 | 976 | f.func_id = j; |
1002 | - *pdir = create_proc_read_entry( | |
1003 | - palinfo_entries[j].name, 0, cpu_dir, | |
1004 | - palinfo_read_entry, (void *)f.value); | |
1005 | - pdir++; | |
977 | + create_proc_read_entry( | |
978 | + palinfo_entries[j].name, 0, cpu_dir, | |
979 | + palinfo_read_entry, (void *)f.value); | |
1006 | 980 | } |
1007 | 981 | } |
1008 | 982 | |
1009 | 983 | static void |
1010 | 984 | remove_palinfo_proc_entries(unsigned int hcpu) |
1011 | 985 | { |
1012 | - int j; | |
1013 | - struct proc_dir_entry *cpu_dir, **pdir; | |
1014 | - | |
1015 | - pdir = &palinfo_proc_entries[hcpu*(NR_PALINFO_ENTRIES+1)]; | |
1016 | - cpu_dir = *pdir; | |
1017 | - *pdir++=NULL; | |
1018 | - for (j=0; j < (NR_PALINFO_ENTRIES); j++) { | |
1019 | - if ((*pdir)) { | |
1020 | - remove_proc_entry ((*pdir)->name, cpu_dir); | |
1021 | - *pdir ++= NULL; | |
1022 | - } | |
1023 | - } | |
1024 | - | |
1025 | - if (cpu_dir) { | |
1026 | - remove_proc_entry(cpu_dir->name, palinfo_dir); | |
1027 | - } | |
986 | + char cpustr[3+4+1]; /* cpu numbers are up to 4095 on itanic */ | |
987 | + sprintf(cpustr, "cpu%d", hcpu); | |
988 | + remove_proc_subtree(cpustr, palinfo_dir); | |
1028 | 989 | } |
1029 | 990 | |
1030 | 991 | static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb, |
... | ... | @@ -1058,6 +1019,8 @@ |
1058 | 1019 | |
1059 | 1020 | printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION); |
1060 | 1021 | palinfo_dir = proc_mkdir("pal", NULL); |
1022 | + if (!palinfo_dir) | |
1023 | + return -ENOMEM; | |
1061 | 1024 | |
1062 | 1025 | /* Create palinfo dirs in /proc for all online cpus */ |
1063 | 1026 | for_each_online_cpu(i) { |
1064 | 1027 | |
... | ... | @@ -1073,22 +1036,8 @@ |
1073 | 1036 | static void __exit |
1074 | 1037 | palinfo_exit(void) |
1075 | 1038 | { |
1076 | - int i = 0; | |
1077 | - | |
1078 | - /* remove all nodes: depth first pass. Could optimize this */ | |
1079 | - for_each_online_cpu(i) { | |
1080 | - remove_palinfo_proc_entries(i); | |
1081 | - } | |
1082 | - | |
1083 | - /* | |
1084 | - * Remove the top level entry finally | |
1085 | - */ | |
1086 | - remove_proc_entry(palinfo_dir->name, NULL); | |
1087 | - | |
1088 | - /* | |
1089 | - * Unregister from cpu notifier callbacks | |
1090 | - */ | |
1091 | 1039 | unregister_hotcpu_notifier(&palinfo_cpu_notifier); |
1040 | + remove_proc_subtree("pal", NULL); | |
1092 | 1041 | } |
1093 | 1042 | |
1094 | 1043 | module_init(palinfo_init); |
fs/ecryptfs/miscdev.c
... | ... | @@ -80,13 +80,6 @@ |
80 | 80 | int rc; |
81 | 81 | |
82 | 82 | mutex_lock(&ecryptfs_daemon_hash_mux); |
83 | - rc = try_module_get(THIS_MODULE); | |
84 | - if (rc == 0) { | |
85 | - rc = -EIO; | |
86 | - printk(KERN_ERR "%s: Error attempting to increment module use " | |
87 | - "count; rc = [%d]\n", __func__, rc); | |
88 | - goto out_unlock_daemon_list; | |
89 | - } | |
90 | 83 | rc = ecryptfs_find_daemon_by_euid(&daemon); |
91 | 84 | if (!rc) { |
92 | 85 | rc = -EINVAL; |
... | ... | @@ -96,7 +89,7 @@ |
96 | 89 | if (rc) { |
97 | 90 | printk(KERN_ERR "%s: Error attempting to spawn daemon; " |
98 | 91 | "rc = [%d]\n", __func__, rc); |
99 | - goto out_module_put_unlock_daemon_list; | |
92 | + goto out_unlock_daemon_list; | |
100 | 93 | } |
101 | 94 | mutex_lock(&daemon->mux); |
102 | 95 | if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) { |
... | ... | @@ -108,9 +101,6 @@ |
108 | 101 | atomic_inc(&ecryptfs_num_miscdev_opens); |
109 | 102 | out_unlock_daemon: |
110 | 103 | mutex_unlock(&daemon->mux); |
111 | -out_module_put_unlock_daemon_list: | |
112 | - if (rc) | |
113 | - module_put(THIS_MODULE); | |
114 | 104 | out_unlock_daemon_list: |
115 | 105 | mutex_unlock(&ecryptfs_daemon_hash_mux); |
116 | 106 | return rc; |
... | ... | @@ -147,7 +137,6 @@ |
147 | 137 | "bug.\n", __func__, rc); |
148 | 138 | BUG(); |
149 | 139 | } |
150 | - module_put(THIS_MODULE); | |
151 | 140 | return rc; |
152 | 141 | } |
153 | 142 | |
... | ... | @@ -471,6 +460,7 @@ |
471 | 460 | |
472 | 461 | |
473 | 462 | static const struct file_operations ecryptfs_miscdev_fops = { |
463 | + .owner = THIS_MODULE, | |
474 | 464 | .open = ecryptfs_miscdev_open, |
475 | 465 | .poll = ecryptfs_miscdev_poll, |
476 | 466 | .read = ecryptfs_miscdev_read, |
fs/namespace.c
fs/proc/generic.c
... | ... | @@ -755,37 +755,8 @@ |
755 | 755 | free_proc_entry(pde); |
756 | 756 | } |
757 | 757 | |
758 | -/* | |
759 | - * Remove a /proc entry and free it if it's not currently in use. | |
760 | - */ | |
761 | -void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |
758 | +static void entry_rundown(struct proc_dir_entry *de) | |
762 | 759 | { |
763 | - struct proc_dir_entry **p; | |
764 | - struct proc_dir_entry *de = NULL; | |
765 | - const char *fn = name; | |
766 | - unsigned int len; | |
767 | - | |
768 | - spin_lock(&proc_subdir_lock); | |
769 | - if (__xlate_proc_name(name, &parent, &fn) != 0) { | |
770 | - spin_unlock(&proc_subdir_lock); | |
771 | - return; | |
772 | - } | |
773 | - len = strlen(fn); | |
774 | - | |
775 | - for (p = &parent->subdir; *p; p=&(*p)->next ) { | |
776 | - if (proc_match(len, fn, *p)) { | |
777 | - de = *p; | |
778 | - *p = de->next; | |
779 | - de->next = NULL; | |
780 | - break; | |
781 | - } | |
782 | - } | |
783 | - spin_unlock(&proc_subdir_lock); | |
784 | - if (!de) { | |
785 | - WARN(1, "name '%s'\n", name); | |
786 | - return; | |
787 | - } | |
788 | - | |
789 | 760 | spin_lock(&de->pde_unload_lock); |
790 | 761 | /* |
791 | 762 | * Stop accepting new callers into module. If you're |
792 | 763 | |
... | ... | @@ -817,7 +788,41 @@ |
817 | 788 | spin_lock(&de->pde_unload_lock); |
818 | 789 | } |
819 | 790 | spin_unlock(&de->pde_unload_lock); |
791 | +} | |
820 | 792 | |
793 | +/* | |
794 | + * Remove a /proc entry and free it if it's not currently in use. | |
795 | + */ | |
796 | +void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |
797 | +{ | |
798 | + struct proc_dir_entry **p; | |
799 | + struct proc_dir_entry *de = NULL; | |
800 | + const char *fn = name; | |
801 | + unsigned int len; | |
802 | + | |
803 | + spin_lock(&proc_subdir_lock); | |
804 | + if (__xlate_proc_name(name, &parent, &fn) != 0) { | |
805 | + spin_unlock(&proc_subdir_lock); | |
806 | + return; | |
807 | + } | |
808 | + len = strlen(fn); | |
809 | + | |
810 | + for (p = &parent->subdir; *p; p=&(*p)->next ) { | |
811 | + if (proc_match(len, fn, *p)) { | |
812 | + de = *p; | |
813 | + *p = de->next; | |
814 | + de->next = NULL; | |
815 | + break; | |
816 | + } | |
817 | + } | |
818 | + spin_unlock(&proc_subdir_lock); | |
819 | + if (!de) { | |
820 | + WARN(1, "name '%s'\n", name); | |
821 | + return; | |
822 | + } | |
823 | + | |
824 | + entry_rundown(de); | |
825 | + | |
821 | 826 | if (S_ISDIR(de->mode)) |
822 | 827 | parent->nlink--; |
823 | 828 | de->nlink = 0; |
... | ... | @@ -827,4 +832,58 @@ |
827 | 832 | pde_put(de); |
828 | 833 | } |
829 | 834 | EXPORT_SYMBOL(remove_proc_entry); |
835 | + | |
836 | +int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) | |
837 | +{ | |
838 | + struct proc_dir_entry **p; | |
839 | + struct proc_dir_entry *root = NULL, *de, *next; | |
840 | + const char *fn = name; | |
841 | + unsigned int len; | |
842 | + | |
843 | + spin_lock(&proc_subdir_lock); | |
844 | + if (__xlate_proc_name(name, &parent, &fn) != 0) { | |
845 | + spin_unlock(&proc_subdir_lock); | |
846 | + return -ENOENT; | |
847 | + } | |
848 | + len = strlen(fn); | |
849 | + | |
850 | + for (p = &parent->subdir; *p; p=&(*p)->next ) { | |
851 | + if (proc_match(len, fn, *p)) { | |
852 | + root = *p; | |
853 | + *p = root->next; | |
854 | + root->next = NULL; | |
855 | + break; | |
856 | + } | |
857 | + } | |
858 | + if (!root) { | |
859 | + spin_unlock(&proc_subdir_lock); | |
860 | + return -ENOENT; | |
861 | + } | |
862 | + de = root; | |
863 | + while (1) { | |
864 | + next = de->subdir; | |
865 | + if (next) { | |
866 | + de->subdir = next->next; | |
867 | + next->next = NULL; | |
868 | + de = next; | |
869 | + continue; | |
870 | + } | |
871 | + spin_unlock(&proc_subdir_lock); | |
872 | + | |
873 | + entry_rundown(de); | |
874 | + next = de->parent; | |
875 | + if (S_ISDIR(de->mode)) | |
876 | + next->nlink--; | |
877 | + de->nlink = 0; | |
878 | + if (de == root) | |
879 | + break; | |
880 | + pde_put(de); | |
881 | + | |
882 | + spin_lock(&proc_subdir_lock); | |
883 | + de = next; | |
884 | + } | |
885 | + pde_put(root); | |
886 | + return 0; | |
887 | +} | |
888 | +EXPORT_SYMBOL(remove_proc_subtree); |
include/linux/proc_fs.h
... | ... | @@ -117,6 +117,7 @@ |
117 | 117 | const struct file_operations *proc_fops, |
118 | 118 | void *data); |
119 | 119 | extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent); |
120 | +extern int remove_proc_subtree(const char *name, struct proc_dir_entry *parent); | |
120 | 121 | |
121 | 122 | struct pid_namespace; |
122 | 123 | |
... | ... | @@ -202,6 +203,7 @@ |
202 | 203 | return NULL; |
203 | 204 | } |
204 | 205 | #define remove_proc_entry(name, parent) do {} while (0) |
206 | +#define remove_proc_subtree(name, parent) do {} while (0) | |
205 | 207 | |
206 | 208 | static inline struct proc_dir_entry *proc_symlink(const char *name, |
207 | 209 | struct proc_dir_entry *parent,const char *dest) {return NULL;} |