aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-03 13:16:43 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-03 17:01:40 -0400
commite419b4cc585680940bc42f8ca8a071d6023fb1bb (patch)
tree8fce0f12b7b2a0fdca7a937af137910011efa783 /arch
parentac001e76546523ec2ef05b2f7001d8fdc588d069 (diff)
vfs: make word-at-a-time accesses handle a non-existing page
It turns out that there are more cases than CONFIG_DEBUG_PAGEALLOC that can have holes in the kernel address space: it seems to happen easily with Xen, and it looks like the AMD gart64 code will also punch holes dynamically. Actually hitting that case is still very unlikely, so just do the access, and take an exception and fix it up for the very unlikely case of it being a page-crosser with no next page. And hey, this abstraction might even help other architectures that have other issues with unaligned word accesses than the possible missing next page. IOW, this could do the byte order magic too. Peter Anvin fixed a thinko in the shifting for the exception case. Reported-and-tested-by: Jana Saout <jana@saout.de> Cc: Peter Anvin <hpa@zytor.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/Kconfig2
-rw-r--r--arch/x86/include/asm/word-at-a-time.h33
2 files changed, 34 insertions, 1 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 1d14cc6b79ad..c9866b0b77d8 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -81,7 +81,7 @@ config X86
81 select CLKEVT_I8253 81 select CLKEVT_I8253
82 select ARCH_HAVE_NMI_SAFE_CMPXCHG 82 select ARCH_HAVE_NMI_SAFE_CMPXCHG
83 select GENERIC_IOMAP 83 select GENERIC_IOMAP
84 select DCACHE_WORD_ACCESS if !DEBUG_PAGEALLOC 84 select DCACHE_WORD_ACCESS
85 85
86config INSTRUCTION_DECODER 86config INSTRUCTION_DECODER
87 def_bool (KPROBES || PERF_EVENTS) 87 def_bool (KPROBES || PERF_EVENTS)
diff --git a/arch/x86/include/asm/word-at-a-time.h b/arch/x86/include/asm/word-at-a-time.h
index 6fe6767b7124..e58f03b206c3 100644
--- a/arch/x86/include/asm/word-at-a-time.h
+++ b/arch/x86/include/asm/word-at-a-time.h
@@ -43,4 +43,37 @@ static inline unsigned long has_zero(unsigned long a)
43 return ((a - REPEAT_BYTE(0x01)) & ~a) & REPEAT_BYTE(0x80); 43 return ((a - REPEAT_BYTE(0x01)) & ~a) & REPEAT_BYTE(0x80);
44} 44}
45 45
46/*
47 * Load an unaligned word from kernel space.
48 *
49 * In the (very unlikely) case of the word being a page-crosser
50 * and the next page not being mapped, take the exception and
51 * return zeroes in the non-existing part.
52 */
53static inline unsigned long load_unaligned_zeropad(const void *addr)
54{
55 unsigned long ret, dummy;
56
57 asm(
58 "1:\tmov %2,%0\n"
59 "2:\n"
60 ".section .fixup,\"ax\"\n"
61 "3:\t"
62 "lea %2,%1\n\t"
63 "and %3,%1\n\t"
64 "mov (%1),%0\n\t"
65 "leal %2,%%ecx\n\t"
66 "andl %4,%%ecx\n\t"
67 "shll $3,%%ecx\n\t"
68 "shr %%cl,%0\n\t"
69 "jmp 2b\n"
70 ".previous\n"
71 _ASM_EXTABLE(1b, 3b)
72 :"=&r" (ret),"=&c" (dummy)
73 :"m" (*(unsigned long *)addr),
74 "i" (-sizeof(unsigned long)),
75 "i" (sizeof(unsigned long)-1));
76 return ret;
77}
78
46#endif /* _ASM_WORD_AT_A_TIME_H */ 79#endif /* _ASM_WORD_AT_A_TIME_H */