Commit 1c754472 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Linus Torvalds

[PATCH] ppc32: Fix racy access to TI_FLAGS

The ppc32 syscall entry code could access the thread info flags in a
racy way, thus potentially losing bits sets there at interrupt time or
by another CPU, like NEED_RESCHED or SIGPENDING (ouch !).

This fixes it by moving the potentially racy bit to a different field (I
preferred that rather than turning the access into an atomic operation
for performances reasons).
parent f9f90f75
...@@ -171,9 +171,10 @@ _GLOBAL(DoSyscall) ...@@ -171,9 +171,10 @@ _GLOBAL(DoSyscall)
bl do_show_syscall bl do_show_syscall
#endif /* SHOW_SYSCALLS */ #endif /* SHOW_SYSCALLS */
rlwinm r10,r1,0,0,18 /* current_thread_info() */ rlwinm r10,r1,0,0,18 /* current_thread_info() */
lwz r11,TI_LOCAL_FLAGS(r10)
rlwinm r11,r11,0,~_TIFL_FORCE_NOERROR
stw r11,TI_LOCAL_FLAGS(r10)
lwz r11,TI_FLAGS(r10) lwz r11,TI_FLAGS(r10)
rlwinm r11,r11,0,~_TIF_FORCE_NOERROR
stw r11,TI_FLAGS(r10)
andi. r11,r11,_TIF_SYSCALL_TRACE andi. r11,r11,_TIF_SYSCALL_TRACE
bne- syscall_dotrace bne- syscall_dotrace
syscall_dotrace_cont: syscall_dotrace_cont:
...@@ -196,8 +197,8 @@ ret_from_syscall: ...@@ -196,8 +197,8 @@ ret_from_syscall:
cmpl 0,r3,r11 cmpl 0,r3,r11
rlwinm r12,r1,0,0,18 /* current_thread_info() */ rlwinm r12,r1,0,0,18 /* current_thread_info() */
blt+ 30f blt+ 30f
lwz r11,TI_FLAGS(r12) lwz r11,TI_LOCAL_FLAGS(r12)
andi. r11,r11,_TIF_FORCE_NOERROR andi. r11,r11,_TIFL_FORCE_NOERROR
bne 30f bne 30f
neg r3,r3 neg r3,r3
lwz r10,_CCR(r1) /* Set SO bit in CR */ lwz r10,_CCR(r1) /* Set SO bit in CR */
......
...@@ -49,7 +49,10 @@ struct pt_regs { ...@@ -49,7 +49,10 @@ struct pt_regs {
#define instruction_pointer(regs) ((regs)->nip) #define instruction_pointer(regs) ((regs)->nip)
#define user_mode(regs) (((regs)->msr & MSR_PR) != 0) #define user_mode(regs) (((regs)->msr & MSR_PR) != 0)
#define force_successful_syscall_return() set_thread_flag(TIF_FORCE_NOERROR) #define force_successful_syscall_return() \
do { \
current_thread_info()->local_flags |= _TIFL_FORCE_NOERROR; \
} while(0)
/* /*
* We use the least-significant bit of the trap field to indicate * We use the least-significant bit of the trap field to indicate
......
...@@ -18,6 +18,7 @@ struct thread_info { ...@@ -18,6 +18,7 @@ struct thread_info {
struct task_struct *task; /* main task structure */ struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */ struct exec_domain *exec_domain; /* execution domain */
unsigned long flags; /* low level flags */ unsigned long flags; /* low level flags */
unsigned long local_flags; /* non-racy flags */
int cpu; /* cpu we're on */ int cpu; /* cpu we're on */
int preempt_count; int preempt_count;
struct restart_block restart_block; struct restart_block restart_block;
...@@ -28,6 +29,7 @@ struct thread_info { ...@@ -28,6 +29,7 @@ struct thread_info {
.task = &tsk, \ .task = &tsk, \
.exec_domain = &default_exec_domain, \ .exec_domain = &default_exec_domain, \
.flags = 0, \ .flags = 0, \
.local_flags = 0, \
.cpu = 0, \ .cpu = 0, \
.preempt_count = 1, \ .preempt_count = 1, \
.restart_block = { \ .restart_block = { \
...@@ -69,8 +71,9 @@ static inline struct thread_info *current_thread_info(void) ...@@ -69,8 +71,9 @@ static inline struct thread_info *current_thread_info(void)
#define TI_TASK 0 #define TI_TASK 0
#define TI_EXECDOMAIN 4 #define TI_EXECDOMAIN 4
#define TI_FLAGS 8 #define TI_FLAGS 8
#define TI_CPU 12 #define TI_LOCAL_FLAGS 12
#define TI_PREEMPT 16 #define TI_CPU 16
#define TI_PREEMPT 20
#define PREEMPT_ACTIVE 0x4000000 #define PREEMPT_ACTIVE 0x4000000
...@@ -83,16 +86,22 @@ static inline struct thread_info *current_thread_info(void) ...@@ -83,16 +86,22 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling #define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling
TIF_NEED_RESCHED */ TIF_NEED_RESCHED */
#define TIF_FORCE_NOERROR 5 /* don't return error from current
syscall even if result < 0 */
/* as above, but as bit values */ /* as above, but as bit values */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
#define _TIF_FORCE_NOERROR (1<<TIF_FORCE_NOERROR)
/*
* Non racy (local) flags bit numbers
*/
#define TIFL_FORCE_NOERROR 0 /* don't return error from current
syscall even if result < 0 */
/* as above, but as bit values */
#define _TIFL_FORCE_NOERROR (1<<TIFL_FORCE_NOERROR)
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment