parisc: fix module loading failure of large kernel modules
Subsystems (2)
Helge Deller
maintainerPATCH 1/1 parisc: fix module loading failure of large kernel modules
The parisc port (esp. the 32bit kernel) currently lacks the ability to load large kernel modules like xfs or ipv6. This is a long outstanding bug and has already been reported a few times, e.g.:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350482,
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=401439,
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=508489
The symptom is like this:
# modprobe xfs FATAL: Error inserting xfs (/lib/modules/2.6.26-1-parisc/kernel/fs/xfs/xfs.ko): Invalid module format
In dmesg:
module xfs relocation of symbol xfs_btree_read_bufs is out of range (0x3ffefffe in 17 bits)
The reason for the failure is, that the architecture only provides the R_PARISC_PCREL17F (for 32bit kernels) and R_PARISC_PCREL22F (for PA2.0 and 64bit kernels) relocations, which sometimes can't reach the target address of the stub entry if the kernel module is too large. Currently parisc (like other architectures) creates one big PLT section for all stubs at the beginning of the init and core sections.
The following two patches changes the parisc module loader to put stubs in between the code sections instead, so that the distance to the stubs more easily fits into the available 17/22 bits.
The first patch touches the generic module loader and adds a call to the new module_additional_section_size() function to get_offset() if CONFIG_ARCH_WANTS_STUBS_BEHIND_SECTIONS is defined. On parisc this function returns the additional bytes for the stub area of a given section.
The second patch implements the parisc-specific changes.
Tested with 32- and 64bit parisc kernels.
Helge
Helge Deller
maintainerPATCH 1/2 module.c: fix module loading failure of large modules
[PATCH 1/2] module.c: fix module loading failure of large modules
When creating the final layout of a kernel module in memory, allow the module loader to reserve some additional memory behind a given section. This is currently only needed for the parisc port which needs to put the stub entries there to fulfill the 17/22bit PCREL relocations with large kernel modules like xfs.
include/linux/moduleloader.h +3 -0
@@ -13,6 +13,9 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,char *secstrings, struct module *mod); +unsigned long module_additional_section_size (struct module *mod, +unsigned int section); +/* Allocator used for allocating struct module, core sections and init sections. Returns NULL on failure. */ void *module_alloc (unsigned long size);
kernel/module.c +7 -3
@@ -1579,12 +1579,16 @@ static int simplify_symbols(Elf_Shdr *sechdrs, }/* Update size with this section: return offset. */ -static long get_offset (unsigned int *size,Elf_Shdr *sechdr) +static long get_offset (struct module *mod,unsigned int *size, +Elf_Shdr *sechdr,unsigned int section) {long ret; ret =ALIGN (*size, sechdr->sh_addralign ?:1 ); *size = ret + sechdr->sh_size; +#ifdef CONFIG_ARCH_WANTS_STUBS_BEHIND_SECTIONS + *size +=module_additional_section_size (mod, section); +#endif return ret; }
@@ -1622,7 +1626,7 @@ static void layout_sections(struct module *mod, || strncmp(secstrings + s->sh_name, ".init", 5) == 0)continue ; - s->sh_entsize =get_offset (&mod->core_size, s); + s->sh_entsize =get_offset (mod, &mod->core_size, s, i);DEBUGP ("\t%s\n" , secstrings + s->sh_name); }if (m ==0 )
@@ -1640,7 +1644,7 @@ static void layout_sections(struct module *mod, || strncmp(secstrings + s->sh_name, ".init", 5) != 0)continue ; - s->sh_entsize = (get_offset (&mod->init_size, s) + s->sh_entsize = (get_offset (mod, &mod->init_size, s, i) |INIT_OFFSET_MASK );DEBUGP ("\t%s\n" , secstrings + s->sh_name); }
Helge Deller
maintainerPATCH 2/2 parisc: fix module loading failure of large modules
In reply to Helge Deller[PATCH 2/2] parisc: fix module loading failure of large modules
On 32bit (and sometimes 64bit) and with big kernel modules like xfs or ipv6 the relocation types R_PARISC_PCREL17F and R_PARISC_PCREL22F may fail to reach their PLT stub if we only create one big stub array for all sections at the beginning of the core or init section.
With this patch we now instead append individual PLT stub entries directly at the end of the code sections where the stubs are actually called. This reduces the distance between the PCREL location and the stub entry so that the relocations can be fulfilled.
The kernel module loader will call module_additional_section_size() and request us to return the amount of additional memory we need for the stubs of each section. The final section size of the code segment will then be increased by that value when the kernel layouts the final addresses of all sections.
Tested with 32- and 64bit kernels.
arch/parisc/Kconfig +3 -0
@@ -34,6 +34,9 @@ config RWSEM_GENERIC_SPINLOCK config RWSEM_XCHGADD_ALGORITHM bool +config ARCH_WANTS_STUBS_BEHIND_SECTIONS + def_bool y + config ARCH_HAS_ILOG2_U32 bool default n
arch/parisc/include/asm/module.h +4 -2
@@ -23,8 +23,10 @@ struct mod_arch_specific {unsigned long got_offset, got_count, got_max;unsigned long fdesc_offset, fdesc_count, fdesc_max; -unsigned long stub_offset, stub_count, stub_max; -unsigned long init_stub_offset, init_stub_count, init_stub_max; +struct { +unsigned long stub_offset; +unsigned int stub_entries; + } *section;int unwind_section;struct unwind_table *unwind; };
arch/parisc/kernel/module.c +131 -82
347 lines not on this page · raw message
Re: [PATCH 2/2] parisc: fix module loading failure of large modules
Quoted 28 lines · Helge Deller
[PATCH 2/2] parisc: fix module loading failure of large modules
On 32bit (and sometimes 64bit) and with big kernel modules like xfs or ipv6 the relocation types
R_PARISC_PCREL17FandR_PARISC_PCREL22Fmay fail to reach their PLT stub if we only create one big stub array for all sections at the beginning of the core or init section.With this patch we now instead append individual PLT stub entries directly at the end of the code sections where the stubs are actually called. This reduces the distance between the PCREL location and the stub entry so that the relocations can be fulfilled.
The kernel module loader will call
module_additional_section_size()and request us to return the amount of additional memory we need for the stubs of each section. The final section size of the code segment will then be increased by that value when the kernel layouts the final addresses of all sections.Tested with 32- and 64bit kernels.
Signed-off-by Helge Deller <[email protected]>arch/parisc/Kconfig +0
-0
arch/parisc/Kconfig config RWSEM_GENERIC_SPINLOCK · line 39
Quoted 6 lines
arch/parisc/Kconfig +3
-0@@ -34,6 +34,9 @@ config RWSEM_GENERIC_SPINLOCK config RWSEM_XCHGADD_ALGORITHM bool +config ARCH_WANTS_STUBS_BEHIND_SECTIONS + def_bool y +
The recommended practive today is:
In some relevant Kconfig file add:
config HAVE_MODULE_SECTION_STUBS
bool
And then in arch/$ARCH/Kconfig do:
config PARISC
... select HAVE_MODULE_SECTION_STUBS ...
The select are supposed to be sorted alphabetically but people seems to use a different alphabet for each arch.
Sam
Helge Deller
maintainerRe: [PATCH 2/2] parisc: fix module loading failure of large modules
Quoted 45 lines · Sam Ravnborg
Quoted 28 lines · Helge Deller
[PATCH 2/2] parisc: fix module loading failure of large modules
On 32bit (and sometimes 64bit) and with big kernel modules like xfs or ipv6 the relocation types
R_PARISC_PCREL17FandR_PARISC_PCREL22Fmay fail to reach their PLT stub if we only create one big stub array for all sections at the beginning of the core or init section.With this patch we now instead append individual PLT stub entries directly at the end of the code sections where the stubs are actually called. This reduces the distance between the PCREL location and the stub entry so that the relocations can be fulfilled.
The kernel module loader will call
module_additional_section_size()and request us to return the amount of additional memory we need for the stubs of each section. The final section size of the code segment will then be increased by that value when the kernel layouts the final addresses of all sections.Tested with 32- and 64bit kernels.
Signed-off-by Helge Deller <[email protected]>arch/parisc/Kconfig +0
-0arch/parisc/Kconfig config RWSEM_GENERIC_SPINLOCK · line 39
Quoted 6 lines
arch/parisc/Kconfig +3
-0@@ -34,6 +34,9 @@ config RWSEM_GENERIC_SPINLOCK config RWSEM_XCHGADD_ALGORITHM bool +config ARCH_WANTS_STUBS_BEHIND_SECTIONS + def_bool y +The recommended practive today is:
In some relevant
Kconfigfile add:config
HAVE_MODULE_SECTION_STUBS
boolAnd then in
arch/$ARCH/Kconfigdo:
Quoted 8 lines
config PARISC
... select HAVE_MODULE_SECTION_STUBS ...The select are supposed to be sorted alphabetically but people seems to use a different alphabet for each arch.
Thanks Sam,
I'll change that and respin.
Helge
Re: [PATCH 2/2] parisc: fix module loading failure of large modules
In reply to Helge DellerHi Helge,
Quoted 4 lines
With this patch we now instead append individual PLT stub entries directly at the end of the code sections where the stubs are actually called. This reduces the distance between the PCREL location and the stub entry so that the relocations can be fulfilled.
GCC for PA-RISC assumes that the stubs will be placed before the code section. This is what HP-UX does. It's also not possible to compute the distance to the end of a function in GCC due to the way branch shortening is done. If the distance to the start of the code section is too large, GCC outputs a long call.
If you can insert them before the code section where the stubs are called, this will minimize the chance that a pc-relative call will not reach its stub.
It is possible to put the stubs after the code section if you can ensure the distance for each call isn't too large. I believe GNU ld does some consolidation of stub blocks.
Great patch!
Dave
Signature · 2 lines
J. David Anglin [email protected] National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
Helge Deller
maintainerRe: [PATCH 2/2] parisc: fix module loading failure of large modules
Quoted 7 lines · John David Anglin
Hi Helge,
Quoted 4 lines
With this patch we now instead append individual PLT stub entries directly at the end of the code sections where the stubs are actually called. This reduces the distance between the PCREL location and the stub entry so that the relocations can be fulfilled.
Quoted 5 lines
GCC for PA-RISC assumes that the stubs will be placed before the code section. This is what HP-UX does. It's also not possible to compute the distance to the end of a function in GCC due to the way branch shortening is done. If the distance to the start of the code section is too large, GCC outputs a long call.
Interesting. I didn't knew that.
Quoted 3 lines
If you can insert them before the code section where the stubs are called, this will minimize the chance that a pc-relative call will not reach its stub.
Yes, good idea.
I'll change that and send an updated patch.
Quoted 1 line
Great patch!
Thanks!
Helge