diff options
author | David S. Miller <davem@davemloft.net> | 2010-01-23 01:45:46 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-01-23 01:45:46 -0500 |
commit | 6be325719b3e54624397e413efd4b33a997e55a3 (patch) | |
tree | 57f321a56794cab2222e179b16731e0d76a4a68a /kernel/module.c | |
parent | 26d92f9276a56d55511a427fb70bd70886af647a (diff) | |
parent | 92dcffb916d309aa01778bf8963a6932e4014d07 (diff) |
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 208 |
1 files changed, 39 insertions, 169 deletions
diff --git a/kernel/module.c b/kernel/module.c index 5842a71cf052..f82386bd9ee9 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -370,8 +370,6 @@ EXPORT_SYMBOL_GPL(find_module); | |||
370 | 370 | ||
371 | #ifdef CONFIG_SMP | 371 | #ifdef CONFIG_SMP |
372 | 372 | ||
373 | #ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA | ||
374 | |||
375 | static void *percpu_modalloc(unsigned long size, unsigned long align, | 373 | static void *percpu_modalloc(unsigned long size, unsigned long align, |
376 | const char *name) | 374 | const char *name) |
377 | { | 375 | { |
@@ -395,154 +393,6 @@ static void percpu_modfree(void *freeme) | |||
395 | free_percpu(freeme); | 393 | free_percpu(freeme); |
396 | } | 394 | } |
397 | 395 | ||
398 | #else /* ... CONFIG_HAVE_LEGACY_PER_CPU_AREA */ | ||
399 | |||
400 | /* Number of blocks used and allocated. */ | ||
401 | static unsigned int pcpu_num_used, pcpu_num_allocated; | ||
402 | /* Size of each block. -ve means used. */ | ||
403 | static int *pcpu_size; | ||
404 | |||
405 | static int split_block(unsigned int i, unsigned short size) | ||
406 | { | ||
407 | /* Reallocation required? */ | ||
408 | if (pcpu_num_used + 1 > pcpu_num_allocated) { | ||
409 | int *new; | ||
410 | |||
411 | new = krealloc(pcpu_size, sizeof(new[0])*pcpu_num_allocated*2, | ||
412 | GFP_KERNEL); | ||
413 | if (!new) | ||
414 | return 0; | ||
415 | |||
416 | pcpu_num_allocated *= 2; | ||
417 | pcpu_size = new; | ||
418 | } | ||
419 | |||
420 | /* Insert a new subblock */ | ||
421 | memmove(&pcpu_size[i+1], &pcpu_size[i], | ||
422 | sizeof(pcpu_size[0]) * (pcpu_num_used - i)); | ||
423 | pcpu_num_used++; | ||
424 | |||
425 | pcpu_size[i+1] -= size; | ||
426 | pcpu_size[i] = size; | ||
427 | return 1; | ||
428 | } | ||
429 | |||
430 | static inline unsigned int block_size(int val) | ||
431 | { | ||
432 | if (val < 0) | ||
433 | return -val; | ||
434 | return val; | ||
435 | } | ||
436 | |||
437 | static void *percpu_modalloc(unsigned long size, unsigned long align, | ||
438 | const char *name) | ||
439 | { | ||
440 | unsigned long extra; | ||
441 | unsigned int i; | ||
442 | void *ptr; | ||
443 | int cpu; | ||
444 | |||
445 | if (align > PAGE_SIZE) { | ||
446 | printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n", | ||
447 | name, align, PAGE_SIZE); | ||
448 | align = PAGE_SIZE; | ||
449 | } | ||
450 | |||
451 | ptr = __per_cpu_start; | ||
452 | for (i = 0; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) { | ||
453 | /* Extra for alignment requirement. */ | ||
454 | extra = ALIGN((unsigned long)ptr, align) - (unsigned long)ptr; | ||
455 | BUG_ON(i == 0 && extra != 0); | ||
456 | |||
457 | if (pcpu_size[i] < 0 || pcpu_size[i] < extra + size) | ||
458 | continue; | ||
459 | |||
460 | /* Transfer extra to previous block. */ | ||
461 | if (pcpu_size[i-1] < 0) | ||
462 | pcpu_size[i-1] -= extra; | ||
463 | else | ||
464 | pcpu_size[i-1] += extra; | ||
465 | pcpu_size[i] -= extra; | ||
466 | ptr += extra; | ||
467 | |||
468 | /* Split block if warranted */ | ||
469 | if (pcpu_size[i] - size > sizeof(unsigned long)) | ||
470 | if (!split_block(i, size)) | ||
471 | return NULL; | ||
472 | |||
473 | /* add the per-cpu scanning areas */ | ||
474 | for_each_possible_cpu(cpu) | ||
475 | kmemleak_alloc(ptr + per_cpu_offset(cpu), size, 0, | ||
476 | GFP_KERNEL); | ||
477 | |||
478 | /* Mark allocated */ | ||
479 | pcpu_size[i] = -pcpu_size[i]; | ||
480 | return ptr; | ||
481 | } | ||
482 | |||
483 | printk(KERN_WARNING "Could not allocate %lu bytes percpu data\n", | ||
484 | size); | ||
485 | return NULL; | ||
486 | } | ||
487 | |||
488 | static void percpu_modfree(void *freeme) | ||
489 | { | ||
490 | unsigned int i; | ||
491 | void *ptr = __per_cpu_start + block_size(pcpu_size[0]); | ||
492 | int cpu; | ||
493 | |||
494 | /* First entry is core kernel percpu data. */ | ||
495 | for (i = 1; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) { | ||
496 | if (ptr == freeme) { | ||
497 | pcpu_size[i] = -pcpu_size[i]; | ||
498 | goto free; | ||
499 | } | ||
500 | } | ||
501 | BUG(); | ||
502 | |||
503 | free: | ||
504 | /* remove the per-cpu scanning areas */ | ||
505 | for_each_possible_cpu(cpu) | ||
506 | kmemleak_free(freeme + per_cpu_offset(cpu)); | ||
507 | |||
508 | /* Merge with previous? */ | ||
509 | if (pcpu_size[i-1] >= 0) { | ||
510 | pcpu_size[i-1] += pcpu_size[i]; | ||
511 | pcpu_num_used--; | ||
512 | memmove(&pcpu_size[i], &pcpu_size[i+1], | ||
513 | (pcpu_num_used - i) * sizeof(pcpu_size[0])); | ||
514 | i--; | ||
515 | } | ||
516 | /* Merge with next? */ | ||
517 | if (i+1 < pcpu_num_used && pcpu_size[i+1] >= 0) { | ||
518 | pcpu_size[i] += pcpu_size[i+1]; | ||
519 | pcpu_num_used--; | ||
520 | memmove(&pcpu_size[i+1], &pcpu_size[i+2], | ||
521 | (pcpu_num_used - (i+1)) * sizeof(pcpu_size[0])); | ||
522 | } | ||
523 | } | ||
524 | |||
525 | static int percpu_modinit(void) | ||
526 | { | ||
527 | pcpu_num_used = 2; | ||
528 | pcpu_num_allocated = 2; | ||
529 | pcpu_size = kmalloc(sizeof(pcpu_size[0]) * pcpu_num_allocated, | ||
530 | GFP_KERNEL); | ||
531 | /* Static in-kernel percpu data (used). */ | ||
532 | pcpu_size[0] = -(__per_cpu_end-__per_cpu_start); | ||
533 | /* Free room. */ | ||
534 | pcpu_size[1] = PERCPU_ENOUGH_ROOM + pcpu_size[0]; | ||
535 | if (pcpu_size[1] < 0) { | ||
536 | printk(KERN_ERR "No per-cpu room for modules.\n"); | ||
537 | pcpu_num_used = 1; | ||
538 | } | ||
539 | |||
540 | return 0; | ||
541 | } | ||
542 | __initcall(percpu_modinit); | ||
543 | |||
544 | #endif /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */ | ||
545 | |||
546 | static unsigned int find_pcpusec(Elf_Ehdr *hdr, | 396 | static unsigned int find_pcpusec(Elf_Ehdr *hdr, |
547 | Elf_Shdr *sechdrs, | 397 | Elf_Shdr *sechdrs, |
548 | const char *secstrings) | 398 | const char *secstrings) |
@@ -1030,11 +880,23 @@ static int try_to_force_load(struct module *mod, const char *reason) | |||
1030 | } | 880 | } |
1031 | 881 | ||
1032 | #ifdef CONFIG_MODVERSIONS | 882 | #ifdef CONFIG_MODVERSIONS |
883 | /* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */ | ||
884 | static unsigned long maybe_relocated(unsigned long crc, | ||
885 | const struct module *crc_owner) | ||
886 | { | ||
887 | #ifdef ARCH_RELOCATES_KCRCTAB | ||
888 | if (crc_owner == NULL) | ||
889 | return crc - (unsigned long)reloc_start; | ||
890 | #endif | ||
891 | return crc; | ||
892 | } | ||
893 | |||
1033 | static int check_version(Elf_Shdr *sechdrs, | 894 | static int check_version(Elf_Shdr *sechdrs, |
1034 | unsigned int versindex, | 895 | unsigned int versindex, |
1035 | const char *symname, | 896 | const char *symname, |
1036 | struct module *mod, | 897 | struct module *mod, |
1037 | const unsigned long *crc) | 898 | const unsigned long *crc, |
899 | const struct module *crc_owner) | ||
1038 | { | 900 | { |
1039 | unsigned int i, num_versions; | 901 | unsigned int i, num_versions; |
1040 | struct modversion_info *versions; | 902 | struct modversion_info *versions; |
@@ -1055,10 +917,10 @@ static int check_version(Elf_Shdr *sechdrs, | |||
1055 | if (strcmp(versions[i].name, symname) != 0) | 917 | if (strcmp(versions[i].name, symname) != 0) |
1056 | continue; | 918 | continue; |
1057 | 919 | ||
1058 | if (versions[i].crc == *crc) | 920 | if (versions[i].crc == maybe_relocated(*crc, crc_owner)) |
1059 | return 1; | 921 | return 1; |
1060 | DEBUGP("Found checksum %lX vs module %lX\n", | 922 | DEBUGP("Found checksum %lX vs module %lX\n", |
1061 | *crc, versions[i].crc); | 923 | maybe_relocated(*crc, crc_owner), versions[i].crc); |
1062 | goto bad_version; | 924 | goto bad_version; |
1063 | } | 925 | } |
1064 | 926 | ||
@@ -1081,7 +943,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, | |||
1081 | if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL, | 943 | if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL, |
1082 | &crc, true, false)) | 944 | &crc, true, false)) |
1083 | BUG(); | 945 | BUG(); |
1084 | return check_version(sechdrs, versindex, "module_layout", mod, crc); | 946 | return check_version(sechdrs, versindex, "module_layout", mod, crc, |
947 | NULL); | ||
1085 | } | 948 | } |
1086 | 949 | ||
1087 | /* First part is kernel version, which we ignore if module has crcs. */ | 950 | /* First part is kernel version, which we ignore if module has crcs. */ |
@@ -1099,7 +962,8 @@ static inline int check_version(Elf_Shdr *sechdrs, | |||
1099 | unsigned int versindex, | 962 | unsigned int versindex, |
1100 | const char *symname, | 963 | const char *symname, |
1101 | struct module *mod, | 964 | struct module *mod, |
1102 | const unsigned long *crc) | 965 | const unsigned long *crc, |
966 | const struct module *crc_owner) | ||
1103 | { | 967 | { |
1104 | return 1; | 968 | return 1; |
1105 | } | 969 | } |
@@ -1134,8 +998,8 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, | |||
1134 | /* use_module can fail due to OOM, | 998 | /* use_module can fail due to OOM, |
1135 | or module initialization or unloading */ | 999 | or module initialization or unloading */ |
1136 | if (sym) { | 1000 | if (sym) { |
1137 | if (!check_version(sechdrs, versindex, name, mod, crc) || | 1001 | if (!check_version(sechdrs, versindex, name, mod, crc, owner) |
1138 | !use_module(mod, owner)) | 1002 | || !use_module(mod, owner)) |
1139 | sym = NULL; | 1003 | sym = NULL; |
1140 | } | 1004 | } |
1141 | return sym; | 1005 | return sym; |
@@ -1146,6 +1010,12 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, | |||
1146 | * J. Corbet <corbet@lwn.net> | 1010 | * J. Corbet <corbet@lwn.net> |
1147 | */ | 1011 | */ |
1148 | #if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS) | 1012 | #if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS) |
1013 | |||
1014 | static inline bool sect_empty(const Elf_Shdr *sect) | ||
1015 | { | ||
1016 | return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0; | ||
1017 | } | ||
1018 | |||
1149 | struct module_sect_attr | 1019 | struct module_sect_attr |
1150 | { | 1020 | { |
1151 | struct module_attribute mattr; | 1021 | struct module_attribute mattr; |
@@ -1187,8 +1057,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, | |||
1187 | 1057 | ||
1188 | /* Count loaded sections and allocate structures */ | 1058 | /* Count loaded sections and allocate structures */ |
1189 | for (i = 0; i < nsect; i++) | 1059 | for (i = 0; i < nsect; i++) |
1190 | if (sechdrs[i].sh_flags & SHF_ALLOC | 1060 | if (!sect_empty(&sechdrs[i])) |
1191 | && sechdrs[i].sh_size) | ||
1192 | nloaded++; | 1061 | nloaded++; |
1193 | size[0] = ALIGN(sizeof(*sect_attrs) | 1062 | size[0] = ALIGN(sizeof(*sect_attrs) |
1194 | + nloaded * sizeof(sect_attrs->attrs[0]), | 1063 | + nloaded * sizeof(sect_attrs->attrs[0]), |
@@ -1206,9 +1075,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, | |||
1206 | sattr = §_attrs->attrs[0]; | 1075 | sattr = §_attrs->attrs[0]; |
1207 | gattr = §_attrs->grp.attrs[0]; | 1076 | gattr = §_attrs->grp.attrs[0]; |
1208 | for (i = 0; i < nsect; i++) { | 1077 | for (i = 0; i < nsect; i++) { |
1209 | if (! (sechdrs[i].sh_flags & SHF_ALLOC)) | 1078 | if (sect_empty(&sechdrs[i])) |
1210 | continue; | ||
1211 | if (!sechdrs[i].sh_size) | ||
1212 | continue; | 1079 | continue; |
1213 | sattr->address = sechdrs[i].sh_addr; | 1080 | sattr->address = sechdrs[i].sh_addr; |
1214 | sattr->name = kstrdup(secstrings + sechdrs[i].sh_name, | 1081 | sattr->name = kstrdup(secstrings + sechdrs[i].sh_name, |
@@ -1292,7 +1159,7 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect, | |||
1292 | /* Count notes sections and allocate structures. */ | 1159 | /* Count notes sections and allocate structures. */ |
1293 | notes = 0; | 1160 | notes = 0; |
1294 | for (i = 0; i < nsect; i++) | 1161 | for (i = 0; i < nsect; i++) |
1295 | if ((sechdrs[i].sh_flags & SHF_ALLOC) && | 1162 | if (!sect_empty(&sechdrs[i]) && |
1296 | (sechdrs[i].sh_type == SHT_NOTE)) | 1163 | (sechdrs[i].sh_type == SHT_NOTE)) |
1297 | ++notes; | 1164 | ++notes; |
1298 | 1165 | ||
@@ -1308,7 +1175,7 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect, | |||
1308 | notes_attrs->notes = notes; | 1175 | notes_attrs->notes = notes; |
1309 | nattr = ¬es_attrs->attrs[0]; | 1176 | nattr = ¬es_attrs->attrs[0]; |
1310 | for (loaded = i = 0; i < nsect; ++i) { | 1177 | for (loaded = i = 0; i < nsect; ++i) { |
1311 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) | 1178 | if (sect_empty(&sechdrs[i])) |
1312 | continue; | 1179 | continue; |
1313 | if (sechdrs[i].sh_type == SHT_NOTE) { | 1180 | if (sechdrs[i].sh_type == SHT_NOTE) { |
1314 | nattr->attr.name = mod->sect_attrs->attrs[loaded].name; | 1181 | nattr->attr.name = mod->sect_attrs->attrs[loaded].name; |
@@ -2046,9 +1913,7 @@ static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, | |||
2046 | unsigned int i; | 1913 | unsigned int i; |
2047 | 1914 | ||
2048 | /* only scan the sections containing data */ | 1915 | /* only scan the sections containing data */ |
2049 | kmemleak_scan_area(mod->module_core, (unsigned long)mod - | 1916 | kmemleak_scan_area(mod, sizeof(struct module), GFP_KERNEL); |
2050 | (unsigned long)mod->module_core, | ||
2051 | sizeof(struct module), GFP_KERNEL); | ||
2052 | 1917 | ||
2053 | for (i = 1; i < hdr->e_shnum; i++) { | 1918 | for (i = 1; i < hdr->e_shnum; i++) { |
2054 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) | 1919 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) |
@@ -2057,8 +1922,7 @@ static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, | |||
2057 | && strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) != 0) | 1922 | && strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) != 0) |
2058 | continue; | 1923 | continue; |
2059 | 1924 | ||
2060 | kmemleak_scan_area(mod->module_core, sechdrs[i].sh_addr - | 1925 | kmemleak_scan_area((void *)sechdrs[i].sh_addr, |
2061 | (unsigned long)mod->module_core, | ||
2062 | sechdrs[i].sh_size, GFP_KERNEL); | 1926 | sechdrs[i].sh_size, GFP_KERNEL); |
2063 | } | 1927 | } |
2064 | } | 1928 | } |
@@ -2386,6 +2250,12 @@ static noinline struct module *load_module(void __user *umod, | |||
2386 | "_ftrace_events", | 2250 | "_ftrace_events", |
2387 | sizeof(*mod->trace_events), | 2251 | sizeof(*mod->trace_events), |
2388 | &mod->num_trace_events); | 2252 | &mod->num_trace_events); |
2253 | /* | ||
2254 | * This section contains pointers to allocated objects in the trace | ||
2255 | * code and not scanning it leads to false positives. | ||
2256 | */ | ||
2257 | kmemleak_scan_area(mod->trace_events, sizeof(*mod->trace_events) * | ||
2258 | mod->num_trace_events, GFP_KERNEL); | ||
2389 | #endif | 2259 | #endif |
2390 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD | 2260 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD |
2391 | /* sechdrs[0].sh_size is always zero */ | 2261 | /* sechdrs[0].sh_size is always zero */ |