Message ID | 1456949376-4910-12-git-send-email-cmetcalf@ezchip.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi Chris, On Wed, Mar 02, 2016 at 03:09:35PM -0500, Chris Metcalf wrote: > Currently ret_fast_syscall, work_pending, and ret_to_user form an ad-hoc > state machine that can be difficult to reason about due to duplicated > code and a large number of branch targets. > > This patch factors the common logic out into the existing > do_notify_resume function, converting the code to C in the process, > making the code more legible. > > This patch tries to closely mirror the existing behaviour while using > the usual C control flow primitives. As local_irq_{disable,enable} may > be instrumented, we balance exception entry (where we will almost most > likely enable IRQs) with a call to trace_hardirqs_on just before the > return to userspace. [...] > diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S > index 1f7f5a2b61bf..966d0d4308f2 100644 > --- a/arch/arm64/kernel/entry.S > +++ b/arch/arm64/kernel/entry.S > @@ -674,18 +674,13 @@ ret_fast_syscall_trace: > * Ok, we need to do extra processing, enter the slow path. > */ > work_pending: > - tbnz x1, #TIF_NEED_RESCHED, work_resched > - /* TIF_SIGPENDING, TIF_NOTIFY_RESUME or TIF_FOREIGN_FPSTATE case */ > mov x0, sp // 'regs' > - enable_irq // enable interrupts for do_notify_resume() > bl do_notify_resume > - b ret_to_user > -work_resched: > #ifdef CONFIG_TRACE_IRQFLAGS > - bl trace_hardirqs_off // the IRQs are off here, inform the tracing code > + bl trace_hardirqs_on // enabled while in userspace This doesn't look right to me. We only get here after running do_notify_resume, which returns with interrupts disabled. Do we not instead need to inform the tracing code that interrupts are disabled prior to calling do_notify_resume? > diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c > index e18c48cb6db1..3432e14b7d6e 100644 > --- a/arch/arm64/kernel/signal.c > +++ b/arch/arm64/kernel/signal.c > @@ -402,15 +402,29 @@ static void do_signal(struct pt_regs *regs) > asmlinkage void do_notify_resume(struct pt_regs *regs, > unsigned int thread_flags) > { > - if (thread_flags & _TIF_SIGPENDING) > - do_signal(regs); > + while (true) { > > - if (thread_flags & _TIF_NOTIFY_RESUME) { > - clear_thread_flag(TIF_NOTIFY_RESUME); > - tracehook_notify_resume(regs); > - } > + if (thread_flags & _TIF_NEED_RESCHED) { > + schedule(); > + } else { > + local_irq_enable(); > + > + if (thread_flags & _TIF_SIGPENDING) > + do_signal(regs); > > - if (thread_flags & _TIF_FOREIGN_FPSTATE) > - fpsimd_restore_current_state(); > + if (thread_flags & _TIF_NOTIFY_RESUME) { > + clear_thread_flag(TIF_NOTIFY_RESUME); > + tracehook_notify_resume(regs); > + } > + > + if (thread_flags & _TIF_FOREIGN_FPSTATE) > + fpsimd_restore_current_state(); > + } > > + local_irq_disable(); > + > + thread_flags = READ_ONCE(current_thread_info()->flags); > + if (!(thread_flags & _TIF_WORK_MASK)) > + break; > + } This might be easier to read as a do { ... } while. Will
On 03/04/2016 11:38 AM, Will Deacon wrote: > Hi Chris, > > On Wed, Mar 02, 2016 at 03:09:35PM -0500, Chris Metcalf wrote: >> Currently ret_fast_syscall, work_pending, and ret_to_user form an ad-hoc >> state machine that can be difficult to reason about due to duplicated >> code and a large number of branch targets. >> >> This patch factors the common logic out into the existing >> do_notify_resume function, converting the code to C in the process, >> making the code more legible. >> >> This patch tries to closely mirror the existing behaviour while using >> the usual C control flow primitives. As local_irq_{disable,enable} may >> be instrumented, we balance exception entry (where we will almost most >> likely enable IRQs) with a call to trace_hardirqs_on just before the >> return to userspace. > [...] > >> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S >> index 1f7f5a2b61bf..966d0d4308f2 100644 >> --- a/arch/arm64/kernel/entry.S >> +++ b/arch/arm64/kernel/entry.S >> @@ -674,18 +674,13 @@ ret_fast_syscall_trace: >> * Ok, we need to do extra processing, enter the slow path. >> */ >> work_pending: >> - tbnz x1, #TIF_NEED_RESCHED, work_resched >> - /* TIF_SIGPENDING, TIF_NOTIFY_RESUME or TIF_FOREIGN_FPSTATE case */ >> mov x0, sp // 'regs' >> - enable_irq // enable interrupts for do_notify_resume() >> bl do_notify_resume >> - b ret_to_user >> -work_resched: >> #ifdef CONFIG_TRACE_IRQFLAGS >> - bl trace_hardirqs_off // the IRQs are off here, inform the tracing code >> + bl trace_hardirqs_on // enabled while in userspace > This doesn't look right to me. We only get here after running > do_notify_resume, which returns with interrupts disabled. > > Do we not instead need to inform the tracing code that interrupts are > disabled prior to calling do_notify_resume? I think you are right about the trace_hardirqs_off prior to calling into do_notify_resume, given Catalin's recent commit to add it. I dropped it since I was moving schedule() into C code, but I suspect we'll see the same problem that Catalin saw with CONFIG_TRACE_IRQFLAGS without it. I'll copy the arch/arm approach and add a trace_hardirqs_off() at the top of do_notify_resume(). The trace_hardirqs_on I was copying from Mark Rutland's earlier patch: http://permalink.gmane.org/gmane.linux.ports.arm.kernel/467781 I don't know if it's necessary to flag that interrupts are enabled prior to returning to userspace; it may well not be. Mark, can you comment on what led you to add that trace_hardirqs_on? For now I've left both of them in there. >> diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c >> index e18c48cb6db1..3432e14b7d6e 100644 >> --- a/arch/arm64/kernel/signal.c >> +++ b/arch/arm64/kernel/signal.c >> @@ -402,15 +402,29 @@ static void do_signal(struct pt_regs *regs) >> asmlinkage void do_notify_resume(struct pt_regs *regs, >> unsigned int thread_flags) >> { >> - if (thread_flags & _TIF_SIGPENDING) >> - do_signal(regs); >> + while (true) { >> [...] >> + } > This might be easier to read as a do { ... } while. Yes, and in fact that's how I did it for arch/tile, as the maintainer. I picked up the arch/x86 version as more canonical to copy. But I'm more than happy to do it the other way :-). Fixed.
Hi, On Fri, Mar 04, 2016 at 03:02:47PM -0500, Chris Metcalf wrote: > On 03/04/2016 11:38 AM, Will Deacon wrote: > >Hi Chris, > > > >On Wed, Mar 02, 2016 at 03:09:35PM -0500, Chris Metcalf wrote: > >>Currently ret_fast_syscall, work_pending, and ret_to_user form an ad-hoc > >>state machine that can be difficult to reason about due to duplicated > >>code and a large number of branch targets. > >> > >>This patch factors the common logic out into the existing > >>do_notify_resume function, converting the code to C in the process, > >>making the code more legible. > >> > >>This patch tries to closely mirror the existing behaviour while using > >>the usual C control flow primitives. As local_irq_{disable,enable} may > >>be instrumented, we balance exception entry (where we will almost most > >>likely enable IRQs) with a call to trace_hardirqs_on just before the > >>return to userspace. > >[...] > > > >>diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S > >>index 1f7f5a2b61bf..966d0d4308f2 100644 > >>--- a/arch/arm64/kernel/entry.S > >>+++ b/arch/arm64/kernel/entry.S > >>@@ -674,18 +674,13 @@ ret_fast_syscall_trace: > >> * Ok, we need to do extra processing, enter the slow path. > >> */ > >> work_pending: > >>- tbnz x1, #TIF_NEED_RESCHED, work_resched > >>- /* TIF_SIGPENDING, TIF_NOTIFY_RESUME or TIF_FOREIGN_FPSTATE case */ > >> mov x0, sp // 'regs' > >>- enable_irq // enable interrupts for do_notify_resume() > >> bl do_notify_resume > >>- b ret_to_user > >>-work_resched: > >> #ifdef CONFIG_TRACE_IRQFLAGS > >>- bl trace_hardirqs_off // the IRQs are off here, inform the tracing code > >>+ bl trace_hardirqs_on // enabled while in userspace > >This doesn't look right to me. We only get here after running > >do_notify_resume, which returns with interrupts disabled. > > > >Do we not instead need to inform the tracing code that interrupts are > >disabled prior to calling do_notify_resume? > > I think you are right about the trace_hardirqs_off prior to > calling into do_notify_resume, given Catalin's recent commit to > add it. I dropped it since I was moving schedule() into C code, > but I suspect we'll see the same problem that Catalin saw with > CONFIG_TRACE_IRQFLAGS without it. I'll copy the arch/arm approach > and add a trace_hardirqs_off() at the top of do_notify_resume(). > > The trace_hardirqs_on I was copying from Mark Rutland's earlier patch: > > http://permalink.gmane.org/gmane.linux.ports.arm.kernel/467781 > > I don't know if it's necessary to flag that interrupts are enabled > prior to returning to userspace; it may well not be. Mark, can you > comment on what led you to add that trace_hardirqs_on? From what I recall, we didn't properly trace enabling IRQs in all the asm entry paths from userspace, and doing this made things appear balanced to the tracing code (as the existing behaviour of masking IRQs in assembly did). It was more expedient / simpler than fixing all the entry assembly to update the IRQ tracing state correctly, which I had expected to rework if/when moving the rest to C. Thanks, Mark.
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 1f7f5a2b61bf..966d0d4308f2 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -674,18 +674,13 @@ ret_fast_syscall_trace: * Ok, we need to do extra processing, enter the slow path. */ work_pending: - tbnz x1, #TIF_NEED_RESCHED, work_resched - /* TIF_SIGPENDING, TIF_NOTIFY_RESUME or TIF_FOREIGN_FPSTATE case */ mov x0, sp // 'regs' - enable_irq // enable interrupts for do_notify_resume() bl do_notify_resume - b ret_to_user -work_resched: #ifdef CONFIG_TRACE_IRQFLAGS - bl trace_hardirqs_off // the IRQs are off here, inform the tracing code + bl trace_hardirqs_on // enabled while in userspace #endif - bl schedule - + ldr x1, [tsk, #TI_FLAGS] // re-check for single-step + b finish_ret_to_user /* * "slow" syscall return path. */ @@ -694,6 +689,7 @@ ret_to_user: ldr x1, [tsk, #TI_FLAGS] and x2, x1, #_TIF_WORK_MASK cbnz x2, work_pending +finish_ret_to_user: enable_step_tsk x1, x2 kernel_exit 0 ENDPROC(ret_to_user) diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index e18c48cb6db1..3432e14b7d6e 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -402,15 +402,29 @@ static void do_signal(struct pt_regs *regs) asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int thread_flags) { - if (thread_flags & _TIF_SIGPENDING) - do_signal(regs); + while (true) { - if (thread_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); - } + if (thread_flags & _TIF_NEED_RESCHED) { + schedule(); + } else { + local_irq_enable(); + + if (thread_flags & _TIF_SIGPENDING) + do_signal(regs); - if (thread_flags & _TIF_FOREIGN_FPSTATE) - fpsimd_restore_current_state(); + if (thread_flags & _TIF_NOTIFY_RESUME) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } + + if (thread_flags & _TIF_FOREIGN_FPSTATE) + fpsimd_restore_current_state(); + } + local_irq_disable(); + + thread_flags = READ_ONCE(current_thread_info()->flags); + if (!(thread_flags & _TIF_WORK_MASK)) + break; + } }
Currently ret_fast_syscall, work_pending, and ret_to_user form an ad-hoc state machine that can be difficult to reason about due to duplicated code and a large number of branch targets. This patch factors the common logic out into the existing do_notify_resume function, converting the code to C in the process, making the code more legible. This patch tries to closely mirror the existing behaviour while using the usual C control flow primitives. As local_irq_{disable,enable} may be instrumented, we balance exception entry (where we will almost most likely enable IRQs) with a call to trace_hardirqs_on just before the return to userspace. Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com> --- arch/arm64/kernel/entry.S | 12 ++++-------- arch/arm64/kernel/signal.c | 30 ++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 16 deletions(-)