Hi David, Please do another test build using the attached patch based on an RFC rmk sent out recently, in place of: arm-linux-3.6-revert-missaligned-access-check-on-put_user.patch That other patch is not going to go upstream, whereas the attached patch will likely land in some form. There is a real kernel bug, which I have attempted to document in the patch (original discussion is ongoing upstream, and I just followed up about this patch). I will followup with a highbank specific patch for the network driver. Jon.
arm: [rfc] use atomic nonfaulting accessors in dump_mem A recent patch from Will Deacon enabled might_fault checks in the __get_user code path used within areas of the kernel where atomic access is required (e.g. in dump_mem). These now result in warnings of "scheduling while atomic", which could happen due to a miss-aligned access or other user fault during a backtrace. This patch changes the use of __get_user to probe_kernel_address, which always ensures that it operates atomically. There is no need to switch FS as this is done by the accessor function rather than by the trap handling code now. Originally from Russell King and an RFC patch (testing here only). Signed-off-by: Jon Masters <jcm@xxxxxxxxxxxxxx> diff -urNp linux-3.6.3-3.fc18.x86_64_orig/arch/arm/kernel/traps.c linux-3.6.3-3.fc18.x86_64/arch/arm/kernel/traps.c --- linux-3.6.3-3.fc18.x86_64_orig/arch/arm/kernel/traps.c 2012-09-30 19:47:46.000000000 -0400 +++ linux-3.6.3-3.fc18.x86_64/arch/arm/kernel/traps.c 2012-10-23 12:40:14.802494230 -0400 @@ -89,17 +89,8 @@ static void dump_mem(const char *lvl, co unsigned long top) { unsigned long first; - mm_segment_t fs; int i; - /* - * We need to switch to kernel mode so that we can use __get_user - * to safely read from kernel space. Note that we now dump the - * code first, just in case the backtrace kills us. - */ - fs = get_fs(); - set_fs(KERNEL_DS); - printk("%s%s(0x%08lx to 0x%08lx)\n", lvl, str, bottom, top); for (first = bottom & ~31; first < top; first += 32) { @@ -112,7 +103,7 @@ static void dump_mem(const char *lvl, co for (p = first, i = 0; i < 8 && p < top; i++, p += 4) { if (p >= bottom && p < top) { unsigned long val; - if (__get_user(val, (unsigned long *)p) == 0) + if (probe_kernel_address(p, val) == 0) sprintf(str + i * 9, " %08lx", val); else sprintf(str + i * 9, " ????????"); @@ -120,8 +111,6 @@ static void dump_mem(const char *lvl, co } printk("%s%04lx:%s\n", lvl, first & 0xffff, str); } - - set_fs(fs); } static void dump_instr(const char *lvl, struct pt_regs *regs) @@ -129,25 +118,18 @@ static void dump_instr(const char *lvl, unsigned long addr = instruction_pointer(regs); const int thumb = thumb_mode(regs); const int width = thumb ? 4 : 8; - mm_segment_t fs; char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str; int i; - /* - * We need to switch to kernel mode so that we can use __get_user - * to safely read from kernel space. Note that we now dump the - * code first, just in case the backtrace kills us. - */ - fs = get_fs(); - set_fs(KERNEL_DS); - for (i = -4; i < 1 + !!thumb; i++) { unsigned int val, bad; - if (thumb) - bad = __get_user(val, &((u16 *)addr)[i]); - else - bad = __get_user(val, &((u32 *)addr)[i]); + if (thumb) { + u16 instr; + bad = probe_kernel_address(addr, instr); + val = instr; + } else + bad = probe_kernel_address(addr, val); if (!bad) p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ", @@ -158,8 +140,6 @@ static void dump_instr(const char *lvl, } } printk("%sCode: %s\n", lvl, str); - - set_fs(fs); } #ifdef CONFIG_ARM_UNWIND diff -urNp linux-3.6.3-3.fc18.x86_64_orig/arch/arm/mm/alignment.c linux-3.6.3-3.fc18.x86_64/arch/arm/mm/alignment.c --- linux-3.6.3-3.fc18.x86_64_orig/arch/arm/mm/alignment.c 2012-09-30 19:47:46.000000000 -0400 +++ linux-3.6.3-3.fc18.x86_64/arch/arm/mm/alignment.c 2012-10-23 12:40:14.804494230 -0400 @@ -750,7 +750,6 @@ do_alignment(unsigned long addr, unsigne unsigned long instr = 0, instrptr; int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs); unsigned int type; - mm_segment_t fs; unsigned int fault; u16 tinstr = 0; int isize = 4; @@ -761,16 +760,15 @@ do_alignment(unsigned long addr, unsigne instrptr = instruction_pointer(regs); - fs = get_fs(); - set_fs(KERNEL_DS); if (thumb_mode(regs)) { - fault = __get_user(tinstr, (u16 *)(instrptr & ~1)); + unsigned long ptr = instrptr; + fault = probe_kernel_address(ptr, tinstr); if (!fault) { if (cpu_architecture() >= CPU_ARCH_ARMv7 && IS_T32(tinstr)) { /* Thumb-2 32-bit */ u16 tinst2 = 0; - fault = __get_user(tinst2, (u16 *)(instrptr+2)); + fault = probe_kernel_address(ptr + 2, tinst2); instr = (tinstr << 16) | tinst2; thumb2_32b = 1; } else { @@ -779,8 +777,7 @@ do_alignment(unsigned long addr, unsigne } } } else - fault = __get_user(instr, (u32 *)instrptr); - set_fs(fs); + fault = probe_kernel_address(instrptr, instr); if (fault) { type = TYPE_FAULT;
_______________________________________________ arm mailing list arm@xxxxxxxxxxxxxxxxxxxxxxx https://admin.fedoraproject.org/mailman/listinfo/arm