diff options
| -rw-r--r-- | arch/parisc/include/asm/module.h | 6 | ||||
| -rw-r--r-- | arch/parisc/kernel/module.c | 216 | ||||
| -rw-r--r-- | include/linux/moduleloader.h | 3 | ||||
| -rw-r--r-- | include/linux/stop_machine.h | 22 | ||||
| -rw-r--r-- | init/Kconfig | 6 | ||||
| -rw-r--r-- | kernel/cpu.c | 6 | ||||
| -rw-r--r-- | kernel/module.c | 59 | ||||
| -rw-r--r-- | kernel/stop_machine.c | 55 |
8 files changed, 258 insertions, 115 deletions
diff --git a/arch/parisc/include/asm/module.h b/arch/parisc/include/asm/module.h index c2cb49e934c1..1f4123427ea0 100644 --- a/arch/parisc/include/asm/module.h +++ b/arch/parisc/include/asm/module.h | |||
| @@ -23,8 +23,10 @@ struct mod_arch_specific | |||
| 23 | { | 23 | { |
| 24 | unsigned long got_offset, got_count, got_max; | 24 | unsigned long got_offset, got_count, got_max; |
| 25 | unsigned long fdesc_offset, fdesc_count, fdesc_max; | 25 | unsigned long fdesc_offset, fdesc_count, fdesc_max; |
| 26 | unsigned long stub_offset, stub_count, stub_max; | 26 | struct { |
| 27 | unsigned long init_stub_offset, init_stub_count, init_stub_max; | 27 | unsigned long stub_offset; |
| 28 | unsigned int stub_entries; | ||
| 29 | } *section; | ||
| 28 | int unwind_section; | 30 | int unwind_section; |
| 29 | struct unwind_table *unwind; | 31 | struct unwind_table *unwind; |
| 30 | }; | 32 | }; |
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index 44138c3e6ea7..9013243cecca 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * | 6 | * |
| 7 | * Linux/PA-RISC Project (http://www.parisc-linux.org/) | 7 | * Linux/PA-RISC Project (http://www.parisc-linux.org/) |
| 8 | * Copyright (C) 2003 Randolph Chung <tausq at debian . org> | 8 | * Copyright (C) 2003 Randolph Chung <tausq at debian . org> |
| 9 | * Copyright (C) 2008 Helge Deller <deller@gmx.de> | ||
| 9 | * | 10 | * |
| 10 | * | 11 | * |
| 11 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
| @@ -24,6 +25,19 @@ | |||
| 24 | * | 25 | * |
| 25 | * | 26 | * |
| 26 | * Notes: | 27 | * Notes: |
| 28 | * - PLT stub handling | ||
| 29 | * On 32bit (and sometimes 64bit) and with big kernel modules like xfs or | ||
| 30 | * ipv6 the relocation types R_PARISC_PCREL17F and R_PARISC_PCREL22F may | ||
| 31 | * fail to reach their PLT stub if we only create one big stub array for | ||
| 32 | * all sections at the beginning of the core or init section. | ||
| 33 | * Instead we now insert individual PLT stub entries directly in front of | ||
| 34 | * of the code sections where the stubs are actually called. | ||
| 35 | * This reduces the distance between the PCREL location and the stub entry | ||
| 36 | * so that the relocations can be fulfilled. | ||
| 37 | * While calculating the final layout of the kernel module in memory, the | ||
| 38 | * kernel module loader calls arch_mod_section_prepend() to request the | ||
| 39 | * to be reserved amount of memory in front of each individual section. | ||
| 40 | * | ||
| 27 | * - SEGREL32 handling | 41 | * - SEGREL32 handling |
| 28 | * We are not doing SEGREL32 handling correctly. According to the ABI, we | 42 | * We are not doing SEGREL32 handling correctly. According to the ABI, we |
| 29 | * should do a value offset, like this: | 43 | * should do a value offset, like this: |
| @@ -58,9 +72,13 @@ | |||
| 58 | #define DEBUGP(fmt...) | 72 | #define DEBUGP(fmt...) |
| 59 | #endif | 73 | #endif |
| 60 | 74 | ||
| 75 | #define RELOC_REACHABLE(val, bits) \ | ||
| 76 | (( ( !((val) & (1<<((bits)-1))) && ((val)>>(bits)) != 0 ) || \ | ||
| 77 | ( ((val) & (1<<((bits)-1))) && ((val)>>(bits)) != (((__typeof__(val))(~0))>>((bits)+2)))) ? \ | ||
| 78 | 0 : 1) | ||
| 79 | |||
| 61 | #define CHECK_RELOC(val, bits) \ | 80 | #define CHECK_RELOC(val, bits) \ |
| 62 | if ( ( !((val) & (1<<((bits)-1))) && ((val)>>(bits)) != 0 ) || \ | 81 | if (!RELOC_REACHABLE(val, bits)) { \ |
| 63 | ( ((val) & (1<<((bits)-1))) && ((val)>>(bits)) != (((__typeof__(val))(~0))>>((bits)+2)))) { \ | ||
| 64 | printk(KERN_ERR "module %s relocation of symbol %s is out of range (0x%lx in %d bits)\n", \ | 82 | printk(KERN_ERR "module %s relocation of symbol %s is out of range (0x%lx in %d bits)\n", \ |
| 65 | me->name, strtab + sym->st_name, (unsigned long)val, bits); \ | 83 | me->name, strtab + sym->st_name, (unsigned long)val, bits); \ |
| 66 | return -ENOEXEC; \ | 84 | return -ENOEXEC; \ |
| @@ -92,13 +110,6 @@ static inline int in_local(struct module *me, void *loc) | |||
| 92 | return in_init(me, loc) || in_core(me, loc); | 110 | return in_init(me, loc) || in_core(me, loc); |
| 93 | } | 111 | } |
| 94 | 112 | ||
| 95 | static inline int in_local_section(struct module *me, void *loc, void *dot) | ||
| 96 | { | ||
| 97 | return (in_init(me, loc) && in_init(me, dot)) || | ||
| 98 | (in_core(me, loc) && in_core(me, dot)); | ||
| 99 | } | ||
| 100 | |||
| 101 | |||
| 102 | #ifndef CONFIG_64BIT | 113 | #ifndef CONFIG_64BIT |
| 103 | struct got_entry { | 114 | struct got_entry { |
| 104 | Elf32_Addr addr; | 115 | Elf32_Addr addr; |
| @@ -258,23 +269,42 @@ static inline unsigned long count_stubs(const Elf_Rela *rela, unsigned long n) | |||
| 258 | /* Free memory returned from module_alloc */ | 269 | /* Free memory returned from module_alloc */ |
| 259 | void module_free(struct module *mod, void *module_region) | 270 | void module_free(struct module *mod, void *module_region) |
| 260 | { | 271 | { |
| 272 | kfree(mod->arch.section); | ||
| 273 | mod->arch.section = NULL; | ||
| 274 | |||
| 261 | vfree(module_region); | 275 | vfree(module_region); |
| 262 | /* FIXME: If module_region == mod->init_region, trim exception | 276 | /* FIXME: If module_region == mod->init_region, trim exception |
| 263 | table entries. */ | 277 | table entries. */ |
| 264 | } | 278 | } |
| 265 | 279 | ||
| 280 | /* Additional bytes needed in front of individual sections */ | ||
| 281 | unsigned int arch_mod_section_prepend(struct module *mod, | ||
| 282 | unsigned int section) | ||
| 283 | { | ||
| 284 | /* size needed for all stubs of this section (including | ||
| 285 | * one additional for correct alignment of the stubs) */ | ||
| 286 | return (mod->arch.section[section].stub_entries + 1) | ||
| 287 | * sizeof(struct stub_entry); | ||
| 288 | } | ||
| 289 | |||
| 266 | #define CONST | 290 | #define CONST |
| 267 | int module_frob_arch_sections(CONST Elf_Ehdr *hdr, | 291 | int module_frob_arch_sections(CONST Elf_Ehdr *hdr, |
| 268 | CONST Elf_Shdr *sechdrs, | 292 | CONST Elf_Shdr *sechdrs, |
| 269 | CONST char *secstrings, | 293 | CONST char *secstrings, |
| 270 | struct module *me) | 294 | struct module *me) |
| 271 | { | 295 | { |
| 272 | unsigned long gots = 0, fdescs = 0, stubs = 0, init_stubs = 0; | 296 | unsigned long gots = 0, fdescs = 0, len; |
| 273 | unsigned int i; | 297 | unsigned int i; |
| 274 | 298 | ||
| 299 | len = hdr->e_shnum * sizeof(me->arch.section[0]); | ||
| 300 | me->arch.section = kzalloc(len, GFP_KERNEL); | ||
| 301 | if (!me->arch.section) | ||
| 302 | return -ENOMEM; | ||
| 303 | |||
| 275 | for (i = 1; i < hdr->e_shnum; i++) { | 304 | for (i = 1; i < hdr->e_shnum; i++) { |
| 276 | const Elf_Rela *rels = (void *)hdr + sechdrs[i].sh_offset; | 305 | const Elf_Rela *rels = (void *)sechdrs[i].sh_addr; |
| 277 | unsigned long nrels = sechdrs[i].sh_size / sizeof(*rels); | 306 | unsigned long nrels = sechdrs[i].sh_size / sizeof(*rels); |
| 307 | unsigned int count, s; | ||
| 278 | 308 | ||
| 279 | if (strncmp(secstrings + sechdrs[i].sh_name, | 309 | if (strncmp(secstrings + sechdrs[i].sh_name, |
| 280 | ".PARISC.unwind", 14) == 0) | 310 | ".PARISC.unwind", 14) == 0) |
| @@ -290,11 +320,23 @@ int module_frob_arch_sections(CONST Elf_Ehdr *hdr, | |||
| 290 | */ | 320 | */ |
| 291 | gots += count_gots(rels, nrels); | 321 | gots += count_gots(rels, nrels); |
| 292 | fdescs += count_fdescs(rels, nrels); | 322 | fdescs += count_fdescs(rels, nrels); |
| 293 | if(strncmp(secstrings + sechdrs[i].sh_name, | 323 | |
| 294 | ".rela.init", 10) == 0) | 324 | /* XXX: By sorting the relocs and finding duplicate entries |
| 295 | init_stubs += count_stubs(rels, nrels); | 325 | * we could reduce the number of necessary stubs and save |
| 296 | else | 326 | * some memory. */ |
| 297 | stubs += count_stubs(rels, nrels); | 327 | count = count_stubs(rels, nrels); |
| 328 | if (!count) | ||
| 329 | continue; | ||
| 330 | |||
| 331 | /* so we need relocation stubs. reserve necessary memory. */ | ||
| 332 | /* sh_info gives the section for which we need to add stubs. */ | ||
| 333 | s = sechdrs[i].sh_info; | ||
| 334 | |||
| 335 | /* each code section should only have one relocation section */ | ||
| 336 | WARN_ON(me->arch.section[s].stub_entries); | ||
| 337 | |||
| 338 | /* store number of stubs we need for this section */ | ||
| 339 | me->arch.section[s].stub_entries += count; | ||
| 298 | } | 340 | } |
| 299 | 341 | ||
| 300 | /* align things a bit */ | 342 | /* align things a bit */ |
| @@ -306,18 +348,8 @@ int module_frob_arch_sections(CONST Elf_Ehdr *hdr, | |||
| 306 | me->arch.fdesc_offset = me->core_size; | 348 | me->arch.fdesc_offset = me->core_size; |
| 307 | me->core_size += fdescs * sizeof(Elf_Fdesc); | 349 | me->core_size += fdescs * sizeof(Elf_Fdesc); |
| 308 | 350 | ||
| 309 | me->core_size = ALIGN(me->core_size, 16); | ||
| 310 | me->arch.stub_offset = me->core_size; | ||
| 311 | me->core_size += stubs * sizeof(struct stub_entry); | ||
| 312 | |||
| 313 | me->init_size = ALIGN(me->init_size, 16); | ||
| 314 | me->arch.init_stub_offset = me->init_size; | ||
| 315 | me->init_size += init_stubs * sizeof(struct stub_entry); | ||
| 316 | |||
| 317 | me->arch.got_max = gots; | 351 | me->arch.got_max = gots; |
| 318 | me->arch.fdesc_max = fdescs; | 352 | me->arch.fdesc_max = fdescs; |
| 319 | me->arch.stub_max = stubs; | ||
| 320 | me->arch.init_stub_max = init_stubs; | ||
| 321 | 353 | ||
| 322 | return 0; | 354 | return 0; |
| 323 | } | 355 | } |
| @@ -380,23 +412,27 @@ enum elf_stub_type { | |||
| 380 | }; | 412 | }; |
| 381 | 413 | ||
| 382 | static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, | 414 | static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, |
| 383 | enum elf_stub_type stub_type, int init_section) | 415 | enum elf_stub_type stub_type, Elf_Addr loc0, unsigned int targetsec) |
| 384 | { | 416 | { |
| 385 | unsigned long i; | ||
| 386 | struct stub_entry *stub; | 417 | struct stub_entry *stub; |
| 387 | 418 | ||
| 388 | if(init_section) { | 419 | /* initialize stub_offset to point in front of the section */ |
| 389 | i = me->arch.init_stub_count++; | 420 | if (!me->arch.section[targetsec].stub_offset) { |
| 390 | BUG_ON(me->arch.init_stub_count > me->arch.init_stub_max); | 421 | loc0 -= (me->arch.section[targetsec].stub_entries + 1) * |
| 391 | stub = me->module_init + me->arch.init_stub_offset + | 422 | sizeof(struct stub_entry); |
| 392 | i * sizeof(struct stub_entry); | 423 | /* get correct alignment for the stubs */ |
| 393 | } else { | 424 | loc0 = ALIGN(loc0, sizeof(struct stub_entry)); |
| 394 | i = me->arch.stub_count++; | 425 | me->arch.section[targetsec].stub_offset = loc0; |
| 395 | BUG_ON(me->arch.stub_count > me->arch.stub_max); | ||
| 396 | stub = me->module_core + me->arch.stub_offset + | ||
| 397 | i * sizeof(struct stub_entry); | ||
| 398 | } | 426 | } |
| 399 | 427 | ||
| 428 | /* get address of stub entry */ | ||
| 429 | stub = (void *) me->arch.section[targetsec].stub_offset; | ||
| 430 | me->arch.section[targetsec].stub_offset += sizeof(struct stub_entry); | ||
| 431 | |||
| 432 | /* do not write outside available stub area */ | ||
| 433 | BUG_ON(0 == me->arch.section[targetsec].stub_entries--); | ||
| 434 | |||
| 435 | |||
| 400 | #ifndef CONFIG_64BIT | 436 | #ifndef CONFIG_64BIT |
| 401 | /* for 32-bit the stub looks like this: | 437 | /* for 32-bit the stub looks like this: |
| 402 | * ldil L'XXX,%r1 | 438 | * ldil L'XXX,%r1 |
| @@ -489,15 +525,19 @@ int apply_relocate_add(Elf_Shdr *sechdrs, | |||
| 489 | Elf32_Addr val; | 525 | Elf32_Addr val; |
| 490 | Elf32_Sword addend; | 526 | Elf32_Sword addend; |
| 491 | Elf32_Addr dot; | 527 | Elf32_Addr dot; |
| 528 | Elf_Addr loc0; | ||
| 529 | unsigned int targetsec = sechdrs[relsec].sh_info; | ||
| 492 | //unsigned long dp = (unsigned long)$global$; | 530 | //unsigned long dp = (unsigned long)$global$; |
| 493 | register unsigned long dp asm ("r27"); | 531 | register unsigned long dp asm ("r27"); |
| 494 | 532 | ||
| 495 | DEBUGP("Applying relocate section %u to %u\n", relsec, | 533 | DEBUGP("Applying relocate section %u to %u\n", relsec, |
| 496 | sechdrs[relsec].sh_info); | 534 | targetsec); |
| 497 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | 535 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { |
| 498 | /* This is where to make the change */ | 536 | /* This is where to make the change */ |
| 499 | loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | 537 | loc = (void *)sechdrs[targetsec].sh_addr |
| 500 | + rel[i].r_offset; | 538 | + rel[i].r_offset; |
| 539 | /* This is the start of the target section */ | ||
| 540 | loc0 = sechdrs[targetsec].sh_addr; | ||
| 501 | /* This is the symbol it is referring to */ | 541 | /* This is the symbol it is referring to */ |
| 502 | sym = (Elf32_Sym *)sechdrs[symindex].sh_addr | 542 | sym = (Elf32_Sym *)sechdrs[symindex].sh_addr |
| 503 | + ELF32_R_SYM(rel[i].r_info); | 543 | + ELF32_R_SYM(rel[i].r_info); |
| @@ -569,19 +609,32 @@ int apply_relocate_add(Elf_Shdr *sechdrs, | |||
| 569 | break; | 609 | break; |
| 570 | case R_PARISC_PCREL17F: | 610 | case R_PARISC_PCREL17F: |
| 571 | /* 17-bit PC relative address */ | 611 | /* 17-bit PC relative address */ |
| 572 | val = get_stub(me, val, addend, ELF_STUB_GOT, in_init(me, loc)); | 612 | /* calculate direct call offset */ |
| 613 | val += addend; | ||
| 573 | val = (val - dot - 8)/4; | 614 | val = (val - dot - 8)/4; |
| 574 | CHECK_RELOC(val, 17) | 615 | if (!RELOC_REACHABLE(val, 17)) { |
| 616 | /* direct distance too far, create | ||
| 617 | * stub entry instead */ | ||
| 618 | val = get_stub(me, sym->st_value, addend, | ||
| 619 | ELF_STUB_DIRECT, loc0, targetsec); | ||
| 620 | val = (val - dot - 8)/4; | ||
| 621 | CHECK_RELOC(val, 17); | ||
| 622 | } | ||
| 575 | *loc = (*loc & ~0x1f1ffd) | reassemble_17(val); | 623 | *loc = (*loc & ~0x1f1ffd) | reassemble_17(val); |
| 576 | break; | 624 | break; |
| 577 | case R_PARISC_PCREL22F: | 625 | case R_PARISC_PCREL22F: |
| 578 | /* 22-bit PC relative address; only defined for pa20 */ | 626 | /* 22-bit PC relative address; only defined for pa20 */ |
| 579 | val = get_stub(me, val, addend, ELF_STUB_GOT, in_init(me, loc)); | 627 | /* calculate direct call offset */ |
| 580 | DEBUGP("STUB FOR %s loc %lx+%lx at %lx\n", | 628 | val += addend; |
| 581 | strtab + sym->st_name, (unsigned long)loc, addend, | ||
| 582 | val) | ||
| 583 | val = (val - dot - 8)/4; | 629 | val = (val - dot - 8)/4; |
| 584 | CHECK_RELOC(val, 22); | 630 | if (!RELOC_REACHABLE(val, 22)) { |
| 631 | /* direct distance too far, create | ||
| 632 | * stub entry instead */ | ||
| 633 | val = get_stub(me, sym->st_value, addend, | ||
| 634 | ELF_STUB_DIRECT, loc0, targetsec); | ||
| 635 | val = (val - dot - 8)/4; | ||
| 636 | CHECK_RELOC(val, 22); | ||
| 637 | } | ||
| 585 | *loc = (*loc & ~0x3ff1ffd) | reassemble_22(val); | 638 | *loc = (*loc & ~0x3ff1ffd) | reassemble_22(val); |
| 586 | break; | 639 | break; |
| 587 | 640 | ||
| @@ -610,13 +663,17 @@ int apply_relocate_add(Elf_Shdr *sechdrs, | |||
| 610 | Elf64_Addr val; | 663 | Elf64_Addr val; |
| 611 | Elf64_Sxword addend; | 664 | Elf64_Sxword addend; |
| 612 | Elf64_Addr dot; | 665 | Elf64_Addr dot; |
| 666 | Elf_Addr loc0; | ||
| 667 | unsigned int targetsec = sechdrs[relsec].sh_info; | ||
| 613 | 668 | ||
| 614 | DEBUGP("Applying relocate section %u to %u\n", relsec, | 669 | DEBUGP("Applying relocate section %u to %u\n", relsec, |
| 615 | sechdrs[relsec].sh_info); | 670 | targetsec); |
| 616 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | 671 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { |
| 617 | /* This is where to make the change */ | 672 | /* This is where to make the change */ |
| 618 | loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | 673 | loc = (void *)sechdrs[targetsec].sh_addr |
| 619 | + rel[i].r_offset; | 674 | + rel[i].r_offset; |
| 675 | /* This is the start of the target section */ | ||
| 676 | loc0 = sechdrs[targetsec].sh_addr; | ||
| 620 | /* This is the symbol it is referring to */ | 677 | /* This is the symbol it is referring to */ |
| 621 | sym = (Elf64_Sym *)sechdrs[symindex].sh_addr | 678 | sym = (Elf64_Sym *)sechdrs[symindex].sh_addr |
| 622 | + ELF64_R_SYM(rel[i].r_info); | 679 | + ELF64_R_SYM(rel[i].r_info); |
| @@ -672,42 +729,40 @@ int apply_relocate_add(Elf_Shdr *sechdrs, | |||
| 672 | DEBUGP("PCREL22F Symbol %s loc %p val %lx\n", | 729 | DEBUGP("PCREL22F Symbol %s loc %p val %lx\n", |
| 673 | strtab + sym->st_name, | 730 | strtab + sym->st_name, |
| 674 | loc, val); | 731 | loc, val); |
| 732 | val += addend; | ||
| 675 | /* can we reach it locally? */ | 733 | /* can we reach it locally? */ |
| 676 | if(!in_local_section(me, (void *)val, (void *)dot)) { | 734 | if (in_local(me, (void *)val)) { |
| 677 | 735 | /* this is the case where the symbol is local | |
| 678 | if (in_local(me, (void *)val)) | 736 | * to the module, but in a different section, |
| 679 | /* this is the case where the | 737 | * so stub the jump in case it's more than 22 |
| 680 | * symbol is local to the | 738 | * bits away */ |
| 681 | * module, but in a different | 739 | val = (val - dot - 8)/4; |
| 682 | * section, so stub the jump | 740 | if (!RELOC_REACHABLE(val, 22)) { |
| 683 | * in case it's more than 22 | 741 | /* direct distance too far, create |
| 684 | * bits away */ | 742 | * stub entry instead */ |
| 685 | val = get_stub(me, val, addend, ELF_STUB_DIRECT, | 743 | val = get_stub(me, sym->st_value, |
| 686 | in_init(me, loc)); | 744 | addend, ELF_STUB_DIRECT, |
| 687 | else if (strncmp(strtab + sym->st_name, "$$", 2) | 745 | loc0, targetsec); |
| 746 | } else { | ||
| 747 | /* Ok, we can reach it directly. */ | ||
| 748 | val = sym->st_value; | ||
| 749 | val += addend; | ||
| 750 | } | ||
| 751 | } else { | ||
| 752 | val = sym->st_value; | ||
| 753 | if (strncmp(strtab + sym->st_name, "$$", 2) | ||
| 688 | == 0) | 754 | == 0) |
| 689 | val = get_stub(me, val, addend, ELF_STUB_MILLI, | 755 | val = get_stub(me, val, addend, ELF_STUB_MILLI, |
| 690 | in_init(me, loc)); | 756 | loc0, targetsec); |
| 691 | else | 757 | else |
| 692 | val = get_stub(me, val, addend, ELF_STUB_GOT, | 758 | val = get_stub(me, val, addend, ELF_STUB_GOT, |
| 693 | in_init(me, loc)); | 759 | loc0, targetsec); |
| 694 | } | 760 | } |
| 695 | DEBUGP("STUB FOR %s loc %lx, val %lx+%lx at %lx\n", | 761 | DEBUGP("STUB FOR %s loc %lx, val %lx+%lx at %lx\n", |
| 696 | strtab + sym->st_name, loc, sym->st_value, | 762 | strtab + sym->st_name, loc, sym->st_value, |
| 697 | addend, val); | 763 | addend, val); |
| 698 | /* FIXME: local symbols work as long as the | ||
| 699 | * core and init pieces aren't separated too | ||
| 700 | * far. If this is ever broken, you will trip | ||
| 701 | * the check below. The way to fix it would | ||
| 702 | * be to generate local stubs to go between init | ||
| 703 | * and core */ | ||
| 704 | if((Elf64_Sxword)(val - dot - 8) > 0x800000 -1 || | ||
| 705 | (Elf64_Sxword)(val - dot - 8) < -0x800000) { | ||
| 706 | printk(KERN_ERR "Module %s, symbol %s is out of range for PCREL22F relocation\n", | ||
| 707 | me->name, strtab + sym->st_name); | ||
| 708 | return -ENOEXEC; | ||
| 709 | } | ||
| 710 | val = (val - dot - 8)/4; | 764 | val = (val - dot - 8)/4; |
| 765 | CHECK_RELOC(val, 22); | ||
| 711 | *loc = (*loc & ~0x3ff1ffd) | reassemble_22(val); | 766 | *loc = (*loc & ~0x3ff1ffd) | reassemble_22(val); |
| 712 | break; | 767 | break; |
| 713 | case R_PARISC_DIR64: | 768 | case R_PARISC_DIR64: |
| @@ -794,12 +849,8 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
| 794 | addr = (u32 *)entry->addr; | 849 | addr = (u32 *)entry->addr; |
| 795 | printk("INSNS: %x %x %x %x\n", | 850 | printk("INSNS: %x %x %x %x\n", |
| 796 | addr[0], addr[1], addr[2], addr[3]); | 851 | addr[0], addr[1], addr[2], addr[3]); |
| 797 | printk("stubs used %ld, stubs max %ld\n" | 852 | printk("got entries used %ld, gots max %ld\n" |
| 798 | "init_stubs used %ld, init stubs max %ld\n" | ||
| 799 | "got entries used %ld, gots max %ld\n" | ||
| 800 | "fdescs used %ld, fdescs max %ld\n", | 853 | "fdescs used %ld, fdescs max %ld\n", |
| 801 | me->arch.stub_count, me->arch.stub_max, | ||
| 802 | me->arch.init_stub_count, me->arch.init_stub_max, | ||
| 803 | me->arch.got_count, me->arch.got_max, | 854 | me->arch.got_count, me->arch.got_max, |
| 804 | me->arch.fdesc_count, me->arch.fdesc_max); | 855 | me->arch.fdesc_count, me->arch.fdesc_max); |
| 805 | #endif | 856 | #endif |
| @@ -829,7 +880,10 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
| 829 | me->name, me->arch.got_count, MAX_GOTS); | 880 | me->name, me->arch.got_count, MAX_GOTS); |
| 830 | return -EINVAL; | 881 | return -EINVAL; |
| 831 | } | 882 | } |
| 832 | 883 | ||
| 884 | kfree(me->arch.section); | ||
| 885 | me->arch.section = NULL; | ||
| 886 | |||
| 833 | /* no symbol table */ | 887 | /* no symbol table */ |
| 834 | if(symhdr == NULL) | 888 | if(symhdr == NULL) |
| 835 | return 0; | 889 | return 0; |
diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h index eb1033957486..c1f40c2f7ffb 100644 --- a/include/linux/moduleloader.h +++ b/include/linux/moduleloader.h | |||
| @@ -13,6 +13,9 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, | |||
| 13 | char *secstrings, | 13 | char *secstrings, |
| 14 | struct module *mod); | 14 | struct module *mod); |
| 15 | 15 | ||
| 16 | /* Additional bytes needed by arch in front of individual sections */ | ||
| 17 | unsigned int arch_mod_section_prepend(struct module *mod, unsigned int section); | ||
| 18 | |||
| 16 | /* Allocator used for allocating struct module, core sections and init | 19 | /* Allocator used for allocating struct module, core sections and init |
| 17 | sections. Returns NULL on failure. */ | 20 | sections. Returns NULL on failure. */ |
| 18 | void *module_alloc(unsigned long size); | 21 | void *module_alloc(unsigned long size); |
diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h index 74d59a641362..baba3a23a814 100644 --- a/include/linux/stop_machine.h +++ b/include/linux/stop_machine.h | |||
| @@ -35,6 +35,24 @@ int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus); | |||
| 35 | * won't come or go while it's being called. Used by hotplug cpu. | 35 | * won't come or go while it's being called. Used by hotplug cpu. |
| 36 | */ | 36 | */ |
| 37 | int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus); | 37 | int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus); |
| 38 | |||
| 39 | /** | ||
| 40 | * stop_machine_create: create all stop_machine threads | ||
| 41 | * | ||
| 42 | * Description: This causes all stop_machine threads to be created before | ||
| 43 | * stop_machine actually gets called. This can be used by subsystems that | ||
| 44 | * need a non failing stop_machine infrastructure. | ||
| 45 | */ | ||
| 46 | int stop_machine_create(void); | ||
| 47 | |||
| 48 | /** | ||
| 49 | * stop_machine_destroy: destroy all stop_machine threads | ||
| 50 | * | ||
| 51 | * Description: This causes all stop_machine threads which were created with | ||
| 52 | * stop_machine_create to be destroyed again. | ||
| 53 | */ | ||
| 54 | void stop_machine_destroy(void); | ||
| 55 | |||
| 38 | #else | 56 | #else |
| 39 | 57 | ||
| 40 | static inline int stop_machine(int (*fn)(void *), void *data, | 58 | static inline int stop_machine(int (*fn)(void *), void *data, |
| @@ -46,5 +64,9 @@ static inline int stop_machine(int (*fn)(void *), void *data, | |||
| 46 | local_irq_enable(); | 64 | local_irq_enable(); |
| 47 | return ret; | 65 | return ret; |
| 48 | } | 66 | } |
| 67 | |||
| 68 | static inline int stop_machine_create(void) { return 0; } | ||
| 69 | static inline void stop_machine_destroy(void) { } | ||
| 70 | |||
| 49 | #endif /* CONFIG_SMP */ | 71 | #endif /* CONFIG_SMP */ |
| 50 | #endif /* _LINUX_STOP_MACHINE */ | 72 | #endif /* _LINUX_STOP_MACHINE */ |
diff --git a/init/Kconfig b/init/Kconfig index f6281711166d..52847eec7398 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
| @@ -916,12 +916,6 @@ config MODULE_SRCVERSION_ALL | |||
| 916 | the version). With this option, such a "srcversion" field | 916 | the version). With this option, such a "srcversion" field |
| 917 | will be created for all modules. If unsure, say N. | 917 | will be created for all modules. If unsure, say N. |
| 918 | 918 | ||
| 919 | config KMOD | ||
| 920 | def_bool y | ||
| 921 | help | ||
| 922 | This is being removed soon. These days, CONFIG_MODULES | ||
| 923 | implies CONFIG_KMOD, so use that instead. | ||
| 924 | |||
| 925 | endif # MODULES | 919 | endif # MODULES |
| 926 | 920 | ||
| 927 | config INIT_ALL_POSSIBLE | 921 | config INIT_ALL_POSSIBLE |
diff --git a/kernel/cpu.c b/kernel/cpu.c index 47fff3b63cbf..30e74dd6d01b 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
| @@ -269,8 +269,11 @@ out_release: | |||
| 269 | 269 | ||
| 270 | int __ref cpu_down(unsigned int cpu) | 270 | int __ref cpu_down(unsigned int cpu) |
| 271 | { | 271 | { |
| 272 | int err = 0; | 272 | int err; |
| 273 | 273 | ||
| 274 | err = stop_machine_create(); | ||
| 275 | if (err) | ||
| 276 | return err; | ||
| 274 | cpu_maps_update_begin(); | 277 | cpu_maps_update_begin(); |
| 275 | 278 | ||
| 276 | if (cpu_hotplug_disabled) { | 279 | if (cpu_hotplug_disabled) { |
| @@ -297,6 +300,7 @@ int __ref cpu_down(unsigned int cpu) | |||
| 297 | 300 | ||
| 298 | out: | 301 | out: |
| 299 | cpu_maps_update_done(); | 302 | cpu_maps_update_done(); |
| 303 | stop_machine_destroy(); | ||
| 300 | return err; | 304 | return err; |
| 301 | } | 305 | } |
| 302 | EXPORT_SYMBOL(cpu_down); | 306 | EXPORT_SYMBOL(cpu_down); |
diff --git a/kernel/module.c b/kernel/module.c index dd2a54155b54..f47cce910f25 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -757,8 +757,16 @@ sys_delete_module(const char __user *name_user, unsigned int flags) | |||
| 757 | return -EFAULT; | 757 | return -EFAULT; |
| 758 | name[MODULE_NAME_LEN-1] = '\0'; | 758 | name[MODULE_NAME_LEN-1] = '\0'; |
| 759 | 759 | ||
| 760 | if (mutex_lock_interruptible(&module_mutex) != 0) | 760 | /* Create stop_machine threads since free_module relies on |
| 761 | return -EINTR; | 761 | * a non-failing stop_machine call. */ |
| 762 | ret = stop_machine_create(); | ||
| 763 | if (ret) | ||
| 764 | return ret; | ||
| 765 | |||
| 766 | if (mutex_lock_interruptible(&module_mutex) != 0) { | ||
| 767 | ret = -EINTR; | ||
| 768 | goto out_stop; | ||
| 769 | } | ||
| 762 | 770 | ||
| 763 | mod = find_module(name); | 771 | mod = find_module(name); |
| 764 | if (!mod) { | 772 | if (!mod) { |
| @@ -817,10 +825,12 @@ sys_delete_module(const char __user *name_user, unsigned int flags) | |||
| 817 | 825 | ||
| 818 | out: | 826 | out: |
| 819 | mutex_unlock(&module_mutex); | 827 | mutex_unlock(&module_mutex); |
| 828 | out_stop: | ||
| 829 | stop_machine_destroy(); | ||
| 820 | return ret; | 830 | return ret; |
| 821 | } | 831 | } |
| 822 | 832 | ||
| 823 | static void print_unload_info(struct seq_file *m, struct module *mod) | 833 | static inline void print_unload_info(struct seq_file *m, struct module *mod) |
| 824 | { | 834 | { |
| 825 | struct module_use *use; | 835 | struct module_use *use; |
| 826 | int printed_something = 0; | 836 | int printed_something = 0; |
| @@ -893,7 +903,7 @@ void module_put(struct module *module) | |||
| 893 | EXPORT_SYMBOL(module_put); | 903 | EXPORT_SYMBOL(module_put); |
| 894 | 904 | ||
| 895 | #else /* !CONFIG_MODULE_UNLOAD */ | 905 | #else /* !CONFIG_MODULE_UNLOAD */ |
| 896 | static void print_unload_info(struct seq_file *m, struct module *mod) | 906 | static inline void print_unload_info(struct seq_file *m, struct module *mod) |
| 897 | { | 907 | { |
| 898 | /* We don't know the usage count, or what modules are using. */ | 908 | /* We don't know the usage count, or what modules are using. */ |
| 899 | seq_printf(m, " - -"); | 909 | seq_printf(m, " - -"); |
| @@ -1578,11 +1588,21 @@ static int simplify_symbols(Elf_Shdr *sechdrs, | |||
| 1578 | return ret; | 1588 | return ret; |
| 1579 | } | 1589 | } |
| 1580 | 1590 | ||
| 1591 | /* Additional bytes needed by arch in front of individual sections */ | ||
| 1592 | unsigned int __weak arch_mod_section_prepend(struct module *mod, | ||
| 1593 | unsigned int section) | ||
| 1594 | { | ||
| 1595 | /* default implementation just returns zero */ | ||
| 1596 | return 0; | ||
| 1597 | } | ||
| 1598 | |||
| 1581 | /* Update size with this section: return offset. */ | 1599 | /* Update size with this section: return offset. */ |
| 1582 | static long get_offset(unsigned int *size, Elf_Shdr *sechdr) | 1600 | static long get_offset(struct module *mod, unsigned int *size, |
| 1601 | Elf_Shdr *sechdr, unsigned int section) | ||
| 1583 | { | 1602 | { |
| 1584 | long ret; | 1603 | long ret; |
| 1585 | 1604 | ||
| 1605 | *size += arch_mod_section_prepend(mod, section); | ||
| 1586 | ret = ALIGN(*size, sechdr->sh_addralign ?: 1); | 1606 | ret = ALIGN(*size, sechdr->sh_addralign ?: 1); |
| 1587 | *size = ret + sechdr->sh_size; | 1607 | *size = ret + sechdr->sh_size; |
| 1588 | return ret; | 1608 | return ret; |
| @@ -1622,7 +1642,7 @@ static void layout_sections(struct module *mod, | |||
| 1622 | || strncmp(secstrings + s->sh_name, | 1642 | || strncmp(secstrings + s->sh_name, |
| 1623 | ".init", 5) == 0) | 1643 | ".init", 5) == 0) |
| 1624 | continue; | 1644 | continue; |
| 1625 | s->sh_entsize = get_offset(&mod->core_size, s); | 1645 | s->sh_entsize = get_offset(mod, &mod->core_size, s, i); |
| 1626 | DEBUGP("\t%s\n", secstrings + s->sh_name); | 1646 | DEBUGP("\t%s\n", secstrings + s->sh_name); |
| 1627 | } | 1647 | } |
| 1628 | if (m == 0) | 1648 | if (m == 0) |
| @@ -1640,7 +1660,7 @@ static void layout_sections(struct module *mod, | |||
| 1640 | || strncmp(secstrings + s->sh_name, | 1660 | || strncmp(secstrings + s->sh_name, |
| 1641 | ".init", 5) != 0) | 1661 | ".init", 5) != 0) |
| 1642 | continue; | 1662 | continue; |
| 1643 | s->sh_entsize = (get_offset(&mod->init_size, s) | 1663 | s->sh_entsize = (get_offset(mod, &mod->init_size, s, i) |
| 1644 | | INIT_OFFSET_MASK); | 1664 | | INIT_OFFSET_MASK); |
| 1645 | DEBUGP("\t%s\n", secstrings + s->sh_name); | 1665 | DEBUGP("\t%s\n", secstrings + s->sh_name); |
| 1646 | } | 1666 | } |
| @@ -1725,15 +1745,15 @@ static const struct kernel_symbol *lookup_symbol(const char *name, | |||
| 1725 | return NULL; | 1745 | return NULL; |
| 1726 | } | 1746 | } |
| 1727 | 1747 | ||
| 1728 | static int is_exported(const char *name, const struct module *mod) | 1748 | static int is_exported(const char *name, unsigned long value, |
| 1749 | const struct module *mod) | ||
| 1729 | { | 1750 | { |
| 1730 | if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab)) | 1751 | const struct kernel_symbol *ks; |
| 1731 | return 1; | 1752 | if (!mod) |
| 1753 | ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab); | ||
| 1732 | else | 1754 | else |
| 1733 | if (mod && lookup_symbol(name, mod->syms, mod->syms + mod->num_syms)) | 1755 | ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms); |
| 1734 | return 1; | 1756 | return ks != NULL && ks->value == value; |
| 1735 | else | ||
| 1736 | return 0; | ||
| 1737 | } | 1757 | } |
| 1738 | 1758 | ||
| 1739 | /* As per nm */ | 1759 | /* As per nm */ |
| @@ -1865,6 +1885,13 @@ static noinline struct module *load_module(void __user *umod, | |||
| 1865 | /* vmalloc barfs on "unusual" numbers. Check here */ | 1885 | /* vmalloc barfs on "unusual" numbers. Check here */ |
| 1866 | if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL) | 1886 | if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL) |
| 1867 | return ERR_PTR(-ENOMEM); | 1887 | return ERR_PTR(-ENOMEM); |
| 1888 | |||
| 1889 | /* Create stop_machine threads since the error path relies on | ||
| 1890 | * a non-failing stop_machine call. */ | ||
| 1891 | err = stop_machine_create(); | ||
| 1892 | if (err) | ||
| 1893 | goto free_hdr; | ||
| 1894 | |||
| 1868 | if (copy_from_user(hdr, umod, len) != 0) { | 1895 | if (copy_from_user(hdr, umod, len) != 0) { |
| 1869 | err = -EFAULT; | 1896 | err = -EFAULT; |
| 1870 | goto free_hdr; | 1897 | goto free_hdr; |
| @@ -2248,6 +2275,7 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2248 | /* Get rid of temporary copy */ | 2275 | /* Get rid of temporary copy */ |
| 2249 | vfree(hdr); | 2276 | vfree(hdr); |
| 2250 | 2277 | ||
| 2278 | stop_machine_destroy(); | ||
| 2251 | /* Done! */ | 2279 | /* Done! */ |
| 2252 | return mod; | 2280 | return mod; |
| 2253 | 2281 | ||
| @@ -2270,6 +2298,7 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2270 | kfree(args); | 2298 | kfree(args); |
| 2271 | free_hdr: | 2299 | free_hdr: |
| 2272 | vfree(hdr); | 2300 | vfree(hdr); |
| 2301 | stop_machine_destroy(); | ||
| 2273 | return ERR_PTR(err); | 2302 | return ERR_PTR(err); |
| 2274 | 2303 | ||
| 2275 | truncated: | 2304 | truncated: |
| @@ -2504,7 +2533,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, | |||
| 2504 | strlcpy(name, mod->strtab + mod->symtab[symnum].st_name, | 2533 | strlcpy(name, mod->strtab + mod->symtab[symnum].st_name, |
| 2505 | KSYM_NAME_LEN); | 2534 | KSYM_NAME_LEN); |
| 2506 | strlcpy(module_name, mod->name, MODULE_NAME_LEN); | 2535 | strlcpy(module_name, mod->name, MODULE_NAME_LEN); |
| 2507 | *exported = is_exported(name, mod); | 2536 | *exported = is_exported(name, *value, mod); |
| 2508 | preempt_enable(); | 2537 | preempt_enable(); |
| 2509 | return 0; | 2538 | return 0; |
| 2510 | } | 2539 | } |
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 286c41722e8c..0cd415ee62a2 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c | |||
| @@ -38,7 +38,10 @@ struct stop_machine_data { | |||
| 38 | static unsigned int num_threads; | 38 | static unsigned int num_threads; |
| 39 | static atomic_t thread_ack; | 39 | static atomic_t thread_ack; |
| 40 | static DEFINE_MUTEX(lock); | 40 | static DEFINE_MUTEX(lock); |
| 41 | 41 | /* setup_lock protects refcount, stop_machine_wq and stop_machine_work. */ | |
| 42 | static DEFINE_MUTEX(setup_lock); | ||
| 43 | /* Users of stop_machine. */ | ||
| 44 | static int refcount; | ||
| 42 | static struct workqueue_struct *stop_machine_wq; | 45 | static struct workqueue_struct *stop_machine_wq; |
| 43 | static struct stop_machine_data active, idle; | 46 | static struct stop_machine_data active, idle; |
| 44 | static const cpumask_t *active_cpus; | 47 | static const cpumask_t *active_cpus; |
| @@ -109,6 +112,43 @@ static int chill(void *unused) | |||
| 109 | return 0; | 112 | return 0; |
| 110 | } | 113 | } |
| 111 | 114 | ||
| 115 | int stop_machine_create(void) | ||
| 116 | { | ||
| 117 | mutex_lock(&setup_lock); | ||
| 118 | if (refcount) | ||
| 119 | goto done; | ||
| 120 | stop_machine_wq = create_rt_workqueue("kstop"); | ||
| 121 | if (!stop_machine_wq) | ||
| 122 | goto err_out; | ||
| 123 | stop_machine_work = alloc_percpu(struct work_struct); | ||
| 124 | if (!stop_machine_work) | ||
| 125 | goto err_out; | ||
| 126 | done: | ||
| 127 | refcount++; | ||
| 128 | mutex_unlock(&setup_lock); | ||
| 129 | return 0; | ||
| 130 | |||
| 131 | err_out: | ||
| 132 | if (stop_machine_wq) | ||
| 133 | destroy_workqueue(stop_machine_wq); | ||
| 134 | mutex_unlock(&setup_lock); | ||
| 135 | return -ENOMEM; | ||
| 136 | } | ||
| 137 | EXPORT_SYMBOL_GPL(stop_machine_create); | ||
| 138 | |||
| 139 | void stop_machine_destroy(void) | ||
| 140 | { | ||
| 141 | mutex_lock(&setup_lock); | ||
| 142 | refcount--; | ||
| 143 | if (refcount) | ||
| 144 | goto done; | ||
| 145 | destroy_workqueue(stop_machine_wq); | ||
| 146 | free_percpu(stop_machine_work); | ||
| 147 | done: | ||
| 148 | mutex_unlock(&setup_lock); | ||
| 149 | } | ||
| 150 | EXPORT_SYMBOL_GPL(stop_machine_destroy); | ||
| 151 | |||
| 112 | int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus) | 152 | int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus) |
| 113 | { | 153 | { |
| 114 | struct work_struct *sm_work; | 154 | struct work_struct *sm_work; |
| @@ -146,19 +186,14 @@ int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus) | |||
| 146 | { | 186 | { |
| 147 | int ret; | 187 | int ret; |
| 148 | 188 | ||
| 189 | ret = stop_machine_create(); | ||
| 190 | if (ret) | ||
| 191 | return ret; | ||
| 149 | /* No CPUs can come up or down during this. */ | 192 | /* No CPUs can come up or down during this. */ |
| 150 | get_online_cpus(); | 193 | get_online_cpus(); |
| 151 | ret = __stop_machine(fn, data, cpus); | 194 | ret = __stop_machine(fn, data, cpus); |
| 152 | put_online_cpus(); | 195 | put_online_cpus(); |
| 153 | 196 | stop_machine_destroy(); | |
| 154 | return ret; | 197 | return ret; |
| 155 | } | 198 | } |
| 156 | EXPORT_SYMBOL_GPL(stop_machine); | 199 | EXPORT_SYMBOL_GPL(stop_machine); |
| 157 | |||
| 158 | static int __init stop_machine_init(void) | ||
| 159 | { | ||
| 160 | stop_machine_wq = create_rt_workqueue("kstop"); | ||
| 161 | stop_machine_work = alloc_percpu(struct work_struct); | ||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | core_initcall(stop_machine_init); | ||
