Skip to contentSkip to conversation

parisc: fix module loading failure of large kernel modules

PATCH New Helge Deller 3 participants 7 messages Dec 29, 2008

Subsystems (2)
lore
Share & tools
lore

Helge Deller

author maintainer
#0 lore raw

PATCH 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

author maintainer
#1 lore raw

PATCH 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
index eb10339..65fb34c 100644
@@ -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
index 1f4cc00..c7662da 100644
@@ -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);
 		}
author maintainer
#2 lore raw

PATCH 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
index 644a70b..cbb622f 100644
@@ -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
index c2cb49e..1f41234 100644
@@ -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

#3 lore raw

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_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 +0 -0
index 644a70b..cbb622f 100644

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

author maintainer
#4 lore raw

Re: [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_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 +0 -0
index 644a70b..cbb622f 100644

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:

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

#5 lore raw

Re: [PATCH 2/2] parisc: fix module loading failure of large modules

In reply to Helge Deller

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.

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)
author maintainer
#6 lore raw

Re: [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