On Tue, Jul 07, 2015 at 03:51:48AM -0700, tip-bot for Andy Lutomirski wrote: > Commit-ID: c5c46f59e4e7c1ab244b8d38f2b61d317df90bba > Gitweb: http://git.kernel.org/tip/c5c46f59e4e7c1ab244b8d38f2b61d317df90bba > Author: Andy Lutomirski <luto@xxxxxxxxxx> > AuthorDate: Fri, 3 Jul 2015 12:44:26 -0700 > Committer: Ingo Molnar <mingo@xxxxxxxxxx> > CommitDate: Tue, 7 Jul 2015 10:59:06 +0200 > > x86/entry: Add new, comprehensible entry and exit handlers written in C > > The current x86 entry and exit code, written in a mixture of assembly and > C code, is incomprehensible due to being open-coded in a lot of places > without coherent documentation. > > It appears to work primary by luck and duct tape: i.e. obvious runtime > failures were fixed on-demand, without re-thinking the design. > > Due to those reasons our confidence level in that code is low, and it is > very difficult to incrementally improve. > > Add new code written in C, in preparation for simply deleting the old > entry code. > > prepare_exit_to_usermode() is a new function that will handle all > slow path exits to user mode. It is called with IRQs disabled > and it leaves us in a state in which it is safe to immediately > return to user mode. IRQs must not be re-enabled at any point > after prepare_exit_to_usermode() returns and user mode is actually > entered. (We can, of course, fail to enter user mode and treat > that failure as a fresh entry to kernel mode.) > > All callers of do_notify_resume() will be migrated to call > prepare_exit_to_usermode() instead; prepare_exit_to_usermode() needs > to do everything that do_notify_resume() does today, but it also > takes care of scheduling and context tracking. Unlike > do_notify_resume(), it does not need to be called in a loop. > > syscall_return_slowpath() is exactly what it sounds like: it will > be called on any syscall exit slow path. It will replace > syscall_trace_leave() and it calls prepare_exit_to_usermode() on the > way out. > > Signed-off-by: Andy Lutomirski <luto@xxxxxxxxxx> > Cc: Andy Lutomirski <luto@xxxxxxxxxxxxxx> > Cc: Borislav Petkov <bp@xxxxxxxxx> > Cc: Brian Gerst <brgerst@xxxxxxxxx> > Cc: Denys Vlasenko <dvlasenk@xxxxxxxxxx> > Cc: Denys Vlasenko <vda.linux@xxxxxxxxxxxxxx> > Cc: Frederic Weisbecker <fweisbec@xxxxxxxxx> > Cc: H. Peter Anvin <hpa@xxxxxxxxx> > Cc: Kees Cook <keescook@xxxxxxxxxxxx> > Cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> > Cc: Oleg Nesterov <oleg@xxxxxxxxxx> > Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx> > Cc: Rik van Riel <riel@xxxxxxxxxx> > Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx> > Cc: paulmck@xxxxxxxxxxxxxxxxxx > Link: http://lkml.kernel.org/r/c57c8b87661a4152801d7d3786eac2d1a2f209dd.1435952415.git.luto@xxxxxxxxxx > [ Improved the changelog a bit. ] > Signed-off-by: Ingo Molnar <mingo@xxxxxxxxxx> > --- > arch/x86/entry/common.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 111 insertions(+), 1 deletion(-) > > diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c > index 9a327ee..febc530 100644 > --- a/arch/x86/entry/common.c > +++ b/arch/x86/entry/common.c > @@ -207,6 +207,7 @@ long syscall_trace_enter(struct pt_regs *regs) > return syscall_trace_enter_phase2(regs, arch, phase1_result); > } > > +/* Deprecated. */ > void syscall_trace_leave(struct pt_regs *regs) > { > bool step; > @@ -237,8 +238,117 @@ void syscall_trace_leave(struct pt_regs *regs) > user_enter(); > } > > +static struct thread_info *pt_regs_to_thread_info(struct pt_regs *regs) > +{ > + unsigned long top_of_stack = > + (unsigned long)(regs + 1) + TOP_OF_KERNEL_STACK_PADDING; > + return (struct thread_info *)(top_of_stack - THREAD_SIZE); > +} > + > +/* Called with IRQs disabled. */ > +__visible void prepare_exit_to_usermode(struct pt_regs *regs) > +{ > + if (WARN_ON(!irqs_disabled())) > + local_irq_disable(); > + > + /* > + * In order to return to user mode, we need to have IRQs off with > + * none of _TIF_SIGPENDING, _TIF_NOTIFY_RESUME, _TIF_USER_RETURN_NOTIFY, > + * _TIF_UPROBE, or _TIF_NEED_RESCHED set. Several of these flags > + * can be set at any time on preemptable kernels if we have IRQs on, > + * so we need to loop. Disabling preemption wouldn't help: doing the > + * work to clear some of the flags can sleep. > + */ > + while (true) { > + u32 cached_flags = > + READ_ONCE(pt_regs_to_thread_info(regs)->flags); > + > + if (!(cached_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | > + _TIF_UPROBE | _TIF_NEED_RESCHED))) > + break; > + > + /* We have work to do. */ > + local_irq_enable(); > + > + if (cached_flags & _TIF_NEED_RESCHED) > + schedule(); > + > + if (cached_flags & _TIF_UPROBE) > + uprobe_notify_resume(regs); > + > + /* deal with pending signal delivery */ > + if (cached_flags & _TIF_SIGPENDING) > + do_signal(regs); > + > + if (cached_flags & _TIF_NOTIFY_RESUME) { > + clear_thread_flag(TIF_NOTIFY_RESUME); > + tracehook_notify_resume(regs); > + } > + > + if (cached_flags & _TIF_USER_RETURN_NOTIFY) > + fire_user_return_notifiers(); > + > + /* Disable IRQs and retry */ > + local_irq_disable(); > + } I dreamed so many times about this loop in C! > + > + user_enter(); So now we are sure that we have only one call to user_enter() before resuming userspace, once we've completed everything, rescheduling, signals, etc... No more context tracking hacky round on signals and rescheduling? That's great. I need to check if other archs still need schedule_user(). Thanks a lot! -- To unsubscribe from this list: send the line "unsubscribe linux-tip-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html
![]() |