diff options
author | Steve French <sfrench@us.ibm.com> | 2006-03-30 22:35:56 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2006-03-30 22:35:56 -0500 |
commit | d62e54abca1146981fc9f98f85ff398a113a22c2 (patch) | |
tree | 870420dbc4c65e716dcef8a802aafdc0ef97a8b4 /kernel/module.c | |
parent | fd4a0b92db6a57cba8d03efbe1cebf91f9124ce0 (diff) | |
parent | ce362c009250340358a7221f3cdb7954cbf19c01 (diff) |
Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 460 |
1 files changed, 158 insertions, 302 deletions
diff --git a/kernel/module.c b/kernel/module.c index 5aad477ddc7..bd088a7c149 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/device.h> | 39 | #include <linux/device.h> |
40 | #include <linux/string.h> | 40 | #include <linux/string.h> |
41 | #include <linux/sched.h> | 41 | #include <linux/sched.h> |
42 | #include <linux/mutex.h> | ||
42 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
43 | #include <asm/semaphore.h> | 44 | #include <asm/semaphore.h> |
44 | #include <asm/cacheflush.h> | 45 | #include <asm/cacheflush.h> |
@@ -60,29 +61,20 @@ | |||
60 | static DEFINE_SPINLOCK(modlist_lock); | 61 | static DEFINE_SPINLOCK(modlist_lock); |
61 | 62 | ||
62 | /* List of modules, protected by module_mutex AND modlist_lock */ | 63 | /* List of modules, protected by module_mutex AND modlist_lock */ |
63 | static DECLARE_MUTEX(module_mutex); | 64 | static DEFINE_MUTEX(module_mutex); |
64 | static LIST_HEAD(modules); | 65 | static LIST_HEAD(modules); |
65 | 66 | ||
66 | static DECLARE_MUTEX(notify_mutex); | 67 | static BLOCKING_NOTIFIER_HEAD(module_notify_list); |
67 | static struct notifier_block * module_notify_list; | ||
68 | 68 | ||
69 | int register_module_notifier(struct notifier_block * nb) | 69 | int register_module_notifier(struct notifier_block * nb) |
70 | { | 70 | { |
71 | int err; | 71 | return blocking_notifier_chain_register(&module_notify_list, nb); |
72 | down(¬ify_mutex); | ||
73 | err = notifier_chain_register(&module_notify_list, nb); | ||
74 | up(¬ify_mutex); | ||
75 | return err; | ||
76 | } | 72 | } |
77 | EXPORT_SYMBOL(register_module_notifier); | 73 | EXPORT_SYMBOL(register_module_notifier); |
78 | 74 | ||
79 | int unregister_module_notifier(struct notifier_block * nb) | 75 | int unregister_module_notifier(struct notifier_block * nb) |
80 | { | 76 | { |
81 | int err; | 77 | return blocking_notifier_chain_unregister(&module_notify_list, nb); |
82 | down(¬ify_mutex); | ||
83 | err = notifier_chain_unregister(&module_notify_list, nb); | ||
84 | up(¬ify_mutex); | ||
85 | return err; | ||
86 | } | 78 | } |
87 | EXPORT_SYMBOL(unregister_module_notifier); | 79 | EXPORT_SYMBOL(unregister_module_notifier); |
88 | 80 | ||
@@ -126,15 +118,30 @@ extern const struct kernel_symbol __start___ksymtab[]; | |||
126 | extern const struct kernel_symbol __stop___ksymtab[]; | 118 | extern const struct kernel_symbol __stop___ksymtab[]; |
127 | extern const struct kernel_symbol __start___ksymtab_gpl[]; | 119 | extern const struct kernel_symbol __start___ksymtab_gpl[]; |
128 | extern const struct kernel_symbol __stop___ksymtab_gpl[]; | 120 | extern const struct kernel_symbol __stop___ksymtab_gpl[]; |
121 | extern const struct kernel_symbol __start___ksymtab_gpl_future[]; | ||
122 | extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; | ||
129 | extern const unsigned long __start___kcrctab[]; | 123 | extern const unsigned long __start___kcrctab[]; |
130 | extern const unsigned long __start___kcrctab_gpl[]; | 124 | extern const unsigned long __start___kcrctab_gpl[]; |
125 | extern const unsigned long __start___kcrctab_gpl_future[]; | ||
131 | 126 | ||
132 | #ifndef CONFIG_MODVERSIONS | 127 | #ifndef CONFIG_MODVERSIONS |
133 | #define symversion(base, idx) NULL | 128 | #define symversion(base, idx) NULL |
134 | #else | 129 | #else |
135 | #define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL) | 130 | #define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL) |
136 | #endif | 131 | #endif |
137 | 132 | ||
133 | /* lookup symbol in given range of kernel_symbols */ | ||
134 | static const struct kernel_symbol *lookup_symbol(const char *name, | ||
135 | const struct kernel_symbol *start, | ||
136 | const struct kernel_symbol *stop) | ||
137 | { | ||
138 | const struct kernel_symbol *ks = start; | ||
139 | for (; ks < stop; ks++) | ||
140 | if (strcmp(ks->name, name) == 0) | ||
141 | return ks; | ||
142 | return NULL; | ||
143 | } | ||
144 | |||
138 | /* Find a symbol, return value, crc and module which owns it */ | 145 | /* Find a symbol, return value, crc and module which owns it */ |
139 | static unsigned long __find_symbol(const char *name, | 146 | static unsigned long __find_symbol(const char *name, |
140 | struct module **owner, | 147 | struct module **owner, |
@@ -142,64 +149,81 @@ static unsigned long __find_symbol(const char *name, | |||
142 | int gplok) | 149 | int gplok) |
143 | { | 150 | { |
144 | struct module *mod; | 151 | struct module *mod; |
145 | unsigned int i; | 152 | const struct kernel_symbol *ks; |
146 | 153 | ||
147 | /* Core kernel first. */ | 154 | /* Core kernel first. */ |
148 | *owner = NULL; | 155 | *owner = NULL; |
149 | for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) { | 156 | ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab); |
150 | if (strcmp(__start___ksymtab[i].name, name) == 0) { | 157 | if (ks) { |
151 | *crc = symversion(__start___kcrctab, i); | 158 | *crc = symversion(__start___kcrctab, (ks - __start___ksymtab)); |
152 | return __start___ksymtab[i].value; | 159 | return ks->value; |
153 | } | ||
154 | } | 160 | } |
155 | if (gplok) { | 161 | if (gplok) { |
156 | for (i = 0; __start___ksymtab_gpl+i<__stop___ksymtab_gpl; i++) | 162 | ks = lookup_symbol(name, __start___ksymtab_gpl, |
157 | if (strcmp(__start___ksymtab_gpl[i].name, name) == 0) { | 163 | __stop___ksymtab_gpl); |
158 | *crc = symversion(__start___kcrctab_gpl, i); | 164 | if (ks) { |
159 | return __start___ksymtab_gpl[i].value; | 165 | *crc = symversion(__start___kcrctab_gpl, |
160 | } | 166 | (ks - __start___ksymtab_gpl)); |
167 | return ks->value; | ||
168 | } | ||
169 | } | ||
170 | ks = lookup_symbol(name, __start___ksymtab_gpl_future, | ||
171 | __stop___ksymtab_gpl_future); | ||
172 | if (ks) { | ||
173 | if (!gplok) { | ||
174 | printk(KERN_WARNING "Symbol %s is being used " | ||
175 | "by a non-GPL module, which will not " | ||
176 | "be allowed in the future\n", name); | ||
177 | printk(KERN_WARNING "Please see the file " | ||
178 | "Documentation/feature-removal-schedule.txt " | ||
179 | "in the kernel source tree for more " | ||
180 | "details.\n"); | ||
181 | } | ||
182 | *crc = symversion(__start___kcrctab_gpl_future, | ||
183 | (ks - __start___ksymtab_gpl_future)); | ||
184 | return ks->value; | ||
161 | } | 185 | } |
162 | 186 | ||
163 | /* Now try modules. */ | 187 | /* Now try modules. */ |
164 | list_for_each_entry(mod, &modules, list) { | 188 | list_for_each_entry(mod, &modules, list) { |
165 | *owner = mod; | 189 | *owner = mod; |
166 | for (i = 0; i < mod->num_syms; i++) | 190 | ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms); |
167 | if (strcmp(mod->syms[i].name, name) == 0) { | 191 | if (ks) { |
168 | *crc = symversion(mod->crcs, i); | 192 | *crc = symversion(mod->crcs, (ks - mod->syms)); |
169 | return mod->syms[i].value; | 193 | return ks->value; |
170 | } | 194 | } |
171 | 195 | ||
172 | if (gplok) { | 196 | if (gplok) { |
173 | for (i = 0; i < mod->num_gpl_syms; i++) { | 197 | ks = lookup_symbol(name, mod->gpl_syms, |
174 | if (strcmp(mod->gpl_syms[i].name, name) == 0) { | 198 | mod->gpl_syms + mod->num_gpl_syms); |
175 | *crc = symversion(mod->gpl_crcs, i); | 199 | if (ks) { |
176 | return mod->gpl_syms[i].value; | 200 | *crc = symversion(mod->gpl_crcs, |
177 | } | 201 | (ks - mod->gpl_syms)); |
202 | return ks->value; | ||
203 | } | ||
204 | } | ||
205 | ks = lookup_symbol(name, mod->gpl_future_syms, | ||
206 | (mod->gpl_future_syms + | ||
207 | mod->num_gpl_future_syms)); | ||
208 | if (ks) { | ||
209 | if (!gplok) { | ||
210 | printk(KERN_WARNING "Symbol %s is being used " | ||
211 | "by a non-GPL module, which will not " | ||
212 | "be allowed in the future\n", name); | ||
213 | printk(KERN_WARNING "Please see the file " | ||
214 | "Documentation/feature-removal-schedule.txt " | ||
215 | "in the kernel source tree for more " | ||
216 | "details.\n"); | ||
178 | } | 217 | } |
218 | *crc = symversion(mod->gpl_future_crcs, | ||
219 | (ks - mod->gpl_future_syms)); | ||
220 | return ks->value; | ||
179 | } | 221 | } |
180 | } | 222 | } |
181 | DEBUGP("Failed to find symbol %s\n", name); | 223 | DEBUGP("Failed to find symbol %s\n", name); |
182 | return 0; | 224 | return 0; |
183 | } | 225 | } |
184 | 226 | ||
185 | /* Find a symbol in this elf symbol table */ | ||
186 | static unsigned long find_local_symbol(Elf_Shdr *sechdrs, | ||
187 | unsigned int symindex, | ||
188 | const char *strtab, | ||
189 | const char *name) | ||
190 | { | ||
191 | unsigned int i; | ||
192 | Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; | ||
193 | |||
194 | /* Search (defined) internal symbols first. */ | ||
195 | for (i = 1; i < sechdrs[symindex].sh_size/sizeof(*sym); i++) { | ||
196 | if (sym[i].st_shndx != SHN_UNDEF | ||
197 | && strcmp(name, strtab + sym[i].st_name) == 0) | ||
198 | return sym[i].st_value; | ||
199 | } | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | /* Search for module by name: must hold module_mutex. */ | 227 | /* Search for module by name: must hold module_mutex. */ |
204 | static struct module *find_module(const char *name) | 228 | static struct module *find_module(const char *name) |
205 | { | 229 | { |
@@ -379,7 +403,6 @@ static inline void percpu_modcopy(void *pcpudst, const void *src, | |||
379 | } | 403 | } |
380 | #endif /* CONFIG_SMP */ | 404 | #endif /* CONFIG_SMP */ |
381 | 405 | ||
382 | #ifdef CONFIG_MODULE_UNLOAD | ||
383 | #define MODINFO_ATTR(field) \ | 406 | #define MODINFO_ATTR(field) \ |
384 | static void setup_modinfo_##field(struct module *mod, const char *s) \ | 407 | static void setup_modinfo_##field(struct module *mod, const char *s) \ |
385 | { \ | 408 | { \ |
@@ -411,12 +434,7 @@ static struct module_attribute modinfo_##field = { \ | |||
411 | MODINFO_ATTR(version); | 434 | MODINFO_ATTR(version); |
412 | MODINFO_ATTR(srcversion); | 435 | MODINFO_ATTR(srcversion); |
413 | 436 | ||
414 | static struct module_attribute *modinfo_attrs[] = { | 437 | #ifdef CONFIG_MODULE_UNLOAD |
415 | &modinfo_version, | ||
416 | &modinfo_srcversion, | ||
417 | NULL, | ||
418 | }; | ||
419 | |||
420 | /* Init the unload section of the module. */ | 438 | /* Init the unload section of the module. */ |
421 | static void module_unload_init(struct module *mod) | 439 | static void module_unload_init(struct module *mod) |
422 | { | 440 | { |
@@ -557,7 +575,7 @@ static void free_module(struct module *mod); | |||
557 | static void wait_for_zero_refcount(struct module *mod) | 575 | static void wait_for_zero_refcount(struct module *mod) |
558 | { | 576 | { |
559 | /* Since we might sleep for some time, drop the semaphore first */ | 577 | /* Since we might sleep for some time, drop the semaphore first */ |
560 | up(&module_mutex); | 578 | mutex_unlock(&module_mutex); |
561 | for (;;) { | 579 | for (;;) { |
562 | DEBUGP("Looking at refcount...\n"); | 580 | DEBUGP("Looking at refcount...\n"); |
563 | set_current_state(TASK_UNINTERRUPTIBLE); | 581 | set_current_state(TASK_UNINTERRUPTIBLE); |
@@ -566,7 +584,7 @@ static void wait_for_zero_refcount(struct module *mod) | |||
566 | schedule(); | 584 | schedule(); |
567 | } | 585 | } |
568 | current->state = TASK_RUNNING; | 586 | current->state = TASK_RUNNING; |
569 | down(&module_mutex); | 587 | mutex_lock(&module_mutex); |
570 | } | 588 | } |
571 | 589 | ||
572 | asmlinkage long | 590 | asmlinkage long |
@@ -583,7 +601,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags) | |||
583 | return -EFAULT; | 601 | return -EFAULT; |
584 | name[MODULE_NAME_LEN-1] = '\0'; | 602 | name[MODULE_NAME_LEN-1] = '\0'; |
585 | 603 | ||
586 | if (down_interruptible(&module_mutex) != 0) | 604 | if (mutex_lock_interruptible(&module_mutex) != 0) |
587 | return -EINTR; | 605 | return -EINTR; |
588 | 606 | ||
589 | mod = find_module(name); | 607 | mod = find_module(name); |
@@ -632,14 +650,14 @@ sys_delete_module(const char __user *name_user, unsigned int flags) | |||
632 | 650 | ||
633 | /* Final destruction now noone is using it. */ | 651 | /* Final destruction now noone is using it. */ |
634 | if (mod->exit != NULL) { | 652 | if (mod->exit != NULL) { |
635 | up(&module_mutex); | 653 | mutex_unlock(&module_mutex); |
636 | mod->exit(); | 654 | mod->exit(); |
637 | down(&module_mutex); | 655 | mutex_lock(&module_mutex); |
638 | } | 656 | } |
639 | free_module(mod); | 657 | free_module(mod); |
640 | 658 | ||
641 | out: | 659 | out: |
642 | up(&module_mutex); | 660 | mutex_unlock(&module_mutex); |
643 | return ret; | 661 | return ret; |
644 | } | 662 | } |
645 | 663 | ||
@@ -731,138 +749,14 @@ static inline void module_unload_init(struct module *mod) | |||
731 | } | 749 | } |
732 | #endif /* CONFIG_MODULE_UNLOAD */ | 750 | #endif /* CONFIG_MODULE_UNLOAD */ |
733 | 751 | ||
734 | #ifdef CONFIG_OBSOLETE_MODPARM | 752 | static struct module_attribute *modinfo_attrs[] = { |
735 | /* Bounds checking done below */ | 753 | &modinfo_version, |
736 | static int obsparm_copy_string(const char *val, struct kernel_param *kp) | 754 | &modinfo_srcversion, |
737 | { | 755 | #ifdef CONFIG_MODULE_UNLOAD |
738 | strcpy(kp->arg, val); | 756 | &refcnt, |
739 | return 0; | 757 | #endif |
740 | } | 758 | NULL, |
741 | 759 | }; | |
742 | static int set_obsolete(const char *val, struct kernel_param *kp) | ||
743 | { | ||
744 | unsigned int min, max; | ||
745 | unsigned int size, maxsize; | ||
746 | int dummy; | ||
747 | char *endp; | ||
748 | const char *p; | ||
749 | struct obsolete_modparm *obsparm = kp->arg; | ||
750 | |||
751 | if (!val) { | ||
752 | printk(KERN_ERR "Parameter %s needs an argument\n", kp->name); | ||
753 | return -EINVAL; | ||
754 | } | ||
755 | |||
756 | /* type is: [min[-max]]{b,h,i,l,s} */ | ||
757 | p = obsparm->type; | ||
758 | min = simple_strtol(p, &endp, 10); | ||
759 | if (endp == obsparm->type) | ||
760 | min = max = 1; | ||
761 | else if (*endp == '-') { | ||
762 | p = endp+1; | ||
763 | max = simple_strtol(p, &endp, 10); | ||
764 | } else | ||
765 | max = min; | ||
766 | switch (*endp) { | ||
767 | case 'b': | ||
768 | return param_array(kp->name, val, min, max, obsparm->addr, | ||
769 | 1, param_set_byte, &dummy); | ||
770 | case 'h': | ||
771 | return param_array(kp->name, val, min, max, obsparm->addr, | ||
772 | sizeof(short), param_set_short, &dummy); | ||
773 | case 'i': | ||
774 | return param_array(kp->name, val, min, max, obsparm->addr, | ||
775 | sizeof(int), param_set_int, &dummy); | ||
776 | case 'l': | ||
777 | return param_array(kp->name, val, min, max, obsparm->addr, | ||
778 | sizeof(long), param_set_long, &dummy); | ||
779 | case 's': | ||
780 | return param_array(kp->name, val, min, max, obsparm->addr, | ||
781 | sizeof(char *), param_set_charp, &dummy); | ||
782 | |||
783 | case 'c': | ||
784 | /* Undocumented: 1-5c50 means 1-5 strings of up to 49 chars, | ||
785 | and the decl is "char xxx[5][50];" */ | ||
786 | p = endp+1; | ||
787 | maxsize = simple_strtol(p, &endp, 10); | ||
788 | /* We check lengths here (yes, this is a hack). */ | ||
789 | p = val; | ||
790 | while (p[size = strcspn(p, ",")]) { | ||
791 | if (size >= maxsize) | ||
792 | goto oversize; | ||
793 | p += size+1; | ||
794 | } | ||
795 | if (size >= maxsize) | ||
796 | goto oversize; | ||
797 | return param_array(kp->name, val, min, max, obsparm->addr, | ||
798 | maxsize, obsparm_copy_string, &dummy); | ||
799 | } | ||
800 | printk(KERN_ERR "Unknown obsolete parameter type %s\n", obsparm->type); | ||
801 | return -EINVAL; | ||
802 | oversize: | ||
803 | printk(KERN_ERR | ||
804 | "Parameter %s doesn't fit in %u chars.\n", kp->name, maxsize); | ||
805 | return -EINVAL; | ||
806 | } | ||
807 | |||
808 | static int obsolete_params(const char *name, | ||
809 | char *args, | ||
810 | struct obsolete_modparm obsparm[], | ||
811 | unsigned int num, | ||
812 | Elf_Shdr *sechdrs, | ||
813 | unsigned int symindex, | ||
814 | const char *strtab) | ||
815 | { | ||
816 | struct kernel_param *kp; | ||
817 | unsigned int i; | ||
818 | int ret; | ||
819 | |||
820 | kp = kmalloc(sizeof(kp[0]) * num, GFP_KERNEL); | ||
821 | if (!kp) | ||
822 | return -ENOMEM; | ||
823 | |||
824 | for (i = 0; i < num; i++) { | ||
825 | char sym_name[128 + sizeof(MODULE_SYMBOL_PREFIX)]; | ||
826 | |||
827 | snprintf(sym_name, sizeof(sym_name), "%s%s", | ||
828 | MODULE_SYMBOL_PREFIX, obsparm[i].name); | ||
829 | |||
830 | kp[i].name = obsparm[i].name; | ||
831 | kp[i].perm = 000; | ||
832 | kp[i].set = set_obsolete; | ||
833 | kp[i].get = NULL; | ||
834 | obsparm[i].addr | ||
835 | = (void *)find_local_symbol(sechdrs, symindex, strtab, | ||
836 | sym_name); | ||
837 | if (!obsparm[i].addr) { | ||
838 | printk("%s: falsely claims to have parameter %s\n", | ||
839 | name, obsparm[i].name); | ||
840 | ret = -EINVAL; | ||
841 | goto out; | ||
842 | } | ||
843 | kp[i].arg = &obsparm[i]; | ||
844 | } | ||
845 | |||
846 | ret = parse_args(name, args, kp, num, NULL); | ||
847 | out: | ||
848 | kfree(kp); | ||
849 | return ret; | ||
850 | } | ||
851 | #else | ||
852 | static int obsolete_params(const char *name, | ||
853 | char *args, | ||
854 | struct obsolete_modparm obsparm[], | ||
855 | unsigned int num, | ||
856 | Elf_Shdr *sechdrs, | ||
857 | unsigned int symindex, | ||
858 | const char *strtab) | ||
859 | { | ||
860 | if (num != 0) | ||
861 | printk(KERN_WARNING "%s: Ignoring obsolete parameters\n", | ||
862 | name); | ||
863 | return 0; | ||
864 | } | ||
865 | #endif /* CONFIG_OBSOLETE_MODPARM */ | ||
866 | 760 | ||
867 | static const char vermagic[] = VERMAGIC_STRING; | 761 | static const char vermagic[] = VERMAGIC_STRING; |
868 | 762 | ||
@@ -1056,37 +950,28 @@ static inline void remove_sect_attrs(struct module *mod) | |||
1056 | } | 950 | } |
1057 | #endif /* CONFIG_KALLSYMS */ | 951 | #endif /* CONFIG_KALLSYMS */ |
1058 | 952 | ||
1059 | |||
1060 | #ifdef CONFIG_MODULE_UNLOAD | ||
1061 | static inline int module_add_refcnt_attr(struct module *mod) | ||
1062 | { | ||
1063 | return sysfs_create_file(&mod->mkobj.kobj, &refcnt.attr); | ||
1064 | } | ||
1065 | static void module_remove_refcnt_attr(struct module *mod) | ||
1066 | { | ||
1067 | return sysfs_remove_file(&mod->mkobj.kobj, &refcnt.attr); | ||
1068 | } | ||
1069 | #else | ||
1070 | static inline int module_add_refcnt_attr(struct module *mod) | ||
1071 | { | ||
1072 | return 0; | ||
1073 | } | ||
1074 | static void module_remove_refcnt_attr(struct module *mod) | ||
1075 | { | ||
1076 | } | ||
1077 | #endif | ||
1078 | |||
1079 | #ifdef CONFIG_MODULE_UNLOAD | ||
1080 | static int module_add_modinfo_attrs(struct module *mod) | 953 | static int module_add_modinfo_attrs(struct module *mod) |
1081 | { | 954 | { |
1082 | struct module_attribute *attr; | 955 | struct module_attribute *attr; |
956 | struct module_attribute *temp_attr; | ||
1083 | int error = 0; | 957 | int error = 0; |
1084 | int i; | 958 | int i; |
1085 | 959 | ||
960 | mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) * | ||
961 | (ARRAY_SIZE(modinfo_attrs) + 1)), | ||
962 | GFP_KERNEL); | ||
963 | if (!mod->modinfo_attrs) | ||
964 | return -ENOMEM; | ||
965 | |||
966 | temp_attr = mod->modinfo_attrs; | ||
1086 | for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { | 967 | for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { |
1087 | if (!attr->test || | 968 | if (!attr->test || |
1088 | (attr->test && attr->test(mod))) | 969 | (attr->test && attr->test(mod))) { |
1089 | error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr); | 970 | memcpy(temp_attr, attr, sizeof(*temp_attr)); |
971 | temp_attr->attr.owner = mod; | ||
972 | error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr); | ||
973 | ++temp_attr; | ||
974 | } | ||
1090 | } | 975 | } |
1091 | return error; | 976 | return error; |
1092 | } | 977 | } |
@@ -1096,12 +981,16 @@ static void module_remove_modinfo_attrs(struct module *mod) | |||
1096 | struct module_attribute *attr; | 981 | struct module_attribute *attr; |
1097 | int i; | 982 | int i; |
1098 | 983 | ||
1099 | for (i = 0; (attr = modinfo_attrs[i]); i++) { | 984 | for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) { |
985 | /* pick a field to test for end of list */ | ||
986 | if (!attr->attr.name) | ||
987 | break; | ||
1100 | sysfs_remove_file(&mod->mkobj.kobj,&attr->attr); | 988 | sysfs_remove_file(&mod->mkobj.kobj,&attr->attr); |
1101 | attr->free(mod); | 989 | if (attr->free) |
990 | attr->free(mod); | ||
1102 | } | 991 | } |
992 | kfree(mod->modinfo_attrs); | ||
1103 | } | 993 | } |
1104 | #endif | ||
1105 | 994 | ||
1106 | static int mod_sysfs_setup(struct module *mod, | 995 | static int mod_sysfs_setup(struct module *mod, |
1107 | struct kernel_param *kparam, | 996 | struct kernel_param *kparam, |
@@ -1119,19 +1008,13 @@ static int mod_sysfs_setup(struct module *mod, | |||
1119 | if (err) | 1008 | if (err) |
1120 | goto out; | 1009 | goto out; |
1121 | 1010 | ||
1122 | err = module_add_refcnt_attr(mod); | ||
1123 | if (err) | ||
1124 | goto out_unreg; | ||
1125 | |||
1126 | err = module_param_sysfs_setup(mod, kparam, num_params); | 1011 | err = module_param_sysfs_setup(mod, kparam, num_params); |
1127 | if (err) | 1012 | if (err) |
1128 | goto out_unreg; | 1013 | goto out_unreg; |
1129 | 1014 | ||
1130 | #ifdef CONFIG_MODULE_UNLOAD | ||
1131 | err = module_add_modinfo_attrs(mod); | 1015 | err = module_add_modinfo_attrs(mod); |
1132 | if (err) | 1016 | if (err) |
1133 | goto out_unreg; | 1017 | goto out_unreg; |
1134 | #endif | ||
1135 | 1018 | ||
1136 | return 0; | 1019 | return 0; |
1137 | 1020 | ||
@@ -1143,10 +1026,7 @@ out: | |||
1143 | 1026 | ||
1144 | static void mod_kobject_remove(struct module *mod) | 1027 | static void mod_kobject_remove(struct module *mod) |
1145 | { | 1028 | { |
1146 | #ifdef CONFIG_MODULE_UNLOAD | ||
1147 | module_remove_modinfo_attrs(mod); | 1029 | module_remove_modinfo_attrs(mod); |
1148 | #endif | ||
1149 | module_remove_refcnt_attr(mod); | ||
1150 | module_param_sysfs_remove(mod); | 1030 | module_param_sysfs_remove(mod); |
1151 | 1031 | ||
1152 | kobject_unregister(&mod->mkobj.kobj); | 1032 | kobject_unregister(&mod->mkobj.kobj); |
@@ -1424,7 +1304,6 @@ static char *get_modinfo(Elf_Shdr *sechdrs, | |||
1424 | return NULL; | 1304 | return NULL; |
1425 | } | 1305 | } |
1426 | 1306 | ||
1427 | #ifdef CONFIG_MODULE_UNLOAD | ||
1428 | static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, | 1307 | static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, |
1429 | unsigned int infoindex) | 1308 | unsigned int infoindex) |
1430 | { | 1309 | { |
@@ -1439,23 +1318,17 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, | |||
1439 | attr->attr.name)); | 1318 | attr->attr.name)); |
1440 | } | 1319 | } |
1441 | } | 1320 | } |
1442 | #endif | ||
1443 | 1321 | ||
1444 | #ifdef CONFIG_KALLSYMS | 1322 | #ifdef CONFIG_KALLSYMS |
1445 | int is_exported(const char *name, const struct module *mod) | 1323 | int is_exported(const char *name, const struct module *mod) |
1446 | { | 1324 | { |
1447 | unsigned int i; | 1325 | if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab)) |
1448 | 1326 | return 1; | |
1449 | if (!mod) { | 1327 | else |
1450 | for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) | 1328 | if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms)) |
1451 | if (strcmp(__start___ksymtab[i].name, name) == 0) | ||
1452 | return 1; | ||
1453 | return 0; | ||
1454 | } | ||
1455 | for (i = 0; i < mod->num_syms; i++) | ||
1456 | if (strcmp(mod->syms[i].name, name) == 0) | ||
1457 | return 1; | 1329 | return 1; |
1458 | return 0; | 1330 | else |
1331 | return 0; | ||
1459 | } | 1332 | } |
1460 | 1333 | ||
1461 | /* As per nm */ | 1334 | /* As per nm */ |
@@ -1537,8 +1410,8 @@ static struct module *load_module(void __user *umod, | |||
1537 | char *secstrings, *args, *modmagic, *strtab = NULL; | 1410 | char *secstrings, *args, *modmagic, *strtab = NULL; |
1538 | unsigned int i, symindex = 0, strindex = 0, setupindex, exindex, | 1411 | unsigned int i, symindex = 0, strindex = 0, setupindex, exindex, |
1539 | exportindex, modindex, obsparmindex, infoindex, gplindex, | 1412 | exportindex, modindex, obsparmindex, infoindex, gplindex, |
1540 | crcindex, gplcrcindex, versindex, pcpuindex; | 1413 | crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex, |
1541 | long arglen; | 1414 | gplfuturecrcindex; |
1542 | struct module *mod; | 1415 | struct module *mod; |
1543 | long err = 0; | 1416 | long err = 0; |
1544 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ | 1417 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ |
@@ -1618,8 +1491,10 @@ static struct module *load_module(void __user *umod, | |||
1618 | /* Optional sections */ | 1491 | /* Optional sections */ |
1619 | exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); | 1492 | exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); |
1620 | gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); | 1493 | gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); |
1494 | gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future"); | ||
1621 | crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); | 1495 | crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); |
1622 | gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); | 1496 | gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); |
1497 | gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future"); | ||
1623 | setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); | 1498 | setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); |
1624 | exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); | 1499 | exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); |
1625 | obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); | 1500 | obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); |
@@ -1655,23 +1530,11 @@ static struct module *load_module(void __user *umod, | |||
1655 | } | 1530 | } |
1656 | 1531 | ||
1657 | /* Now copy in args */ | 1532 | /* Now copy in args */ |
1658 | arglen = strlen_user(uargs); | 1533 | args = strndup_user(uargs, ~0UL >> 1); |
1659 | if (!arglen) { | 1534 | if (IS_ERR(args)) { |
1660 | err = -EFAULT; | 1535 | err = PTR_ERR(args); |
1661 | goto free_hdr; | 1536 | goto free_hdr; |
1662 | } | 1537 | } |
1663 | args = kmalloc(arglen, GFP_KERNEL); | ||
1664 | if (!args) { | ||
1665 | err = -ENOMEM; | ||
1666 | goto free_hdr; | ||
1667 | } | ||
1668 | if (copy_from_user(args, uargs, arglen) != 0) { | ||
1669 | err = -EFAULT; | ||
1670 | goto free_mod; | ||
1671 | } | ||
1672 | |||
1673 | /* Userspace could have altered the string after the strlen_user() */ | ||
1674 | args[arglen - 1] = '\0'; | ||
1675 | 1538 | ||
1676 | if (find_module(mod->name)) { | 1539 | if (find_module(mod->name)) { |
1677 | err = -EEXIST; | 1540 | err = -EEXIST; |
@@ -1755,10 +1618,8 @@ static struct module *load_module(void __user *umod, | |||
1755 | if (strcmp(mod->name, "driverloader") == 0) | 1618 | if (strcmp(mod->name, "driverloader") == 0) |
1756 | add_taint(TAINT_PROPRIETARY_MODULE); | 1619 | add_taint(TAINT_PROPRIETARY_MODULE); |
1757 | 1620 | ||
1758 | #ifdef CONFIG_MODULE_UNLOAD | ||
1759 | /* Set up MODINFO_ATTR fields */ | 1621 | /* Set up MODINFO_ATTR fields */ |
1760 | setup_modinfo(mod, sechdrs, infoindex); | 1622 | setup_modinfo(mod, sechdrs, infoindex); |
1761 | #endif | ||
1762 | 1623 | ||
1763 | /* Fix up syms, so that st_value is a pointer to location. */ | 1624 | /* Fix up syms, so that st_value is a pointer to location. */ |
1764 | err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, | 1625 | err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, |
@@ -1775,10 +1636,16 @@ static struct module *load_module(void __user *umod, | |||
1775 | mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr; | 1636 | mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr; |
1776 | if (gplcrcindex) | 1637 | if (gplcrcindex) |
1777 | mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; | 1638 | mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; |
1639 | mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size / | ||
1640 | sizeof(*mod->gpl_future_syms); | ||
1641 | mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; | ||
1642 | if (gplfuturecrcindex) | ||
1643 | mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; | ||
1778 | 1644 | ||
1779 | #ifdef CONFIG_MODVERSIONS | 1645 | #ifdef CONFIG_MODVERSIONS |
1780 | if ((mod->num_syms && !crcindex) || | 1646 | if ((mod->num_syms && !crcindex) || |
1781 | (mod->num_gpl_syms && !gplcrcindex)) { | 1647 | (mod->num_gpl_syms && !gplcrcindex) || |
1648 | (mod->num_gpl_future_syms && !gplfuturecrcindex)) { | ||
1782 | printk(KERN_WARNING "%s: No versions for exported symbols." | 1649 | printk(KERN_WARNING "%s: No versions for exported symbols." |
1783 | " Tainting kernel.\n", mod->name); | 1650 | " Tainting kernel.\n", mod->name); |
1784 | add_taint(TAINT_FORCED_MODULE); | 1651 | add_taint(TAINT_FORCED_MODULE); |
@@ -1847,27 +1714,17 @@ static struct module *load_module(void __user *umod, | |||
1847 | set_fs(old_fs); | 1714 | set_fs(old_fs); |
1848 | 1715 | ||
1849 | mod->args = args; | 1716 | mod->args = args; |
1850 | if (obsparmindex) { | 1717 | if (obsparmindex) |
1851 | err = obsolete_params(mod->name, mod->args, | 1718 | printk(KERN_WARNING "%s: Ignoring obsolete parameters\n", |
1852 | (struct obsolete_modparm *) | 1719 | mod->name); |
1853 | sechdrs[obsparmindex].sh_addr, | 1720 | |
1854 | sechdrs[obsparmindex].sh_size | 1721 | /* Size of section 0 is 0, so this works well if no params */ |
1855 | / sizeof(struct obsolete_modparm), | 1722 | err = parse_args(mod->name, mod->args, |
1856 | sechdrs, symindex, | 1723 | (struct kernel_param *) |
1857 | (char *)sechdrs[strindex].sh_addr); | 1724 | sechdrs[setupindex].sh_addr, |
1858 | if (setupindex) | 1725 | sechdrs[setupindex].sh_size |
1859 | printk(KERN_WARNING "%s: Ignoring new-style " | 1726 | / sizeof(struct kernel_param), |
1860 | "parameters in presence of obsolete ones\n", | 1727 | NULL); |
1861 | mod->name); | ||
1862 | } else { | ||
1863 | /* Size of section 0 is 0, so this works well if no params */ | ||
1864 | err = parse_args(mod->name, mod->args, | ||
1865 | (struct kernel_param *) | ||
1866 | sechdrs[setupindex].sh_addr, | ||
1867 | sechdrs[setupindex].sh_size | ||
1868 | / sizeof(struct kernel_param), | ||
1869 | NULL); | ||
1870 | } | ||
1871 | if (err < 0) | 1728 | if (err < 0) |
1872 | goto arch_cleanup; | 1729 | goto arch_cleanup; |
1873 | 1730 | ||
@@ -1933,13 +1790,13 @@ sys_init_module(void __user *umod, | |||
1933 | return -EPERM; | 1790 | return -EPERM; |
1934 | 1791 | ||
1935 | /* Only one module load at a time, please */ | 1792 | /* Only one module load at a time, please */ |
1936 | if (down_interruptible(&module_mutex) != 0) | 1793 | if (mutex_lock_interruptible(&module_mutex) != 0) |
1937 | return -EINTR; | 1794 | return -EINTR; |
1938 | 1795 | ||
1939 | /* Do all the hard work */ | 1796 | /* Do all the hard work */ |
1940 | mod = load_module(umod, len, uargs); | 1797 | mod = load_module(umod, len, uargs); |
1941 | if (IS_ERR(mod)) { | 1798 | if (IS_ERR(mod)) { |
1942 | up(&module_mutex); | 1799 | mutex_unlock(&module_mutex); |
1943 | return PTR_ERR(mod); | 1800 | return PTR_ERR(mod); |
1944 | } | 1801 | } |
1945 | 1802 | ||
@@ -1948,11 +1805,10 @@ sys_init_module(void __user *umod, | |||
1948 | stop_machine_run(__link_module, mod, NR_CPUS); | 1805 | stop_machine_run(__link_module, mod, NR_CPUS); |
1949 | 1806 | ||
1950 | /* Drop lock so they can recurse */ | 1807 | /* Drop lock so they can recurse */ |
1951 | up(&module_mutex); | 1808 | mutex_unlock(&module_mutex); |
1952 | 1809 | ||
1953 | down(¬ify_mutex); | 1810 | blocking_notifier_call_chain(&module_notify_list, |
1954 | notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod); | 1811 | MODULE_STATE_COMING, mod); |
1955 | up(¬ify_mutex); | ||
1956 | 1812 | ||
1957 | /* Start the module */ | 1813 | /* Start the module */ |
1958 | if (mod->init != NULL) | 1814 | if (mod->init != NULL) |
@@ -1967,15 +1823,15 @@ sys_init_module(void __user *umod, | |||
1967 | mod->name); | 1823 | mod->name); |
1968 | else { | 1824 | else { |
1969 | module_put(mod); | 1825 | module_put(mod); |
1970 | down(&module_mutex); | 1826 | mutex_lock(&module_mutex); |
1971 | free_module(mod); | 1827 | free_module(mod); |
1972 | up(&module_mutex); | 1828 | mutex_unlock(&module_mutex); |
1973 | } | 1829 | } |
1974 | return ret; | 1830 | return ret; |
1975 | } | 1831 | } |
1976 | 1832 | ||
1977 | /* Now it's a first class citizen! */ | 1833 | /* Now it's a first class citizen! */ |
1978 | down(&module_mutex); | 1834 | mutex_lock(&module_mutex); |
1979 | mod->state = MODULE_STATE_LIVE; | 1835 | mod->state = MODULE_STATE_LIVE; |
1980 | /* Drop initial reference. */ | 1836 | /* Drop initial reference. */ |
1981 | module_put(mod); | 1837 | module_put(mod); |
@@ -1983,7 +1839,7 @@ sys_init_module(void __user *umod, | |||
1983 | mod->module_init = NULL; | 1839 | mod->module_init = NULL; |
1984 | mod->init_size = 0; | 1840 | mod->init_size = 0; |
1985 | mod->init_text_size = 0; | 1841 | mod->init_text_size = 0; |
1986 | up(&module_mutex); | 1842 | mutex_unlock(&module_mutex); |
1987 | 1843 | ||
1988 | return 0; | 1844 | return 0; |
1989 | } | 1845 | } |
@@ -2073,7 +1929,7 @@ struct module *module_get_kallsym(unsigned int symnum, | |||
2073 | { | 1929 | { |
2074 | struct module *mod; | 1930 | struct module *mod; |
2075 | 1931 | ||
2076 | down(&module_mutex); | 1932 | mutex_lock(&module_mutex); |
2077 | list_for_each_entry(mod, &modules, list) { | 1933 | list_for_each_entry(mod, &modules, list) { |
2078 | if (symnum < mod->num_symtab) { | 1934 | if (symnum < mod->num_symtab) { |
2079 | *value = mod->symtab[symnum].st_value; | 1935 | *value = mod->symtab[symnum].st_value; |
@@ -2081,12 +1937,12 @@ struct module *module_get_kallsym(unsigned int symnum, | |||
2081 | strncpy(namebuf, | 1937 | strncpy(namebuf, |
2082 | mod->strtab + mod->symtab[symnum].st_name, | 1938 | mod->strtab + mod->symtab[symnum].st_name, |
2083 | 127); | 1939 | 127); |
2084 | up(&module_mutex); | 1940 | mutex_unlock(&module_mutex); |
2085 | return mod; | 1941 | return mod; |
2086 | } | 1942 | } |
2087 | symnum -= mod->num_symtab; | 1943 | symnum -= mod->num_symtab; |
2088 | } | 1944 | } |
2089 | up(&module_mutex); | 1945 | mutex_unlock(&module_mutex); |
2090 | return NULL; | 1946 | return NULL; |
2091 | } | 1947 | } |
2092 | 1948 | ||
@@ -2129,7 +1985,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
2129 | struct list_head *i; | 1985 | struct list_head *i; |
2130 | loff_t n = 0; | 1986 | loff_t n = 0; |
2131 | 1987 | ||
2132 | down(&module_mutex); | 1988 | mutex_lock(&module_mutex); |
2133 | list_for_each(i, &modules) { | 1989 | list_for_each(i, &modules) { |
2134 | if (n++ == *pos) | 1990 | if (n++ == *pos) |
2135 | break; | 1991 | break; |
@@ -2150,7 +2006,7 @@ static void *m_next(struct seq_file *m, void *p, loff_t *pos) | |||
2150 | 2006 | ||
2151 | static void m_stop(struct seq_file *m, void *p) | 2007 | static void m_stop(struct seq_file *m, void *p) |
2152 | { | 2008 | { |
2153 | up(&module_mutex); | 2009 | mutex_unlock(&module_mutex); |
2154 | } | 2010 | } |
2155 | 2011 | ||
2156 | static int m_show(struct seq_file *m, void *p) | 2012 | static int m_show(struct seq_file *m, void *p) |