diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 343 |
1 files changed, 207 insertions, 136 deletions
diff --git a/kernel/module.c b/kernel/module.c index 5f80478b746d..61d212120df4 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -70,6 +70,9 @@ static DECLARE_WAIT_QUEUE_HEAD(module_wq); | |||
| 70 | 70 | ||
| 71 | static BLOCKING_NOTIFIER_HEAD(module_notify_list); | 71 | static BLOCKING_NOTIFIER_HEAD(module_notify_list); |
| 72 | 72 | ||
| 73 | /* Bounds of module allocation, for speeding __module_text_address */ | ||
| 74 | static unsigned long module_addr_min = -1UL, module_addr_max = 0; | ||
| 75 | |||
| 73 | int register_module_notifier(struct notifier_block * nb) | 76 | int register_module_notifier(struct notifier_block * nb) |
| 74 | { | 77 | { |
| 75 | return blocking_notifier_chain_register(&module_notify_list, nb); | 78 | return blocking_notifier_chain_register(&module_notify_list, nb); |
| @@ -134,17 +137,19 @@ extern const struct kernel_symbol __start___ksymtab_gpl[]; | |||
| 134 | extern const struct kernel_symbol __stop___ksymtab_gpl[]; | 137 | extern const struct kernel_symbol __stop___ksymtab_gpl[]; |
| 135 | extern const struct kernel_symbol __start___ksymtab_gpl_future[]; | 138 | extern const struct kernel_symbol __start___ksymtab_gpl_future[]; |
| 136 | extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; | 139 | extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; |
| 137 | extern const struct kernel_symbol __start___ksymtab_unused[]; | ||
| 138 | extern const struct kernel_symbol __stop___ksymtab_unused[]; | ||
| 139 | extern const struct kernel_symbol __start___ksymtab_unused_gpl[]; | ||
| 140 | extern const struct kernel_symbol __stop___ksymtab_unused_gpl[]; | ||
| 141 | extern const struct kernel_symbol __start___ksymtab_gpl_future[]; | 140 | extern const struct kernel_symbol __start___ksymtab_gpl_future[]; |
| 142 | extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; | 141 | extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; |
| 143 | extern const unsigned long __start___kcrctab[]; | 142 | extern const unsigned long __start___kcrctab[]; |
| 144 | extern const unsigned long __start___kcrctab_gpl[]; | 143 | extern const unsigned long __start___kcrctab_gpl[]; |
| 145 | extern const unsigned long __start___kcrctab_gpl_future[]; | 144 | extern const unsigned long __start___kcrctab_gpl_future[]; |
| 145 | #ifdef CONFIG_UNUSED_SYMBOLS | ||
| 146 | extern const struct kernel_symbol __start___ksymtab_unused[]; | ||
| 147 | extern const struct kernel_symbol __stop___ksymtab_unused[]; | ||
| 148 | extern const struct kernel_symbol __start___ksymtab_unused_gpl[]; | ||
| 149 | extern const struct kernel_symbol __stop___ksymtab_unused_gpl[]; | ||
| 146 | extern const unsigned long __start___kcrctab_unused[]; | 150 | extern const unsigned long __start___kcrctab_unused[]; |
| 147 | extern const unsigned long __start___kcrctab_unused_gpl[]; | 151 | extern const unsigned long __start___kcrctab_unused_gpl[]; |
| 152 | #endif | ||
| 148 | 153 | ||
| 149 | #ifndef CONFIG_MODVERSIONS | 154 | #ifndef CONFIG_MODVERSIONS |
| 150 | #define symversion(base, idx) NULL | 155 | #define symversion(base, idx) NULL |
| @@ -152,152 +157,170 @@ extern const unsigned long __start___kcrctab_unused_gpl[]; | |||
| 152 | #define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL) | 157 | #define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL) |
| 153 | #endif | 158 | #endif |
| 154 | 159 | ||
| 155 | /* lookup symbol in given range of kernel_symbols */ | ||
| 156 | static const struct kernel_symbol *lookup_symbol(const char *name, | ||
| 157 | const struct kernel_symbol *start, | ||
| 158 | const struct kernel_symbol *stop) | ||
| 159 | { | ||
| 160 | const struct kernel_symbol *ks = start; | ||
| 161 | for (; ks < stop; ks++) | ||
| 162 | if (strcmp(ks->name, name) == 0) | ||
| 163 | return ks; | ||
| 164 | return NULL; | ||
| 165 | } | ||
| 166 | |||
| 167 | static bool always_ok(bool gplok, bool warn, const char *name) | ||
| 168 | { | ||
| 169 | return true; | ||
| 170 | } | ||
| 171 | |||
| 172 | static bool printk_unused_warning(bool gplok, bool warn, const char *name) | ||
| 173 | { | ||
| 174 | if (warn) { | ||
| 175 | printk(KERN_WARNING "Symbol %s is marked as UNUSED, " | ||
| 176 | "however this module is using it.\n", name); | ||
| 177 | printk(KERN_WARNING | ||
| 178 | "This symbol will go away in the future.\n"); | ||
| 179 | printk(KERN_WARNING | ||
| 180 | "Please evalute if this is the right api to use and if " | ||
| 181 | "it really is, submit a report the linux kernel " | ||
| 182 | "mailinglist together with submitting your code for " | ||
| 183 | "inclusion.\n"); | ||
| 184 | } | ||
| 185 | return true; | ||
| 186 | } | ||
| 187 | |||
| 188 | static bool gpl_only_unused_warning(bool gplok, bool warn, const char *name) | ||
| 189 | { | ||
| 190 | if (!gplok) | ||
| 191 | return false; | ||
| 192 | return printk_unused_warning(gplok, warn, name); | ||
| 193 | } | ||
| 194 | |||
| 195 | static bool gpl_only(bool gplok, bool warn, const char *name) | ||
| 196 | { | ||
| 197 | return gplok; | ||
| 198 | } | ||
| 199 | |||
| 200 | static bool warn_if_not_gpl(bool gplok, bool warn, const char *name) | ||
| 201 | { | ||
| 202 | if (!gplok && warn) { | ||
| 203 | printk(KERN_WARNING "Symbol %s is being used " | ||
| 204 | "by a non-GPL module, which will not " | ||
| 205 | "be allowed in the future\n", name); | ||
| 206 | printk(KERN_WARNING "Please see the file " | ||
| 207 | "Documentation/feature-removal-schedule.txt " | ||
| 208 | "in the kernel source tree for more details.\n"); | ||
| 209 | } | ||
| 210 | return true; | ||
| 211 | } | ||
| 212 | |||
| 213 | struct symsearch { | 160 | struct symsearch { |
| 214 | const struct kernel_symbol *start, *stop; | 161 | const struct kernel_symbol *start, *stop; |
| 215 | const unsigned long *crcs; | 162 | const unsigned long *crcs; |
| 216 | bool (*check)(bool gplok, bool warn, const char *name); | 163 | enum { |
| 164 | NOT_GPL_ONLY, | ||
| 165 | GPL_ONLY, | ||
| 166 | WILL_BE_GPL_ONLY, | ||
| 167 | } licence; | ||
| 168 | bool unused; | ||
| 217 | }; | 169 | }; |
| 218 | 170 | ||
| 219 | /* Look through this array of symbol tables for a symbol match which | 171 | static bool each_symbol_in_section(const struct symsearch *arr, |
| 220 | * passes the check function. */ | 172 | unsigned int arrsize, |
| 221 | static const struct kernel_symbol *search_symarrays(const struct symsearch *arr, | 173 | struct module *owner, |
| 222 | unsigned int num, | 174 | bool (*fn)(const struct symsearch *syms, |
| 223 | const char *name, | 175 | struct module *owner, |
| 224 | bool gplok, | 176 | unsigned int symnum, void *data), |
| 225 | bool warn, | 177 | void *data) |
| 226 | const unsigned long **crc) | ||
| 227 | { | 178 | { |
| 228 | unsigned int i; | 179 | unsigned int i, j; |
| 229 | const struct kernel_symbol *ks; | ||
| 230 | |||
| 231 | for (i = 0; i < num; i++) { | ||
| 232 | ks = lookup_symbol(name, arr[i].start, arr[i].stop); | ||
| 233 | if (!ks || !arr[i].check(gplok, warn, name)) | ||
| 234 | continue; | ||
| 235 | 180 | ||
| 236 | if (crc) | 181 | for (j = 0; j < arrsize; j++) { |
| 237 | *crc = symversion(arr[i].crcs, ks - arr[i].start); | 182 | for (i = 0; i < arr[j].stop - arr[j].start; i++) |
| 238 | return ks; | 183 | if (fn(&arr[j], owner, i, data)) |
| 184 | return true; | ||
| 239 | } | 185 | } |
| 240 | return NULL; | 186 | |
| 187 | return false; | ||
| 241 | } | 188 | } |
| 242 | 189 | ||
| 243 | /* Find a symbol, return value, (optional) crc and (optional) module | 190 | /* Returns true as soon as fn returns true, otherwise false. */ |
| 244 | * which owns it */ | 191 | static bool each_symbol(bool (*fn)(const struct symsearch *arr, |
| 245 | static unsigned long find_symbol(const char *name, | 192 | struct module *owner, |
| 246 | struct module **owner, | 193 | unsigned int symnum, void *data), |
| 247 | const unsigned long **crc, | 194 | void *data) |
| 248 | bool gplok, | ||
| 249 | bool warn) | ||
| 250 | { | 195 | { |
| 251 | struct module *mod; | 196 | struct module *mod; |
| 252 | const struct kernel_symbol *ks; | ||
| 253 | const struct symsearch arr[] = { | 197 | const struct symsearch arr[] = { |
| 254 | { __start___ksymtab, __stop___ksymtab, __start___kcrctab, | 198 | { __start___ksymtab, __stop___ksymtab, __start___kcrctab, |
| 255 | always_ok }, | 199 | NOT_GPL_ONLY, false }, |
| 256 | { __start___ksymtab_gpl, __stop___ksymtab_gpl, | 200 | { __start___ksymtab_gpl, __stop___ksymtab_gpl, |
| 257 | __start___kcrctab_gpl, gpl_only }, | 201 | __start___kcrctab_gpl, |
| 202 | GPL_ONLY, false }, | ||
| 258 | { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future, | 203 | { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future, |
| 259 | __start___kcrctab_gpl_future, warn_if_not_gpl }, | 204 | __start___kcrctab_gpl_future, |
| 205 | WILL_BE_GPL_ONLY, false }, | ||
| 206 | #ifdef CONFIG_UNUSED_SYMBOLS | ||
| 260 | { __start___ksymtab_unused, __stop___ksymtab_unused, | 207 | { __start___ksymtab_unused, __stop___ksymtab_unused, |
| 261 | __start___kcrctab_unused, printk_unused_warning }, | 208 | __start___kcrctab_unused, |
| 209 | NOT_GPL_ONLY, true }, | ||
| 262 | { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl, | 210 | { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl, |
| 263 | __start___kcrctab_unused_gpl, gpl_only_unused_warning }, | 211 | __start___kcrctab_unused_gpl, |
| 212 | GPL_ONLY, true }, | ||
| 213 | #endif | ||
| 264 | }; | 214 | }; |
| 265 | 215 | ||
| 266 | /* Core kernel first. */ | 216 | if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data)) |
| 267 | ks = search_symarrays(arr, ARRAY_SIZE(arr), name, gplok, warn, crc); | 217 | return true; |
| 268 | if (ks) { | ||
| 269 | if (owner) | ||
| 270 | *owner = NULL; | ||
| 271 | return ks->value; | ||
| 272 | } | ||
| 273 | 218 | ||
| 274 | /* Now try modules. */ | ||
| 275 | list_for_each_entry(mod, &modules, list) { | 219 | list_for_each_entry(mod, &modules, list) { |
| 276 | struct symsearch arr[] = { | 220 | struct symsearch arr[] = { |
| 277 | { mod->syms, mod->syms + mod->num_syms, mod->crcs, | 221 | { mod->syms, mod->syms + mod->num_syms, mod->crcs, |
| 278 | always_ok }, | 222 | NOT_GPL_ONLY, false }, |
| 279 | { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms, | 223 | { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms, |
| 280 | mod->gpl_crcs, gpl_only }, | 224 | mod->gpl_crcs, |
| 225 | GPL_ONLY, false }, | ||
| 281 | { mod->gpl_future_syms, | 226 | { mod->gpl_future_syms, |
| 282 | mod->gpl_future_syms + mod->num_gpl_future_syms, | 227 | mod->gpl_future_syms + mod->num_gpl_future_syms, |
| 283 | mod->gpl_future_crcs, warn_if_not_gpl }, | 228 | mod->gpl_future_crcs, |
| 229 | WILL_BE_GPL_ONLY, false }, | ||
| 230 | #ifdef CONFIG_UNUSED_SYMBOLS | ||
| 284 | { mod->unused_syms, | 231 | { mod->unused_syms, |
| 285 | mod->unused_syms + mod->num_unused_syms, | 232 | mod->unused_syms + mod->num_unused_syms, |
| 286 | mod->unused_crcs, printk_unused_warning }, | 233 | mod->unused_crcs, |
| 234 | NOT_GPL_ONLY, true }, | ||
| 287 | { mod->unused_gpl_syms, | 235 | { mod->unused_gpl_syms, |
| 288 | mod->unused_gpl_syms + mod->num_unused_gpl_syms, | 236 | mod->unused_gpl_syms + mod->num_unused_gpl_syms, |
| 289 | mod->unused_gpl_crcs, gpl_only_unused_warning }, | 237 | mod->unused_gpl_crcs, |
| 238 | GPL_ONLY, true }, | ||
| 239 | #endif | ||
| 290 | }; | 240 | }; |
| 291 | 241 | ||
| 292 | ks = search_symarrays(arr, ARRAY_SIZE(arr), | 242 | if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data)) |
| 293 | name, gplok, warn, crc); | 243 | return true; |
| 294 | if (ks) { | 244 | } |
| 295 | if (owner) | 245 | return false; |
| 296 | *owner = mod; | 246 | } |
| 297 | return ks->value; | 247 | |
| 248 | struct find_symbol_arg { | ||
| 249 | /* Input */ | ||
| 250 | const char *name; | ||
| 251 | bool gplok; | ||
| 252 | bool warn; | ||
| 253 | |||
| 254 | /* Output */ | ||
| 255 | struct module *owner; | ||
| 256 | const unsigned long *crc; | ||
| 257 | unsigned long value; | ||
| 258 | }; | ||
| 259 | |||
| 260 | static bool find_symbol_in_section(const struct symsearch *syms, | ||
| 261 | struct module *owner, | ||
| 262 | unsigned int symnum, void *data) | ||
| 263 | { | ||
| 264 | struct find_symbol_arg *fsa = data; | ||
| 265 | |||
| 266 | if (strcmp(syms->start[symnum].name, fsa->name) != 0) | ||
| 267 | return false; | ||
| 268 | |||
| 269 | if (!fsa->gplok) { | ||
| 270 | if (syms->licence == GPL_ONLY) | ||
| 271 | return false; | ||
| 272 | if (syms->licence == WILL_BE_GPL_ONLY && fsa->warn) { | ||
| 273 | printk(KERN_WARNING "Symbol %s is being used " | ||
| 274 | "by a non-GPL module, which will not " | ||
| 275 | "be allowed in the future\n", fsa->name); | ||
| 276 | printk(KERN_WARNING "Please see the file " | ||
| 277 | "Documentation/feature-removal-schedule.txt " | ||
| 278 | "in the kernel source tree for more details.\n"); | ||
| 298 | } | 279 | } |
| 299 | } | 280 | } |
| 300 | 281 | ||
| 282 | #ifdef CONFIG_UNUSED_SYMBOLS | ||
| 283 | if (syms->unused && fsa->warn) { | ||
| 284 | printk(KERN_WARNING "Symbol %s is marked as UNUSED, " | ||
| 285 | "however this module is using it.\n", fsa->name); | ||
| 286 | printk(KERN_WARNING | ||
| 287 | "This symbol will go away in the future.\n"); | ||
| 288 | printk(KERN_WARNING | ||
| 289 | "Please evalute if this is the right api to use and if " | ||
| 290 | "it really is, submit a report the linux kernel " | ||
| 291 | "mailinglist together with submitting your code for " | ||
| 292 | "inclusion.\n"); | ||
| 293 | } | ||
| 294 | #endif | ||
| 295 | |||
| 296 | fsa->owner = owner; | ||
| 297 | fsa->crc = symversion(syms->crcs, symnum); | ||
| 298 | fsa->value = syms->start[symnum].value; | ||
| 299 | return true; | ||
| 300 | } | ||
| 301 | |||
| 302 | /* Find a symbol, return value, (optional) crc and (optional) module | ||
| 303 | * which owns it */ | ||
| 304 | static unsigned long find_symbol(const char *name, | ||
| 305 | struct module **owner, | ||
| 306 | const unsigned long **crc, | ||
| 307 | bool gplok, | ||
| 308 | bool warn) | ||
| 309 | { | ||
| 310 | struct find_symbol_arg fsa; | ||
| 311 | |||
| 312 | fsa.name = name; | ||
| 313 | fsa.gplok = gplok; | ||
| 314 | fsa.warn = warn; | ||
| 315 | |||
| 316 | if (each_symbol(find_symbol_in_section, &fsa)) { | ||
| 317 | if (owner) | ||
| 318 | *owner = fsa.owner; | ||
| 319 | if (crc) | ||
| 320 | *crc = fsa.crc; | ||
| 321 | return fsa.value; | ||
| 322 | } | ||
| 323 | |||
| 301 | DEBUGP("Failed to find symbol %s\n", name); | 324 | DEBUGP("Failed to find symbol %s\n", name); |
| 302 | return -ENOENT; | 325 | return -ENOENT; |
| 303 | } | 326 | } |
| @@ -639,8 +662,8 @@ static int __try_stop_module(void *_sref) | |||
| 639 | { | 662 | { |
| 640 | struct stopref *sref = _sref; | 663 | struct stopref *sref = _sref; |
| 641 | 664 | ||
| 642 | /* If it's not unused, quit unless we are told to block. */ | 665 | /* If it's not unused, quit unless we're forcing. */ |
| 643 | if ((sref->flags & O_NONBLOCK) && module_refcount(sref->mod) != 0) { | 666 | if (module_refcount(sref->mod) != 0) { |
| 644 | if (!(*sref->forced = try_force_unload(sref->flags))) | 667 | if (!(*sref->forced = try_force_unload(sref->flags))) |
| 645 | return -EWOULDBLOCK; | 668 | return -EWOULDBLOCK; |
| 646 | } | 669 | } |
| @@ -652,9 +675,16 @@ static int __try_stop_module(void *_sref) | |||
| 652 | 675 | ||
| 653 | static int try_stop_module(struct module *mod, int flags, int *forced) | 676 | static int try_stop_module(struct module *mod, int flags, int *forced) |
| 654 | { | 677 | { |
| 655 | struct stopref sref = { mod, flags, forced }; | 678 | if (flags & O_NONBLOCK) { |
| 679 | struct stopref sref = { mod, flags, forced }; | ||
| 656 | 680 | ||
| 657 | return stop_machine_run(__try_stop_module, &sref, NR_CPUS); | 681 | return stop_machine(__try_stop_module, &sref, NULL); |
| 682 | } else { | ||
| 683 | /* We don't need to stop the machine for this. */ | ||
| 684 | mod->state = MODULE_STATE_GOING; | ||
| 685 | synchronize_sched(); | ||
| 686 | return 0; | ||
| 687 | } | ||
| 658 | } | 688 | } |
| 659 | 689 | ||
| 660 | unsigned int module_refcount(struct module *mod) | 690 | unsigned int module_refcount(struct module *mod) |
| @@ -1386,7 +1416,7 @@ static int __unlink_module(void *_mod) | |||
| 1386 | static void free_module(struct module *mod) | 1416 | static void free_module(struct module *mod) |
| 1387 | { | 1417 | { |
| 1388 | /* Delete from various lists */ | 1418 | /* Delete from various lists */ |
| 1389 | stop_machine_run(__unlink_module, mod, NR_CPUS); | 1419 | stop_machine(__unlink_module, mod, NULL); |
| 1390 | remove_notes_attrs(mod); | 1420 | remove_notes_attrs(mod); |
| 1391 | remove_sect_attrs(mod); | 1421 | remove_sect_attrs(mod); |
| 1392 | mod_kobject_remove(mod); | 1422 | mod_kobject_remove(mod); |
| @@ -1445,8 +1475,10 @@ static int verify_export_symbols(struct module *mod) | |||
| 1445 | { mod->syms, mod->num_syms }, | 1475 | { mod->syms, mod->num_syms }, |
| 1446 | { mod->gpl_syms, mod->num_gpl_syms }, | 1476 | { mod->gpl_syms, mod->num_gpl_syms }, |
| 1447 | { mod->gpl_future_syms, mod->num_gpl_future_syms }, | 1477 | { mod->gpl_future_syms, mod->num_gpl_future_syms }, |
| 1478 | #ifdef CONFIG_UNUSED_SYMBOLS | ||
| 1448 | { mod->unused_syms, mod->num_unused_syms }, | 1479 | { mod->unused_syms, mod->num_unused_syms }, |
| 1449 | { mod->unused_gpl_syms, mod->num_unused_gpl_syms }, | 1480 | { mod->unused_gpl_syms, mod->num_unused_gpl_syms }, |
| 1481 | #endif | ||
| 1450 | }; | 1482 | }; |
| 1451 | 1483 | ||
| 1452 | for (i = 0; i < ARRAY_SIZE(arr); i++) { | 1484 | for (i = 0; i < ARRAY_SIZE(arr); i++) { |
| @@ -1526,7 +1558,7 @@ static int simplify_symbols(Elf_Shdr *sechdrs, | |||
| 1526 | } | 1558 | } |
| 1527 | 1559 | ||
| 1528 | /* Update size with this section: return offset. */ | 1560 | /* Update size with this section: return offset. */ |
| 1529 | static long get_offset(unsigned long *size, Elf_Shdr *sechdr) | 1561 | static long get_offset(unsigned int *size, Elf_Shdr *sechdr) |
| 1530 | { | 1562 | { |
| 1531 | long ret; | 1563 | long ret; |
| 1532 | 1564 | ||
| @@ -1659,6 +1691,19 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, | |||
| 1659 | } | 1691 | } |
| 1660 | 1692 | ||
| 1661 | #ifdef CONFIG_KALLSYMS | 1693 | #ifdef CONFIG_KALLSYMS |
| 1694 | |||
| 1695 | /* lookup symbol in given range of kernel_symbols */ | ||
| 1696 | static const struct kernel_symbol *lookup_symbol(const char *name, | ||
| 1697 | const struct kernel_symbol *start, | ||
| 1698 | const struct kernel_symbol *stop) | ||
| 1699 | { | ||
| 1700 | const struct kernel_symbol *ks = start; | ||
| 1701 | for (; ks < stop; ks++) | ||
| 1702 | if (strcmp(ks->name, name) == 0) | ||
| 1703 | return ks; | ||
| 1704 | return NULL; | ||
| 1705 | } | ||
| 1706 | |||
| 1662 | static int is_exported(const char *name, const struct module *mod) | 1707 | static int is_exported(const char *name, const struct module *mod) |
| 1663 | { | 1708 | { |
| 1664 | if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab)) | 1709 | if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab)) |
| @@ -1738,6 +1783,20 @@ static inline void add_kallsyms(struct module *mod, | |||
| 1738 | } | 1783 | } |
| 1739 | #endif /* CONFIG_KALLSYMS */ | 1784 | #endif /* CONFIG_KALLSYMS */ |
| 1740 | 1785 | ||
| 1786 | static void *module_alloc_update_bounds(unsigned long size) | ||
| 1787 | { | ||
| 1788 | void *ret = module_alloc(size); | ||
| 1789 | |||
| 1790 | if (ret) { | ||
| 1791 | /* Update module bounds. */ | ||
| 1792 | if ((unsigned long)ret < module_addr_min) | ||
| 1793 | module_addr_min = (unsigned long)ret; | ||
| 1794 | if ((unsigned long)ret + size > module_addr_max) | ||
| 1795 | module_addr_max = (unsigned long)ret + size; | ||
| 1796 | } | ||
| 1797 | return ret; | ||
| 1798 | } | ||
| 1799 | |||
| 1741 | /* Allocate and load the module: note that size of section 0 is always | 1800 | /* Allocate and load the module: note that size of section 0 is always |
| 1742 | zero, and we rely on this for optional sections. */ | 1801 | zero, and we rely on this for optional sections. */ |
| 1743 | static struct module *load_module(void __user *umod, | 1802 | static struct module *load_module(void __user *umod, |
| @@ -1764,10 +1823,12 @@ static struct module *load_module(void __user *umod, | |||
| 1764 | unsigned int gplfutureindex; | 1823 | unsigned int gplfutureindex; |
| 1765 | unsigned int gplfuturecrcindex; | 1824 | unsigned int gplfuturecrcindex; |
| 1766 | unsigned int unwindex = 0; | 1825 | unsigned int unwindex = 0; |
| 1826 | #ifdef CONFIG_UNUSED_SYMBOLS | ||
| 1767 | unsigned int unusedindex; | 1827 | unsigned int unusedindex; |
| 1768 | unsigned int unusedcrcindex; | 1828 | unsigned int unusedcrcindex; |
| 1769 | unsigned int unusedgplindex; | 1829 | unsigned int unusedgplindex; |
| 1770 | unsigned int unusedgplcrcindex; | 1830 | unsigned int unusedgplcrcindex; |
| 1831 | #endif | ||
| 1771 | unsigned int markersindex; | 1832 | unsigned int markersindex; |
| 1772 | unsigned int markersstringsindex; | 1833 | unsigned int markersstringsindex; |
| 1773 | struct module *mod; | 1834 | struct module *mod; |
| @@ -1850,13 +1911,15 @@ static struct module *load_module(void __user *umod, | |||
| 1850 | exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); | 1911 | exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); |
| 1851 | gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); | 1912 | gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); |
| 1852 | gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future"); | 1913 | gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future"); |
| 1853 | unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused"); | ||
| 1854 | unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl"); | ||
| 1855 | crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); | 1914 | crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); |
| 1856 | gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); | 1915 | gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); |
| 1857 | gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future"); | 1916 | gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future"); |
| 1917 | #ifdef CONFIG_UNUSED_SYMBOLS | ||
| 1918 | unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused"); | ||
| 1919 | unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl"); | ||
| 1858 | unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused"); | 1920 | unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused"); |
| 1859 | unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl"); | 1921 | unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl"); |
| 1922 | #endif | ||
| 1860 | setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); | 1923 | setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); |
| 1861 | exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); | 1924 | exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); |
| 1862 | obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); | 1925 | obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); |
| @@ -1935,7 +1998,7 @@ static struct module *load_module(void __user *umod, | |||
| 1935 | layout_sections(mod, hdr, sechdrs, secstrings); | 1998 | layout_sections(mod, hdr, sechdrs, secstrings); |
| 1936 | 1999 | ||
| 1937 | /* Do the allocs. */ | 2000 | /* Do the allocs. */ |
| 1938 | ptr = module_alloc(mod->core_size); | 2001 | ptr = module_alloc_update_bounds(mod->core_size); |
| 1939 | if (!ptr) { | 2002 | if (!ptr) { |
| 1940 | err = -ENOMEM; | 2003 | err = -ENOMEM; |
| 1941 | goto free_percpu; | 2004 | goto free_percpu; |
| @@ -1943,7 +2006,7 @@ static struct module *load_module(void __user *umod, | |||
| 1943 | memset(ptr, 0, mod->core_size); | 2006 | memset(ptr, 0, mod->core_size); |
| 1944 | mod->module_core = ptr; | 2007 | mod->module_core = ptr; |
| 1945 | 2008 | ||
| 1946 | ptr = module_alloc(mod->init_size); | 2009 | ptr = module_alloc_update_bounds(mod->init_size); |
| 1947 | if (!ptr && mod->init_size) { | 2010 | if (!ptr && mod->init_size) { |
| 1948 | err = -ENOMEM; | 2011 | err = -ENOMEM; |
| 1949 | goto free_core; | 2012 | goto free_core; |
| @@ -2018,14 +2081,15 @@ static struct module *load_module(void __user *umod, | |||
| 2018 | mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; | 2081 | mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; |
| 2019 | mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size / | 2082 | mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size / |
| 2020 | sizeof(*mod->gpl_future_syms); | 2083 | sizeof(*mod->gpl_future_syms); |
| 2021 | mod->num_unused_syms = sechdrs[unusedindex].sh_size / | ||
| 2022 | sizeof(*mod->unused_syms); | ||
| 2023 | mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size / | ||
| 2024 | sizeof(*mod->unused_gpl_syms); | ||
| 2025 | mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; | 2084 | mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; |
| 2026 | if (gplfuturecrcindex) | 2085 | if (gplfuturecrcindex) |
| 2027 | mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; | 2086 | mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; |
| 2028 | 2087 | ||
| 2088 | #ifdef CONFIG_UNUSED_SYMBOLS | ||
| 2089 | mod->num_unused_syms = sechdrs[unusedindex].sh_size / | ||
| 2090 | sizeof(*mod->unused_syms); | ||
| 2091 | mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size / | ||
| 2092 | sizeof(*mod->unused_gpl_syms); | ||
| 2029 | mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr; | 2093 | mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr; |
| 2030 | if (unusedcrcindex) | 2094 | if (unusedcrcindex) |
| 2031 | mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; | 2095 | mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; |
| @@ -2033,13 +2097,17 @@ static struct module *load_module(void __user *umod, | |||
| 2033 | if (unusedgplcrcindex) | 2097 | if (unusedgplcrcindex) |
| 2034 | mod->unused_gpl_crcs | 2098 | mod->unused_gpl_crcs |
| 2035 | = (void *)sechdrs[unusedgplcrcindex].sh_addr; | 2099 | = (void *)sechdrs[unusedgplcrcindex].sh_addr; |
| 2100 | #endif | ||
| 2036 | 2101 | ||
| 2037 | #ifdef CONFIG_MODVERSIONS | 2102 | #ifdef CONFIG_MODVERSIONS |
| 2038 | if ((mod->num_syms && !crcindex) || | 2103 | if ((mod->num_syms && !crcindex) |
| 2039 | (mod->num_gpl_syms && !gplcrcindex) || | 2104 | || (mod->num_gpl_syms && !gplcrcindex) |
| 2040 | (mod->num_gpl_future_syms && !gplfuturecrcindex) || | 2105 | || (mod->num_gpl_future_syms && !gplfuturecrcindex) |
| 2041 | (mod->num_unused_syms && !unusedcrcindex) || | 2106 | #ifdef CONFIG_UNUSED_SYMBOLS |
| 2042 | (mod->num_unused_gpl_syms && !unusedgplcrcindex)) { | 2107 | || (mod->num_unused_syms && !unusedcrcindex) |
| 2108 | || (mod->num_unused_gpl_syms && !unusedgplcrcindex) | ||
| 2109 | #endif | ||
| 2110 | ) { | ||
| 2043 | printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name); | 2111 | printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name); |
| 2044 | err = try_to_force_load(mod, "nocrc"); | 2112 | err = try_to_force_load(mod, "nocrc"); |
| 2045 | if (err) | 2113 | if (err) |
| @@ -2129,7 +2197,7 @@ static struct module *load_module(void __user *umod, | |||
| 2129 | /* Now sew it into the lists so we can get lockdep and oops | 2197 | /* Now sew it into the lists so we can get lockdep and oops |
| 2130 | * info during argument parsing. Noone should access us, since | 2198 | * info during argument parsing. Noone should access us, since |
| 2131 | * strong_try_module_get() will fail. */ | 2199 | * strong_try_module_get() will fail. */ |
| 2132 | stop_machine_run(__link_module, mod, NR_CPUS); | 2200 | stop_machine(__link_module, mod, NULL); |
| 2133 | 2201 | ||
| 2134 | /* Size of section 0 is 0, so this works well if no params */ | 2202 | /* Size of section 0 is 0, so this works well if no params */ |
| 2135 | err = parse_args(mod->name, mod->args, | 2203 | err = parse_args(mod->name, mod->args, |
| @@ -2163,7 +2231,7 @@ static struct module *load_module(void __user *umod, | |||
| 2163 | return mod; | 2231 | return mod; |
| 2164 | 2232 | ||
| 2165 | unlink: | 2233 | unlink: |
| 2166 | stop_machine_run(__unlink_module, mod, NR_CPUS); | 2234 | stop_machine(__unlink_module, mod, NULL); |
| 2167 | module_arch_cleanup(mod); | 2235 | module_arch_cleanup(mod); |
| 2168 | cleanup: | 2236 | cleanup: |
| 2169 | kobject_del(&mod->mkobj.kobj); | 2237 | kobject_del(&mod->mkobj.kobj); |
| @@ -2512,7 +2580,7 @@ static int m_show(struct seq_file *m, void *p) | |||
| 2512 | struct module *mod = list_entry(p, struct module, list); | 2580 | struct module *mod = list_entry(p, struct module, list); |
| 2513 | char buf[8]; | 2581 | char buf[8]; |
| 2514 | 2582 | ||
| 2515 | seq_printf(m, "%s %lu", | 2583 | seq_printf(m, "%s %u", |
| 2516 | mod->name, mod->init_size + mod->core_size); | 2584 | mod->name, mod->init_size + mod->core_size); |
| 2517 | print_unload_info(m, mod); | 2585 | print_unload_info(m, mod); |
| 2518 | 2586 | ||
| @@ -2595,6 +2663,9 @@ struct module *__module_text_address(unsigned long addr) | |||
| 2595 | { | 2663 | { |
| 2596 | struct module *mod; | 2664 | struct module *mod; |
| 2597 | 2665 | ||
| 2666 | if (addr < module_addr_min || addr > module_addr_max) | ||
| 2667 | return NULL; | ||
| 2668 | |||
| 2598 | list_for_each_entry(mod, &modules, list) | 2669 | list_for_each_entry(mod, &modules, list) |
| 2599 | if (within(addr, mod->module_init, mod->init_text_size) | 2670 | if (within(addr, mod->module_init, mod->init_text_size) |
| 2600 | || within(addr, mod->module_core, mod->core_text_size)) | 2671 | || within(addr, mod->module_core, mod->core_text_size)) |
