arch/tile: fix up some issues in calling do_work_pending()
First, we were at risk of handling thread-info flags, in particular do_signal(), when returning from kernel space. This could happen after a failed kernel_execve(), or when forking a kernel thread. The fix is to test in do_work_pending() for user_mode() and return immediately if so; we already had this test for one of the flags, so I just hoisted it to the top of the function. Second, if a ptraced process updated the callee-saved registers in the ptregs struct and then processed another thread-info flag, we would overwrite the modifications with the original callee-saved registers. To fix this, we add a register to note if we've already saved the registers once, and skip doing it on additional passes through the loop. To avoid a performance hit from the couple of extra instructions involved, I modified the GET_THREAD_INFO() macro to be guaranteed to be one instruction, then bundled it with adjacent instructions, yielding an overall net savings. Reported-By: Al Viro <viro@ZenIV.linux.org.uk> Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
This commit is contained in:
@@ -567,6 +567,10 @@ struct task_struct *__sched _switch_to(struct task_struct *prev,
|
||||
*/
|
||||
int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
|
||||
{
|
||||
/* If we enter in kernel mode, do nothing and exit the caller loop. */
|
||||
if (!user_mode(regs))
|
||||
return 0;
|
||||
|
||||
if (thread_info_flags & _TIF_NEED_RESCHED) {
|
||||
schedule();
|
||||
return 1;
|
||||
@@ -589,8 +593,7 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
|
||||
return 1;
|
||||
}
|
||||
if (thread_info_flags & _TIF_SINGLESTEP) {
|
||||
if ((regs->ex1 & SPR_EX_CONTEXT_1_1__PL_MASK) == 0)
|
||||
single_step_once(regs);
|
||||
single_step_once(regs);
|
||||
return 0;
|
||||
}
|
||||
panic("work_pending: bad flags %#x\n", thread_info_flags);
|
||||
|
Reference in New Issue
Block a user