aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2012-08-08 10:59:43 -0400
committerRalf Baechle <ralf@linux-mips.org>2012-08-17 04:57:28 -0400
commit861667dc82f561e65336ea67f73021b782b4ff74 (patch)
tree822734b6d8c58b92e118215c27deb9bc61aeb2bc /arch/mips/kernel
parentd3cac35cd0a2a987f7559e1829fb0253cea33872 (diff)
MIPS: Fix race condition in module relocation code.
The relocation code was essentially taken from the 2.4 modutils which perform relocation in userspace. In 2.6 relocation of multiple modules may be performed in parallel by the in-kernel loader so the global variable mips_hi16_list won't fly anymore. Fix race by moving it into mod_arch_specific. [ralf@linux-mips.org: folded in Tony's followup fix. Thanks Tony!] Signed-off-by: Ralf Baechle <ralf@linux-mips.org> Signed-off-by: Tony Wu <tung7970@gmail.com> Cc: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/4189/
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/module.c13
1 files changed, 6 insertions, 7 deletions
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c
index e5f2f56524e..8e1fb802c3e 100644
--- a/arch/mips/kernel/module.c
+++ b/arch/mips/kernel/module.c
@@ -39,8 +39,6 @@ struct mips_hi16 {
39 Elf_Addr value; 39 Elf_Addr value;
40}; 40};
41 41
42static struct mips_hi16 *mips_hi16_list;
43
44static LIST_HEAD(dbe_list); 42static LIST_HEAD(dbe_list);
45static DEFINE_SPINLOCK(dbe_lock); 43static DEFINE_SPINLOCK(dbe_lock);
46 44
@@ -128,8 +126,8 @@ static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v)
128 126
129 n->addr = (Elf_Addr *)location; 127 n->addr = (Elf_Addr *)location;
130 n->value = v; 128 n->value = v;
131 n->next = mips_hi16_list; 129 n->next = me->arch.r_mips_hi16_list;
132 mips_hi16_list = n; 130 me->arch.r_mips_hi16_list = n;
133 131
134 return 0; 132 return 0;
135} 133}
@@ -151,9 +149,9 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
151 /* Sign extend the addend we extract from the lo insn. */ 149 /* Sign extend the addend we extract from the lo insn. */
152 vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; 150 vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
153 151
154 if (mips_hi16_list != NULL) { 152 if (me->arch.r_mips_hi16_list != NULL) {
155 153
156 l = mips_hi16_list; 154 l = me->arch.r_mips_hi16_list;
157 while (l != NULL) { 155 while (l != NULL) {
158 unsigned long insn; 156 unsigned long insn;
159 157
@@ -187,7 +185,7 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
187 l = next; 185 l = next;
188 } 186 }
189 187
190 mips_hi16_list = NULL; 188 me->arch.r_mips_hi16_list = NULL;
191 } 189 }
192 190
193 /* 191 /*
@@ -278,6 +276,7 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
278 pr_debug("Applying relocate section %u to %u\n", relsec, 276 pr_debug("Applying relocate section %u to %u\n", relsec,
279 sechdrs[relsec].sh_info); 277 sechdrs[relsec].sh_info);
280 278
279 me->arch.r_mips_hi16_list = NULL;
281 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 280 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
282 /* This is where to make the change */ 281 /* This is where to make the change */
283 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 282 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr