diff options
author | Hugh Dickins <hugh@veritas.com> | 2006-10-31 13:39:31 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-10-31 22:52:48 -0500 |
commit | 5fe8e8b88e68e517637e3f8287f1fee89e2d9252 (patch) | |
tree | 5b7d1878e9d16107d7c8fcfa0d866d660372161d /include/asm-powerpc/current.h | |
parent | 302439d2167e0f1e01a6480ac40c06063f4e16a1 (diff) |
[POWERPC] Make current preempt-safe
Repeated -j20 kernel builds on a G5 Quad running an SMP PREEMPT kernel
would often collapse within a day, some exec failing with "Bad address".
In each case examined, load_elf_binary was doing a kernel_read, but
generic_file_aio_read's access_ok saw current->thread.fs.seg as USER_DS
instead of KERNEL_DS.
objdump of filemap.o shows gcc 4.1.0 emitting "mr r5,r13 ... ld r9,416(r5)"
here for get_paca()->__current, instead of the expected and much more usual
"ld r9,416(r13)"; I've seen other gcc4s do the same, but perhaps not gcc3s.
So, if the task is preempted and rescheduled on a different cpu in between
the mr and the ld, r5 will be looking at a different paca_struct from the
one it's now on, pick up the wrong __current, and perhaps the wrong seg.
Presumably much worse could happen elsewhere, though that split is rare.
Other architectures appear to be safe (x86_64's read_pda is more limiting
than get_paca), but ppc64 needs to force "current" into one instruction.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'include/asm-powerpc/current.h')
-rw-r--r-- | include/asm-powerpc/current.h | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/include/asm-powerpc/current.h b/include/asm-powerpc/current.h index 1938d6abd255..b8708aedf925 100644 --- a/include/asm-powerpc/current.h +++ b/include/asm-powerpc/current.h | |||
@@ -14,7 +14,17 @@ struct task_struct; | |||
14 | #ifdef __powerpc64__ | 14 | #ifdef __powerpc64__ |
15 | #include <asm/paca.h> | 15 | #include <asm/paca.h> |
16 | 16 | ||
17 | #define current (get_paca()->__current) | 17 | static inline struct task_struct *get_current(void) |
18 | { | ||
19 | struct task_struct *task; | ||
20 | |||
21 | __asm__ __volatile__("ld %0,%1(13)" | ||
22 | : "=r" (task) | ||
23 | : "i" (offsetof(struct paca_struct, __current))); | ||
24 | |||
25 | return task; | ||
26 | } | ||
27 | #define current get_current() | ||
18 | 28 | ||
19 | #else | 29 | #else |
20 | 30 | ||