Skip to contentSkip to conversation

x86/entry: Consolidation - Part II

PATCH Superseded Thomas Gleixner 11 participants 56 messages Feb 25, 2020 – Mar 2, 2020

Subsystems (2)

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

cover x86/entry: Consolidation - Part II

Hi!

This is the second batch of a 73 patches series which consolidates the x86 entry code. The larger explanation is in the part I cover letter:

https://lore.kernel.org/r/[email protected]

I applies on top of part I which can be found via the above link.

This part cleans up the entry code and lifts the irq tracing and entry/exit work into C, which is a preliminary to make especially the exit work a generic infrastructure.

It has some rough edges as some of the ASM code is shared with exceptions/traps/interrupts, which will be addressed in later parts of the series.

This applies on top of part one which is available here:

git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git entry-v1-part1

To get both part 1 and part 2 pull from here:

git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git entry-v1-part2

Thanks,

tglx

8<---------------

 common.c          |   82 ++++++++++++++++++++++++++++++++++++++++--------------
 entry_32.S        |   24 ++-------------
 entry_64.S        |    6 ---
 entry_64_compat.S |   32 +++------------------
 4 files changed, 71 insertions(+), 73 deletions(-)
#1 lore raw

PATCH 1/8 x86/entry/64: Trace irqflags unconditionally on when returing to user space

User space cannot longer disable interrupts so trace return to user space unconditionally as IRQS_ON.

---
 arch/x86/entry/entry_64.S |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/entry/entry_64.S +2 -2
@@ -174,7 +174,7 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_h
 	movq	%rsp, %rsi
 	call	do_syscall_64		/* returns with IRQs disabled */
 
-	TRACE_IRQS_IRETQ		/* we're about to change IF */
+	TRACE_IRQS_ON			/* return enables interrupts */
 
 	/*
 	 * Try to use SYSRET instead of IRET if we're returning to
@@ -619,7 +619,7 @@ SYM_CODE_START_LOCAL(common_interrupt)
 .Lretint_user:
 	mov	%rsp,%rdi
 	call	prepare_exit_to_usermode
-	TRACE_IRQS_IRETQ
+	TRACE_IRQS_ON
 
 SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
 #ifdef CONFIG_DEBUG_ENTRY
maintainer
#2 lore raw

Re: [patch 1/8] x86/entry/64: Trace irqflags unconditionally on when returing to user space

Just formulations improvements:

Quoted 1 line

Subject: [patch 1/8] x86/entry/64: Trace irqflags unconditionally on when returing to user space

s/on //

Quoted 1 line · Thomas Gleixner

User space cannot longer disable interrupts so trace return to user space

"Userspace cannot disable interrupts any longer... "

Quoted 3 lines

unconditionally as IRQS_ON.

...

Signature · 4 lines
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Reviewed-by on v1 1/8
#4 lore raw

Re: [patch 1/8] x86/entry/64: Trace irqflags unconditionally on when returing to user space

In reply to Thomas Gleixner
Quoted 8 lines · Thomas Gleixner

User space cannot longer disable interrupts so trace return to user space unconditionally as IRQS_ON.

---
  arch/x86/entry/entry_64.S |    4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)

alex.

#5 lore raw

PATCH 2/8 x86/entry/common: Consolidate syscall entry code

In reply to Thomas Gleixner

All syscall entry points call enter_from_user_mode() and local_irq_enable(). Move that into an inline helper so the interrupt tracing can be moved into that helper later instead of sprinkling it all over the place.

---
 arch/x86/entry/common.c |   48 +++++++++++++++++++++++++++++++++---------------
 1 file changed, 33 insertions(+), 15 deletions(-)
arch/x86/entry/common.c +33 -15
@@ -49,6 +49,18 @@
 static inline void enter_from_user_mode(void) {}
 #endif
 
+/*
+ * All syscall entry variants call with interrupts disabled.
+ *
+ * Invoke context tracking if enabled and enable interrupts for further
+ * processing.
+ */
+static __always_inline void syscall_entry_fixups(void)
+{
+	enter_from_user_mode();
+	local_irq_enable();
+}
+
 static void do_audit_syscall_entry(struct pt_regs *regs, u32 arch)
 {
 #ifdef CONFIG_X86_64
@@ -279,13 +291,11 @@ static void syscall_slow_exit_work(struc
 }
 
 #ifdef CONFIG_X86_64
-__visible void do_syscall_64(unsigned long nr, struct pt_regs *regs)
+static __always_inline
+void do_syscall_64_irqs_on(unsigned long nr, struct pt_regs *regs)
 {
-	struct thread_info *ti;
+	struct thread_info *ti = current_thread_info();
 
-	enter_from_user_mode();
-	local_irq_enable();
-	ti = current_thread_info();
 	if (READ_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY)
 		nr = syscall_trace_enter(regs);
 
@@ -303,6 +313,12 @@ static void syscall_slow_exit_work(struc
 
 	syscall_return_slowpath(regs);
 }
+
+__visible void do_syscall_64(unsigned long nr, struct pt_regs *regs)
+{
+	syscall_entry_fixups();
+	do_syscall_64_irqs_on(nr, regs);
+}
 #endif
 
 #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
@@ -355,19 +371,17 @@ static __always_inline void do_syscall_3
 /* Handles int $0x80 */
 __visible void do_int80_syscall_32(struct pt_regs *regs)
 {
-	enter_from_user_mode();
-	local_irq_enable();
+	syscall_entry_fixups();
 	do_syscall_32_irqs_on(regs);
 }
 
-/* Returns 0 to return using IRET or 1 to return using SYSEXIT/SYSRETL. */
-__visible long do_fast_syscall_32(struct pt_regs *regs)
+/* Fast syscall 32bit variant */
+static __always_inline long do_fast_syscall_32_irqs_on(struct pt_regs *regs)
 {
 	/*
 	 * Called using the internal vDSO SYSENTER/SYSCALL32 calling
 	 * convention.  Adjust regs so it looks like we entered using int80.
 	 */
-
 	unsigned long landing_pad = (unsigned long)current->mm->context.vdso +
 		vdso_image_32.sym_int80_landing_pad;
 
@@ -378,10 +392,6 @@ static __always_inline void do_syscall_3
 	 */
 	regs->ip = landing_pad;
 
-	enter_from_user_mode();
-
-	local_irq_enable();
-
 	/* Fetch EBP from where the vDSO stashed it. */
 	if (
 #ifdef CONFIG_X86_64
@@ -437,4 +447,12 @@ static __always_inline void do_syscall_3
 		(regs->flags & (X86_EFLAGS_RF | X86_EFLAGS_TF | X86_EFLAGS_VM)) == 0;
 #endif
 }
-#endif
+
+/* Returns 0 to return using IRET or 1 to return using SYSEXIT/SYSRETL. */
+__visible long do_fast_syscall_32(struct pt_regs *regs)
+{
+	syscall_entry_fixups();
+	return do_fast_syscall_32_irqs_on(regs);
+}
+
+#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
maintainer
#6 lore raw

Re: [patch 2/8] x86/entry/common: Consolidate syscall entry code

Quoted 13 lines · Thomas Gleixner

All syscall entry points call enter_from_user_mode() and local_irq_enable(). Move that into an inline helper so the interrupt tracing can be moved into that helper later instead of sprinkling it all over the place.

---
 arch/x86/entry/common.c |   48 +++++++++++++++++++++++++++++++++---------------
 1 file changed, 33 insertions(+), 15 deletions(-)

arch/x86/entry/common.c line 58

Quoted 10 lines
arch/x86/entry/common.c +7 -0
@@ -49,6 +49,18 @@
 static inline void enter_from_user_mode(void) {}
 #endif
 
+/*
+ * All syscall entry variants call with interrupts disabled.
+ *
+ * Invoke context tracking if enabled and enable interrupts for further
+ * processing.
+ */
+static __always_inline void syscall_entry_fixups(void)

Function name needs a verb. "do_syscall_entry_fixups()" seems to fit well with where it is called or "apply_..." or so.

Rest looks ok.

Signature · 4 lines
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Reviewed-by on v1 2/8
#7 lore raw

Re: [patch 2/8] x86/entry/common: Consolidate syscall entry code

In reply to Thomas Gleixner
Quoted 6 lines · Thomas Gleixner

All syscall entry points call enter_from_user_mode() and local_irq_enable(). Move that into an inline helper so the interrupt tracing can be moved into that helper later instead of sprinkling it all over the place.

Reviewed-by on v1 2/8
#8 lore raw

Re: [patch 2/8] x86/entry/common: Consolidate syscall entry code

In reply to Thomas Gleixner
Quoted 10 lines · Thomas Gleixner

All syscall entry points call enter_from_user_mode() and local_irq_enable(). Move that into an inline helper so the interrupt tracing can be moved into that helper later instead of sprinkling it all over the place.

---
  arch/x86/entry/common.c |   48 +++++++++++++++++++++++++++++++++---------------
  1 file changed, 33 insertions(+), 15 deletions(-)

alex.

#9 lore raw

PATCH 3/8 x86/entry/common: Mark syscall entry points notrace/nokprobe

In reply to Thomas Gleixner

Anything before enter_from_user_mode() is not safe to be traced or probed.

---
 arch/x86/entry/common.c |    9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
arch/x86/entry/common.c +6 -3
@@ -314,11 +314,12 @@ void do_syscall_64_irqs_on(unsigned long
 	syscall_return_slowpath(regs);
 }
 
-__visible void do_syscall_64(unsigned long nr, struct pt_regs *regs)
+__visible notrace void do_syscall_64(unsigned long nr, struct pt_regs *regs)
 {
 	syscall_entry_fixups();
 	do_syscall_64_irqs_on(nr, regs);
 }
+NOKPROBE_SYMBOL(do_syscall_64);
 #endif
 
 #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
@@ -369,11 +370,12 @@ static __always_inline void do_syscall_3
 }
 
 /* Handles int $0x80 */
-__visible void do_int80_syscall_32(struct pt_regs *regs)
+__visible notrace void do_int80_syscall_32(struct pt_regs *regs)
 {
 	syscall_entry_fixups();
 	do_syscall_32_irqs_on(regs);
 }
+NOKPROBE_SYMBOL(do_int80_syscall_32);
 
 /* Fast syscall 32bit variant */
 static __always_inline long do_fast_syscall_32_irqs_on(struct pt_regs *regs)
@@ -449,10 +451,11 @@ static __always_inline long do_fast_sysc
 }
 
 /* Returns 0 to return using IRET or 1 to return using SYSEXIT/SYSRETL. */
-__visible long do_fast_syscall_32(struct pt_regs *regs)
+__visible notrace long do_fast_syscall_32(struct pt_regs *regs)
 {
 	syscall_entry_fixups();
 	return do_fast_syscall_32_irqs_on(regs);
 }
+NOKPROBE_SYMBOL(do_fast_syscall_32);
 
 #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
#10 lore raw

Re: [patch 3/8] x86/entry/common: Mark syscall entry points notrace/nokprobe

Quoted 1 line · Thomas Gleixner

Anything before enter_from_user_mode() is not safe to be traced or probed.

Perhaps the changelog should clarify as to why exactly it isn't safe to trace before enter_from_user_mode(). There have been so many patches on that lately that I'm not clear on that either.

Thanks.

#12 lore raw

PATCH 4/8 x86/entry: Move irq tracing on syscall entry to C-code

In reply to Thomas Gleixner

Now that the C entry points are safe, move the irq flags tracing code into the entry helper.

---
 arch/x86/entry/common.c          |    5 +++++
 arch/x86/entry/entry_32.S        |   12 ------------
 arch/x86/entry/entry_64.S        |    2 --
 arch/x86/entry/entry_64_compat.S |   18 ------------------
 4 files changed, 5 insertions(+), 32 deletions(-)
arch/x86/entry/common.c +5 -0
@@ -57,6 +57,11 @@ static inline void enter_from_user_mode(
  */
 static __always_inline void syscall_entry_fixups(void)
 {
+	/*
+	 * Usermode is traced as interrupts enabled, but the syscall entry
+	 * mechanisms disable interrupts. Tell the tracer.
+	 */
+	trace_hardirqs_off();
 	enter_from_user_mode();
 	local_irq_enable();
 }
arch/x86/entry/entry_32.S +0 -12
@@ -960,12 +960,6 @@ SYM_FUNC_START(entry_SYSENTER_32)
 	jnz	.Lsysenter_fix_flags
 .Lsysenter_flags_fixed:
 
-	/*
-	 * User mode is traced as though IRQs are on, and SYSENTER
-	 * turned them off.
-	 */
-	TRACE_IRQS_OFF
-
 	movl	%esp, %eax
 	call	do_fast_syscall_32
 	/* XEN PV guests always use IRET path */
@@ -1075,12 +1069,6 @@ SYM_FUNC_START(entry_INT80_32)
 
 	SAVE_ALL pt_regs_ax=$-ENOSYS switch_stacks=1	/* save rest */
 
-	/*
-	 * User mode is traced as though IRQs are on, and the interrupt gate
-	 * turned them off.
-	 */
-	TRACE_IRQS_OFF
-
 	movl	%esp, %eax
 	call	do_int80_syscall_32
 .Lsyscall_32_done:
arch/x86/entry/entry_64.S +0 -2
@@ -167,8 +167,6 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_h
 
 	PUSH_AND_CLEAR_REGS rax=$-ENOSYS
 
-	TRACE_IRQS_OFF
-
 	/* IRQs are off. */
 	movq	%rax, %rdi
 	movq	%rsp, %rsi
arch/x86/entry/entry_64_compat.S +0 -18
@@ -129,12 +129,6 @@ SYM_FUNC_START(entry_SYSENTER_compat)
 	jnz	.Lsysenter_fix_flags
 .Lsysenter_flags_fixed:
 
-	/*
-	 * User mode is traced as though IRQs are on, and SYSENTER
-	 * turned them off.
-	 */
-	TRACE_IRQS_OFF
-
 	movq	%rsp, %rdi
 	call	do_fast_syscall_32
 	/* XEN PV guests always use IRET path */
@@ -247,12 +241,6 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_aft
 	pushq   $0			/* pt_regs->r15 = 0 */
 	xorl	%r15d, %r15d		/* nospec   r15 */
 
-	/*
-	 * User mode is traced as though IRQs are on, and SYSENTER
-	 * turned them off.
-	 */
-	TRACE_IRQS_OFF
-
 	movq	%rsp, %rdi
 	call	do_fast_syscall_32
 	/* XEN PV guests always use IRET path */
@@ -403,12 +391,6 @@ SYM_CODE_START(entry_INT80_compat)
 	xorl	%r15d, %r15d		/* nospec   r15 */
 	cld
 
-	/*
-	 * User mode is traced as though IRQs are on, and the interrupt
-	 * gate turned them off.
-	 */
-	TRACE_IRQS_OFF
-
 	movq	%rsp, %rdi
 	call	do_int80_syscall_32
 .Lsyscall_32_done:
maintainer
#13 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 2 lines · Thomas Gleixner

Now that the C entry points are safe, move the irq flags tracing code into the entry helper.

I'm so confused.

Quoted 12 lines
---
 arch/x86/entry/common.c          |    5 +++++
 arch/x86/entry/entry_32.S        |   12 ------------
 arch/x86/entry/entry_64.S        |    2 --
 arch/x86/entry/entry_64_compat.S |   18 ------------------
 4 files changed, 5 insertions(+), 32 deletions(-)

arch/x86/entry/common.c static inline void enter_from_user_mode( · line 64

Quoted 8 lines
arch/x86/entry/common.c +5 -0
@@ -57,6 +57,11 @@ static inline void enter_from_user_mode(
  */
 static __always_inline void syscall_entry_fixups(void)
 {
+	/*
+	 * Usermode is traced as interrupts enabled, but the syscall entry
+	 * mechanisms disable interrupts. Tell the tracer.
+	 */
+	trace_hardirqs_off();

Your earlier patches suggest quite strongly that tracing isn't safe until enter_from_user_mode(). But trace_hardirqs_off() calls trace_irq_disable_rcuidle(), which looks [0] like a tracepoint.

Did you perhaps mean to do this *after* enter_from_user_mode()?

(My tracepoint-fu is pretty bad, and I can't actually find where it's defined as a tracepoint. But then it does nothing at all, so it must be a tracepoint, right?)

Quoted 3 lines
arch/x86/entry/common.c +0 -0
 	enter_from_user_mode();
 	local_irq_enable();
 }
#14 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 31 lines · Andy Lutomirski
Quoted 2 lines · Thomas Gleixner

Now that the C entry points are safe, move the irq flags tracing code into the entry helper.

I'm so confused.

Quoted 12 lines
---
 arch/x86/entry/common.c          |    5 +++++
 arch/x86/entry/entry_32.S        |   12 ------------
 arch/x86/entry/entry_64.S        |    2 --
 arch/x86/entry/entry_64_compat.S |   18 ------------------
 4 files changed, 5 insertions(+), 32 deletions(-)

arch/x86/entry/common.c static inline void enter_from_user_mode( · line 64

Quoted 8 lines
arch/x86/entry/common.c +5 -0
@@ -57,6 +57,11 @@ static inline void enter_from_user_mode(
  */
 static __always_inline void syscall_entry_fixups(void)
 {
+	/*
+	 * Usermode is traced as interrupts enabled, but the syscall entry
+	 * mechanisms disable interrupts. Tell the tracer.
+	 */
+	trace_hardirqs_off();

Your earlier patches suggest quite strongly that tracing isn't safe until enter_from_user_mode(). But trace_hardirqs_off() calls trace_irq_disable_rcuidle(), which looks [0] like a tracepoint.

Quoted 1 line

Did you perhaps mean to do this *after* enter_from_user_mode()?

aside from the fact that enter_from_user_mode() itself also has a tracepoint, the crucial detail is that we must not trace/kprobe the function calling this.

Specifically for #PF, because we need read_cr2() before this. See later patches.

#15 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 36 lines · Peter Zijlstra
Quoted 31 lines · Andy Lutomirski
Quoted 3 lines · Thomas Gleixner

Now that the C entry points are safe, move the irq flags tracing code into the entry helper.

I'm so confused.

Quoted 12 lines

---

arch/x86/entry/common.c          |    5 +++++
arch/x86/entry/entry_32.S        |   12 ------------
arch/x86/entry/entry_64.S        |    2 --
arch/x86/entry/entry_64_compat.S |   18 ------------------
4 files changed, 5 insertions(+), 32 deletions(-)

arch/x86/entry/common.c static inline void enter_from_user_mode( · line 64

Quoted 8 lines
arch/x86/entry/common.c +5 -0
@@ -57,6 +57,11 @@ static inline void enter_from_user_mode(
 */
 static __always_inline void syscall_entry_fixups(void)
 {
+    /*
+     * Usermode is traced as interrupts enabled, but the syscall entry
+     * mechanisms disable interrupts. Tell the tracer.
+     */
+    trace_hardirqs_off();

Your earlier patches suggest quite strongly that tracing isn't safe until enter_from_user_mode(). But trace_hardirqs_off() calls trace_irq_disable_rcuidle(), which looks [0] like a tracepoint.

Quoted 8 lines
Quoted 1 line

Did you perhaps mean to do this *after* enter_from_user_mode()?

aside from the fact that enter_from_user_mode() itself also has a tracepoint, the crucial detail is that we must not trace/kprobe the function calling this.

Specifically for #PF, because we need read_cr2() before this. See later patches.

Indeed. I’m fine with this patch, but I still don’t understand what the changelog is about. And I’m still rather baffled by most of the notrace annotations in the series.

#16 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 12 lines · Andy Lutomirski
Quoted 12 lines · Peter Zijlstra
Quoted 5 lines · Andy Lutomirski

Your earlier patches suggest quite strongly that tracing isn't safe until enter_from_user_mode(). But trace_hardirqs_off() calls trace_irq_disable_rcuidle(), which looks [0] like a tracepoint.

Did you perhaps mean to do this *after* enter_from_user_mode()?

aside from the fact that enter_from_user_mode() itself also has a tracepoint, the crucial detail is that we must not trace/kprobe the function calling this.

Quoted 5 lines
Quoted 2 lines

Specifically for #PF, because we need read_cr2() before this. See later patches.

Indeed. I’m fine with this patch, but I still don’t understand what the changelog is about.

Yeah, the changelog is not really helpful. Let me fix that.

Quoted 2 lines

And I’m still rather baffled by most of the notrace annotations in the series.

As discussed on IRC, this might be too broad, but then I rather have the actual C-entry points neither traceable nor probable in general and relax this by calling functions which can be traced and probed.

My rationale for this decision was that enter_from_user_mode() is marked notrace/noprobe as well, so I kept the protection scope the same as we had in the ASM maze which is marked noprobe already.

Thanks,

tglx

#17 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 24 lines · Thomas Gleixner
Quoted 12 lines · Andy Lutomirski
Quoted 12 lines · Peter Zijlstra
Quoted 5 lines · Andy Lutomirski

Your earlier patches suggest quite strongly that tracing isn't safe until enter_from_user_mode(). But trace_hardirqs_off() calls trace_irq_disable_rcuidle(), which looks [0] like a tracepoint.

Did you perhaps mean to do this *after* enter_from_user_mode()?

aside from the fact that enter_from_user_mode() itself also has a tracepoint, the crucial detail is that we must not trace/kprobe the function calling this.

Quoted 5 lines
Quoted 2 lines

Specifically for #PF, because we need read_cr2() before this. See later patches.

Indeed. I’m fine with this patch, but I still don’t understand what the changelog is about.

Yeah, the changelog is not really helpful. Let me fix that.

Quoted 2 lines

And I’m still rather baffled by most of the notrace annotations in the series.

Quoted 7 lines

As discussed on IRC, this might be too broad, but then I rather have the actual C-entry points neither traceable nor probable in general and relax this by calling functions which can be traced and probed.

My rationale for this decision was that enter_from_user_mode() is marked notrace/noprobe as well, so I kept the protection scope the same as we had in the ASM maze which is marked noprobe already.

I have second thoughts vs. tracing in this context.

While the tracer itself seems to handle this correctly, what about things like BPF programs which can be attached to tracepoints and function trace entries?

Is that really safe _before_ context tracking has updated RCU state?

Thanks,

tglx

#18 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 37 lines · Thomas Gleixner
Quoted 24 lines · Thomas Gleixner
Quoted 12 lines · Andy Lutomirski
Quoted 12 lines
Quoted 12 lines · Peter Zijlstra
Quoted 5 lines · Andy Lutomirski

Your earlier patches suggest quite strongly that tracing isn't safe until enter_from_user_mode(). But trace_hardirqs_off() calls trace_irq_disable_rcuidle(), which looks [0] like a tracepoint.

Did you perhaps mean to do this *after* enter_from_user_mode()?

aside from the fact that enter_from_user_mode() itself also has a tracepoint, the crucial detail is that we must not trace/kprobe the function calling this.

Quoted 5 lines
Quoted 2 lines
Quoted 2 lines

Specifically for #PF, because we need read_cr2() before this. See later patches.

Indeed. I’m fine with this patch, but I still don’t understand what the changelog is about.

Yeah, the changelog is not really helpful. Let me fix that.

Quoted 2 lines

And I’m still rather baffled by most of the notrace annotations in the series.

Quoted 7 lines

As discussed on IRC, this might be too broad, but then I rather have the actual C-entry points neither traceable nor probable in general and relax this by calling functions which can be traced and probed.

My rationale for this decision was that enter_from_user_mode() is marked notrace/noprobe as well, so I kept the protection scope the same as we had in the ASM maze which is marked noprobe already.

Quoted 5 lines

I have second thoughts vs. tracing in this context.

While the tracer itself seems to handle this correctly, what about things like BPF programs which can be attached to tracepoints and function trace entries?

I think that everything using the tracing code, including BPF, should either do its own rcuidle stuff or explicitly not execute if we’re not in CONTEXT_KERNEL. That is, we probably need to patch BPF.

Quoted 8 lines

Is that really safe _before_ context tracking has updated RCU state?

Thanks,

tglx

#19 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 7 lines · On Sat, 29 Feb 2020 11:25:24 -0800 Andy Lutomirski <[email protected]> wrote:
Quoted 3 lines

While the tracer itself seems to handle this correctly, what about things like BPF programs which can be attached to tracepoints and function trace entries?

I think that everything using the tracing code, including BPF, should either do its own rcuidle stuff or explicitly not execute if we’re not in CONTEXT_KERNEL. That is, we probably need to patch BPF.

That's basically the route we are taking.

-- Steve

#20 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 7 lines · Steven Rostedt
Quoted 4 lines · On Sat, 29 Feb 2020 11:25:24 -0800 Andy Lutomirski <[email protected]> wrote:
Quoted 3 lines

While the tracer itself seems to handle this correctly, what about things like BPF programs which can be attached to tracepoints and function trace entries?

Quoted 5 lines
Quoted 3 lines

I think that everything using the tracing code, including BPF, should either do its own rcuidle stuff or explicitly not execute if we’re not in CONTEXT_KERNEL. That is, we probably need to patch BPF.

That's basically the route we are taking.

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Thanks,

tglx

#21 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 17 lines · Thomas Gleixner
Quoted 11 lines · Steven Rostedt
Quoted 7 lines · On Sat, 29 Feb 2020 11:25:24 -0800 Andy Lutomirski <[email protected]> wrote:
Quoted 3 lines

While the tracer itself seems to handle this correctly, what about things like BPF programs which can be attached to tracepoints and function trace entries?

I think that everything using the tracing code, including BPF, should either do its own rcuidle stuff or explicitly not execute if we’re not in CONTEXT_KERNEL. That is, we probably need to patch BPF.

Quoted 5 lines
Quoted 1 line

That's basically the route we are taking.

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Quoted 4 lines

Thanks,

tglx

#22 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

Thanks,

tglx

maintainer
#23 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 7 lines · Thomas Gleixner
Quoted 5 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Quoted 5 lines
Quoted 2 lines

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
        if (this_cpu_read(tracing_irq_cpu)) {
                if (!in_nmi())
                        trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
                tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
                this_cpu_write(tracing_irq_cpu, 0);
        }

        lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

# ./include/trace/events/preemptirq.h:40:
DEFINE_EVENT(preemptirq_template, irq_enable,

with a bunch of asm magic that looks like it's probably a tracepoint. I still don't quite see where the "_rcuidle" went.

But I also don't see why this is any different from any other tracepoint.

--Andy

#24 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 47 lines · Andy Lutomirski
Quoted 11 lines · Thomas Gleixner
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
        if (this_cpu_read(tracing_irq_cpu)) {
                if (!in_nmi())
                        trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
                tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
                this_cpu_write(tracing_irq_cpu, 0);
        }

        lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

Quoted 3 lines

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

DEFINE_EVENT
DECLARE_TRACE

    __DECLARE_TRACE
       __DECLARE_TRACE_RCU
         static inline void trace_##name##_rcuidle(proto)
            __DO_TRACE
               if (rcuidle)
                  ....
Quoted 1 line

But I also don't see why this is any different from any other tracepoint.

Indeed. I took a wrong turn at some point in the macro jungle :)

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Thanks,

tglx

#25 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 61 lines · Thomas Gleixner
Quoted 47 lines · Andy Lutomirski
Quoted 11 lines · Thomas Gleixner
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
        if (this_cpu_read(tracing_irq_cpu)) {
                if (!in_nmi())
                        trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
                tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
                this_cpu_write(tracing_irq_cpu, 0);
        }

        lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

Quoted 3 lines

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

DEFINE_EVENT
DECLARE_TRACE

    __DECLARE_TRACE
       __DECLARE_TRACE_RCU
         static inline void trace_##name##_rcuidle(proto)
            __DO_TRACE
               if (rcuidle)
                  ....
Quoted 7 lines
Quoted 1 line

But I also don't see why this is any different from any other tracepoint.

Indeed. I took a wrong turn at some point in the macro jungle :)

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Definitely, any such code needs to use tricks similar to that of the tracing code. Or instead use something like SRCU, which is OK with readers from idle. Or use something like Steve Rostedt's workqueue-based approach, though please be very careful with this latter, lest the battery-powered embedded guys come after you for waking up idle CPUs too often. ;-)

Thanx, Paul

maintainer
#26 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 71 lines · Paul E. McKenney
Quoted 61 lines · Thomas Gleixner
Quoted 47 lines · Andy Lutomirski
Quoted 11 lines · Thomas Gleixner
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
        if (this_cpu_read(tracing_irq_cpu)) {
                if (!in_nmi())
                        trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
                tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
                this_cpu_write(tracing_irq_cpu, 0);
        }

        lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

Quoted 3 lines

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

DEFINE_EVENT
DECLARE_TRACE

    __DECLARE_TRACE
       __DECLARE_TRACE_RCU
         static inline void trace_##name##_rcuidle(proto)
            __DO_TRACE
               if (rcuidle)
                  ....
Quoted 7 lines
Quoted 1 line

But I also don't see why this is any different from any other tracepoint.

Indeed. I took a wrong turn at some point in the macro jungle :)

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Quoted 7 lines

Definitely, any such code needs to use tricks similar to that of the tracing code. Or instead use something like SRCU, which is OK with readers from idle. Or use something like Steve Rostedt's workqueue-based approach, though please be very careful with this latter, lest the battery-powered embedded guys come after you for waking up idle CPUs too often. ;-)

Are we okay if we somehow ensure that all the entry code before enter_from_user_mode() only does rcuidle tracing variants and has kprobes off? Including for BPF use cases?

It would be *really* nice if we could statically verify this, as has been mentioned elsewhere in the thread. It would also probably be good enough if we could do it at runtime. Maybe with lockdep on, we verify rcu state in tracepoints even if the tracepoint isn't active? And we could plausibly have some widget that could inject something into *every* kprobeable function to check rcu state.

--Andy

#27 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 79 lines · Andy Lutomirski
Quoted 71 lines · Paul E. McKenney
Quoted 61 lines · Thomas Gleixner
Quoted 47 lines · Andy Lutomirski
Quoted 11 lines · Thomas Gleixner
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
        if (this_cpu_read(tracing_irq_cpu)) {
                if (!in_nmi())
                        trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
                tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
                this_cpu_write(tracing_irq_cpu, 0);
        }

        lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

Quoted 3 lines

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

DEFINE_EVENT
DECLARE_TRACE

    __DECLARE_TRACE
       __DECLARE_TRACE_RCU
         static inline void trace_##name##_rcuidle(proto)
            __DO_TRACE
               if (rcuidle)
                  ....
Quoted 7 lines
Quoted 1 line

But I also don't see why this is any different from any other tracepoint.

Indeed. I took a wrong turn at some point in the macro jungle :)

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Quoted 6 lines

Definitely, any such code needs to use tricks similar to that of the tracing code. Or instead use something like SRCU, which is OK with readers from idle. Or use something like Steve Rostedt's workqueue-based approach, though please be very careful with this latter, lest the battery-powered embedded guys come after you for waking up idle CPUs too often. ;-)

Quoted 3 lines

Are we okay if we somehow ensure that all the entry code before enter_from_user_mode() only does rcuidle tracing variants and has kprobes off? Including for BPF use cases?

That would work, though if BPF used SRCU instead of RCU, this would be unnecessary. Sadly, SRCU has full memory barriers in each of srcu_read_lock() and srcu_read_unlock(), but we are working on it. (As always, no promises!)

Quoted 6 lines

It would be *really* nice if we could statically verify this, as has been mentioned elsewhere in the thread. It would also probably be good enough if we could do it at runtime. Maybe with lockdep on, we verify rcu state in tracepoints even if the tracepoint isn't active? And we could plausibly have some widget that could inject something into *every* kprobeable function to check rcu state.

Or just have at least one testing step that activates all tracepoints, but with lockdep enabled?

Thanx, Paul

#28 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 100 lines · Paul E. McKenney
Quoted 79 lines · Andy Lutomirski
Quoted 72 lines · Paul E. McKenney
Quoted 61 lines · Thomas Gleixner
Quoted 47 lines · Andy Lutomirski
Quoted 11 lines · Thomas Gleixner
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
       if (this_cpu_read(tracing_irq_cpu)) {
               if (!in_nmi())
                       trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
               tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
               this_cpu_write(tracing_irq_cpu, 0);
       }

       lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

Quoted 3 lines

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

DEFINE_EVENT
DECLARE_TRACE
__DECLARE_TRACE

      __DECLARE_TRACE_RCU
        static inline void trace_##name##_rcuidle(proto)
           __DO_TRACE
              if (rcuidle)
                 ....
Quoted 7 lines
Quoted 1 line

But I also don't see why this is any different from any other tracepoint.

Indeed. I took a wrong turn at some point in the macro jungle :)

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Quoted 6 lines

Definitely, any such code needs to use tricks similar to that of the tracing code. Or instead use something like SRCU, which is OK with readers from idle. Or use something like Steve Rostedt's workqueue-based approach, though please be very careful with this latter, lest the battery-powered embedded guys come after you for waking up idle CPUs too often. ;-)

Quoted 3 lines

Are we okay if we somehow ensure that all the entry code before enter_from_user_mode() only does rcuidle tracing variants and has kprobes off? Including for BPF use cases?

That would work, though if BPF used SRCU instead of RCU, this would be unnecessary. Sadly, SRCU has full memory barriers in each of srcu_read_lock() and srcu_read_unlock(), but we are working on it. (As always, no promises!)

Quoted 6 lines

It would be *really* nice if we could statically verify this, as has been mentioned elsewhere in the thread. It would also probably be good enough if we could do it at runtime. Maybe with lockdep on, we verify rcu state in tracepoints even if the tracepoint isn't active? And we could plausibly have some widget that could inject something into *every* kprobeable function to check rcu state.

Quoted 2 lines

Or just have at least one testing step that activates all tracepoints, but with lockdep enabled?

Also kprobe.

I don’t suppose we could make notrace imply nokprobe. Then all kprobeable functions would also have entry/exit tracepoints, right?

#29 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 100 lines · Andy Lutomirski
Quoted 100 lines · Paul E. McKenney
Quoted 79 lines · Andy Lutomirski
Quoted 72 lines · Paul E. McKenney
Quoted 61 lines · Thomas Gleixner
Quoted 47 lines · Andy Lutomirski
Quoted 11 lines · Thomas Gleixner
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
       if (this_cpu_read(tracing_irq_cpu)) {
               if (!in_nmi())
                       trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
               tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
               this_cpu_write(tracing_irq_cpu, 0);
       }

       lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

Quoted 3 lines

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

DEFINE_EVENT
DECLARE_TRACE
__DECLARE_TRACE

      __DECLARE_TRACE_RCU
        static inline void trace_##name##_rcuidle(proto)
           __DO_TRACE
              if (rcuidle)
                 ....
Quoted 7 lines
Quoted 1 line

But I also don't see why this is any different from any other tracepoint.

Indeed. I took a wrong turn at some point in the macro jungle :)

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Quoted 6 lines

Definitely, any such code needs to use tricks similar to that of the tracing code. Or instead use something like SRCU, which is OK with readers from idle. Or use something like Steve Rostedt's workqueue-based approach, though please be very careful with this latter, lest the battery-powered embedded guys come after you for waking up idle CPUs too often. ;-)

Quoted 3 lines

Are we okay if we somehow ensure that all the entry code before enter_from_user_mode() only does rcuidle tracing variants and has kprobes off? Including for BPF use cases?

That would work, though if BPF used SRCU instead of RCU, this would be unnecessary. Sadly, SRCU has full memory barriers in each of srcu_read_lock() and srcu_read_unlock(), but we are working on it. (As always, no promises!)

Quoted 6 lines

It would be *really* nice if we could statically verify this, as has been mentioned elsewhere in the thread. It would also probably be good enough if we could do it at runtime. Maybe with lockdep on, we verify rcu state in tracepoints even if the tracepoint isn't active? And we could plausibly have some widget that could inject something into *every* kprobeable function to check rcu state.

Quoted 4 lines
Quoted 2 lines

Or just have at least one testing step that activates all tracepoints, but with lockdep enabled?

Also kprobe.

I didn't realize we could test all kprobe points easily, but yes, that would also be good.

Quoted 1 line

I don’t suppose we could make notrace imply nokprobe. Then all kprobeable functions would also have entry/exit tracepoints, right?

On this, I must defer to the tracing and kprobes people.

Thanx, Paul

#30 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

In reply to Andy Lutomirski
Quoted 98 lines · On Sun, 1 Mar 2020 11:39:42 -0800 Andy Lutomirski <[email protected]> wrote:
Quoted 98 lines · Paul E. McKenney
Quoted 79 lines · Andy Lutomirski
Quoted 72 lines · Paul E. McKenney
Quoted 61 lines · Thomas Gleixner
Quoted 47 lines · Andy Lutomirski
Quoted 11 lines · Thomas Gleixner
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
       if (this_cpu_read(tracing_irq_cpu)) {
               if (!in_nmi())
                       trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
               tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
               this_cpu_write(tracing_irq_cpu, 0);
       }

       lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

Quoted 3 lines

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

DEFINE_EVENT
DECLARE_TRACE
__DECLARE_TRACE

      __DECLARE_TRACE_RCU
        static inline void trace_##name##_rcuidle(proto)
           __DO_TRACE
              if (rcuidle)
                 ....
Quoted 7 lines
Quoted 1 line

But I also don't see why this is any different from any other tracepoint.

Indeed. I took a wrong turn at some point in the macro jungle :)

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Quoted 6 lines

Definitely, any such code needs to use tricks similar to that of the tracing code. Or instead use something like SRCU, which is OK with readers from idle. Or use something like Steve Rostedt's workqueue-based approach, though please be very careful with this latter, lest the battery-powered embedded guys come after you for waking up idle CPUs too often. ;-)

Quoted 3 lines

Are we okay if we somehow ensure that all the entry code before enter_from_user_mode() only does rcuidle tracing variants and has kprobes off? Including for BPF use cases?

That would work, though if BPF used SRCU instead of RCU, this would be unnecessary. Sadly, SRCU has full memory barriers in each of srcu_read_lock() and srcu_read_unlock(), but we are working on it. (As always, no promises!)

Quoted 6 lines

It would be *really* nice if we could statically verify this, as has been mentioned elsewhere in the thread. It would also probably be good enough if we could do it at runtime. Maybe with lockdep on, we verify rcu state in tracepoints even if the tracepoint isn't active? And we could plausibly have some widget that could inject something into *every* kprobeable function to check rcu state.

Quoted 7 lines
Quoted 2 lines

Or just have at least one testing step that activates all tracepoints, but with lockdep enabled?

Also kprobe.

I don’t suppose we could make notrace imply nokprobe. Then all kprobeable functions would also have entry/exit tracepoints, right?

There was some code before that prevented a kprobe from being allowed in something that was not in the ftrace mcount table (which would make this happen). But I think that was changed because it was too restrictive.

Masami?

-- Steve

#31 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 94 lines · On Sun, 1 Mar 2020 19:35:01 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 91 lines · On Sun, 1 Mar 2020 11:39:42 -0800 Andy Lutomirski <[email protected]> wrote:
Quoted 91 lines · Paul E. McKenney
Quoted 79 lines · Andy Lutomirski
Quoted 72 lines · Paul E. McKenney
Quoted 61 lines · Thomas Gleixner
Quoted 47 lines · Andy Lutomirski
Quoted 11 lines · Thomas Gleixner
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
       if (this_cpu_read(tracing_irq_cpu)) {
               if (!in_nmi())
                       trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
               tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
               this_cpu_write(tracing_irq_cpu, 0);
       }

       lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

Quoted 3 lines

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

DEFINE_EVENT
DECLARE_TRACE
__DECLARE_TRACE

      __DECLARE_TRACE_RCU
        static inline void trace_##name##_rcuidle(proto)
           __DO_TRACE
              if (rcuidle)
                 ....
Quoted 7 lines
Quoted 1 line

But I also don't see why this is any different from any other tracepoint.

Indeed. I took a wrong turn at some point in the macro jungle :)

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Quoted 6 lines

Definitely, any such code needs to use tricks similar to that of the tracing code. Or instead use something like SRCU, which is OK with readers from idle. Or use something like Steve Rostedt's workqueue-based approach, though please be very careful with this latter, lest the battery-powered embedded guys come after you for waking up idle CPUs too often. ;-)

Quoted 3 lines

Are we okay if we somehow ensure that all the entry code before enter_from_user_mode() only does rcuidle tracing variants and has kprobes off? Including for BPF use cases?

That would work, though if BPF used SRCU instead of RCU, this would be unnecessary. Sadly, SRCU has full memory barriers in each of srcu_read_lock() and srcu_read_unlock(), but we are working on it. (As always, no promises!)

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

It would be *really* nice if we could statically verify this, as has been mentioned elsewhere in the thread. It would also probably be good enough if we could do it at runtime. Maybe with lockdep on, we verify rcu state in tracepoints even if the tracepoint isn't active? And we could plausibly have some widget that could inject something into *every* kprobeable function to check rcu state.

I'm still not clear about this point, should I check rcuidle in kprobes int3 handler or jump optimized handler? (int3 handler will run in irq context so is not able to use srcu anyway...) Maybe I missed the point.

Quoted 6 lines
Quoted 6 lines
Quoted 3 lines

Or just have at least one testing step that activates all tracepoints, but with lockdep enabled?

Also kprobe.

Quoted 7 lines
Quoted 2 lines

I don’t suppose we could make notrace imply nokprobe. Then all kprobeable functions would also have entry/exit tracepoints, right?

There was some code before that prevented a kprobe from being allowed in something that was not in the ftrace mcount table (which would make this happen). But I think that was changed because it was too restrictive.

Would you mean CONFIG_KPROBE_EVENTS_ON_NOTRACE? By default notrace means noprobe too now. With CONFIG_KPROBE_EVENTS_ON_NOTRACE=y, we can put kprobe events on notrace functions. So if you unsure, we can put a kprobe on those functions and see what happens.
(Note that this is only for kprobe event, not kprobes itself)

It is actually very restrictive, but it is hard to make a whitelist maually, especially if the CC_FLAGS_FTRACE is removed while building.

Thank you,

Signature · 1 line
Masami Hiramatsu <[email protected]>
#32 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

In reply to Andy Lutomirski
Quoted 84 lines · Andy Lutomirski
Quoted 71 lines · Paul E. McKenney
Quoted 61 lines · Thomas Gleixner
Quoted 47 lines · Andy Lutomirski
Quoted 11 lines · Thomas Gleixner
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
        if (this_cpu_read(tracing_irq_cpu)) {
                if (!in_nmi())
                        trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
                tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
                this_cpu_write(tracing_irq_cpu, 0);
        }

        lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

Quoted 3 lines

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

DEFINE_EVENT
DECLARE_TRACE

    __DECLARE_TRACE
       __DECLARE_TRACE_RCU
         static inline void trace_##name##_rcuidle(proto)
            __DO_TRACE
               if (rcuidle)
                  ....
Quoted 7 lines
Quoted 1 line

But I also don't see why this is any different from any other tracepoint.

Indeed. I took a wrong turn at some point in the macro jungle :)

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Quoted 7 lines

Definitely, any such code needs to use tricks similar to that of the tracing code. Or instead use something like SRCU, which is OK with readers from idle. Or use something like Steve Rostedt's workqueue-based approach, though please be very careful with this latter, lest the battery-powered embedded guys come after you for waking up idle CPUs too often. ;-)

Are we okay if we somehow ensure that all the entry code before enter_from_user_mode() only does rcuidle tracing variants and has kprobes off? Including for BPF use cases?

Quoted 6 lines

It would be *really* nice if we could statically verify this, as has been mentioned elsewhere in the thread. It would also probably be good enough if we could do it at runtime. Maybe with lockdep on, we verify rcu state in tracepoints even if the tracepoint isn't active? And we could plausibly have some widget that could inject something into *every* kprobeable function to check rcu state.

You are talking about verifying that a non-rcuidle tracepoint is not called into when RCU is not watching right? I think that's fine, though I feel lockdep kernels should not be slowed down any more than they already are. I feel over time if we add too many checks to lockdep enabled kernels, then it becomes too slow even for "debug" kernels. May be it is time for a CONFIG_LOCKDEP_SLOW or some such? And then anyone who wants to go crazy on runtime checking can do so. I myself want to add a few.

Note that the checking is being added into "non rcu-idle" tracepoints many of which are probably always called when RCU is watching, making such checking useless for those tracepoints (and slowing them down however less).

Also another note would be that the whole reason we are getting rid of the "make RCU watch when rcuidle" logic in DO_TRACE is because it is slow for tracepoints that are frequently called into. Another reason to do it is because tracepoint callbacks are expected to know what they are doing and turn on RCU watching as appropriate (as consensus on the matter suggests).

thanks,

- Joel

#33 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 104 lines · Joel Fernandes
Quoted 84 lines · Andy Lutomirski
Quoted 72 lines · Paul E. McKenney
Quoted 61 lines · Thomas Gleixner
Quoted 47 lines · Andy Lutomirski
Quoted 11 lines · Thomas Gleixner
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
       if (this_cpu_read(tracing_irq_cpu)) {
               if (!in_nmi())
                       trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
               tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
               this_cpu_write(tracing_irq_cpu, 0);
       }

       lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

Quoted 3 lines

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

DEFINE_EVENT
DECLARE_TRACE
__DECLARE_TRACE

      __DECLARE_TRACE_RCU
        static inline void trace_##name##_rcuidle(proto)
           __DO_TRACE
              if (rcuidle)
                 ....
Quoted 7 lines
Quoted 1 line

But I also don't see why this is any different from any other tracepoint.

Indeed. I took a wrong turn at some point in the macro jungle :)

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Quoted 7 lines

Definitely, any such code needs to use tricks similar to that of the tracing code. Or instead use something like SRCU, which is OK with readers from idle. Or use something like Steve Rostedt's workqueue-based approach, though please be very careful with this latter, lest the battery-powered embedded guys come after you for waking up idle CPUs too often. ;-)

Are we okay if we somehow ensure that all the entry code before enter_from_user_mode() only does rcuidle tracing variants and has kprobes off? Including for BPF use cases?

Quoted 6 lines

It would be *really* nice if we could statically verify this, as has been mentioned elsewhere in the thread. It would also probably be good enough if we could do it at runtime. Maybe with lockdep on, we verify rcu state in tracepoints even if the tracepoint isn't active? And we could plausibly have some widget that could inject something into *every* kprobeable function to check rcu state.

You are talking about verifying that a non-rcuidle tracepoint is not called into when RCU is not watching right? I think that's fine, though I feel lockdep kernels should not be slowed down any more than they already are. I feel over time if we add too many checks to lockdep enabled kernels, then it becomes too slow even for "debug" kernels. May be it is time for a CONFIG_LOCKDEP_SLOW or some such? And then anyone who wants to go crazy on runtime checking can do so. I myself want to add a few.

Quoted 4 lines

Note that the checking is being added into "non rcu-idle" tracepoints many of which are probably always called when RCU is watching, making such checking useless for those tracepoints (and slowing them down however less).

Indeed. Static analysis would help a lot here.

Quoted 5 lines

Also another note would be that the whole reason we are getting rid of the "make RCU watch when rcuidle" logic in DO_TRACE is because it is slow for tracepoints that are frequently called into. Another reason to do it is because tracepoint callbacks are expected to know what they are doing and turn on RCU watching as appropriate (as consensus on the matter suggests).

Whoa there. We arch people need crystal clear rules as to what tracepoints can be called in what contexts and what is the responsibility of the callbacks.

Quoted 5 lines

thanks,

- Joel

#34 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 117 lines · Andy Lutomirski
Quoted 104 lines · Joel Fernandes
Quoted 84 lines · Andy Lutomirski
Quoted 72 lines · Paul E. McKenney
Quoted 61 lines · Thomas Gleixner
Quoted 47 lines · Andy Lutomirski
Quoted 11 lines · Thomas Gleixner
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
       if (this_cpu_read(tracing_irq_cpu)) {
               if (!in_nmi())
                       trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
               tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
               this_cpu_write(tracing_irq_cpu, 0);
       }

       lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

Quoted 3 lines

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

DEFINE_EVENT
DECLARE_TRACE
__DECLARE_TRACE

      __DECLARE_TRACE_RCU
        static inline void trace_##name##_rcuidle(proto)
           __DO_TRACE
              if (rcuidle)
                 ....
Quoted 7 lines
Quoted 1 line

But I also don't see why this is any different from any other tracepoint.

Indeed. I took a wrong turn at some point in the macro jungle :)

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Quoted 7 lines

Definitely, any such code needs to use tricks similar to that of the tracing code. Or instead use something like SRCU, which is OK with readers from idle. Or use something like Steve Rostedt's workqueue-based approach, though please be very careful with this latter, lest the battery-powered embedded guys come after you for waking up idle CPUs too often. ;-)

Are we okay if we somehow ensure that all the entry code before enter_from_user_mode() only does rcuidle tracing variants and has kprobes off? Including for BPF use cases?

Quoted 6 lines

It would be *really* nice if we could statically verify this, as has been mentioned elsewhere in the thread. It would also probably be good enough if we could do it at runtime. Maybe with lockdep on, we verify rcu state in tracepoints even if the tracepoint isn't active? And we could plausibly have some widget that could inject something into *every* kprobeable function to check rcu state.

You are talking about verifying that a non-rcuidle tracepoint is not called into when RCU is not watching right? I think that's fine, though I feel lockdep kernels should not be slowed down any more than they already are. I feel over time if we add too many checks to lockdep enabled kernels, then it becomes too slow even for "debug" kernels. May be it is time for a CONFIG_LOCKDEP_SLOW or some such? And then anyone who wants to go crazy on runtime checking can do so. I myself want to add a few.

Quoted 4 lines

Note that the checking is being added into "non rcu-idle" tracepoints many of which are probably always called when RCU is watching, making such checking useless for those tracepoints (and slowing them down however less).

Indeed. Static analysis would help a lot here.

Quoted 5 lines

Also another note would be that the whole reason we are getting rid of the "make RCU watch when rcuidle" logic in DO_TRACE is because it is slow for tracepoints that are frequently called into. Another reason to do it is because tracepoint callbacks are expected to know what they are doing and turn on RCU watching as appropriate (as consensus on the matter suggests).

Quoted 4 lines

Whoa there. We arch people need crystal clear rules as to what tracepoints can be called in what contexts and what is the responsibility of the callbacks.

The direction that Peter, Mathieu and Steve are going is that callbacks registered on "rcu idle" tracepoints need to turn on "RCU watching" themselves. Such as perf. Turning on "RCU watching" is non-free as I tested in 2017 and we removed it back then, but it was added right back when perf started splatting. Now it is being removed again, and the turning on of RCU's eyes happens in the perf callback itself since perf uses RCU.

If you are calling trace_.._rcuidle(), can you not ensure that RCU is watching by calling the appropriate RCU APIs in your callbacks? Or did I miss the point?

thanks,

- Joel

#35 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

Quoted 134 lines · Joel Fernandes
Quoted 117 lines · Andy Lutomirski
Quoted 104 lines
Quoted 3 lines · Joel Fernandes
Quoted 84 lines · Andy Lutomirski
Quoted 72 lines · Paul E. McKenney
Quoted 61 lines · Thomas Gleixner
Quoted 47 lines · Andy Lutomirski
Quoted 11 lines · Thomas Gleixner
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

That has:

void trace_hardirqs_on(void)

{
      if (this_cpu_read(tracing_irq_cpu)) {
              if (!in_nmi())
                      trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
              tracer_hardirqs_on(CALLER_ADDR0, CALLER_ADDR1);
              this_cpu_write(tracing_irq_cpu, 0);
      }

      lockdep_hardirqs_on(CALLER_ADDR0);
}

EXPORT_SYMBOL(trace_hardirqs_on);
NOKPROBE_SYMBOL(trace_hardirqs_on);

But this calls trace_irq_enable_rcuidle(), and that's the part of the macro maze I got lost in. I found:

#ifdef CONFIG_TRACE_IRQFLAGS DEFINE_EVENT(preemptirq_template, irq_disable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));

DEFINE_EVENT(preemptirq_template, irq_enable,
TP_PROTO(unsigned long ip, unsigned long parent_ip), TP_ARGS(ip, parent_ip));
#else
#define trace_irq_enable(...)
#define trace_irq_disable(...)
#define trace_irq_enable_rcuidle(...)
#define trace_irq_disable_rcuidle(...)
#endif

Quoted 3 lines

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

DEFINE_EVENT
DECLARE_TRACE
__DECLARE_TRACE

     __DECLARE_TRACE_RCU
       static inline void trace_##name##_rcuidle(proto)
          __DO_TRACE
             if (rcuidle)
                ....
Quoted 7 lines
Quoted 1 line

But I also don't see why this is any different from any other tracepoint.

Indeed. I took a wrong turn at some point in the macro jungle :)

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Quoted 7 lines

Definitely, any such code needs to use tricks similar to that of the tracing code. Or instead use something like SRCU, which is OK with readers from idle. Or use something like Steve Rostedt's workqueue-based approach, though please be very careful with this latter, lest the battery-powered embedded guys come after you for waking up idle CPUs too often. ;-)

Are we okay if we somehow ensure that all the entry code before enter_from_user_mode() only does rcuidle tracing variants and has kprobes off? Including for BPF use cases?

Quoted 6 lines

It would be *really* nice if we could statically verify this, as has been mentioned elsewhere in the thread. It would also probably be good enough if we could do it at runtime. Maybe with lockdep on, we verify rcu state in tracepoints even if the tracepoint isn't active? And we could plausibly have some widget that could inject something into *every* kprobeable function to check rcu state.

You are talking about verifying that a non-rcuidle tracepoint is not called into when RCU is not watching right? I think that's fine, though I feel lockdep kernels should not be slowed down any more than they already are. I feel over time if we add too many checks to lockdep enabled kernels, then it becomes too slow even for "debug" kernels. May be it is time for a CONFIG_LOCKDEP_SLOW or some such? And then anyone who wants to go crazy on runtime checking can do so. I myself want to add a few.

Quoted 4 lines

Note that the checking is being added into "non rcu-idle" tracepoints many of which are probably always called when RCU is watching, making such checking useless for those tracepoints (and slowing them down however less).

Indeed. Static analysis would help a lot here.

Quoted 5 lines

Also another note would be that the whole reason we are getting rid of the "make RCU watch when rcuidle" logic in DO_TRACE is because it is slow for tracepoints that are frequently called into. Another reason to do it is because tracepoint callbacks are expected to know what they are doing and turn on RCU watching as appropriate (as consensus on the matter suggests).

Quoted 4 lines

Whoa there. We arch people need crystal clear rules as to what tracepoints can be called in what contexts and what is the responsibility of the callbacks.

The direction that Peter, Mathieu and Steve are going is that callbacks registered on "rcu idle" tracepoints need to turn on "RCU watching" themselves. Such as perf. Turning on "RCU watching" is non-free as I tested in 2017 and we removed it back then, but it was added right back when perf started splatting. Now it is being removed again, and the turning on of RCU's eyes happens in the perf callback itself since perf uses RCU.

Quoted 3 lines

If you are calling trace_.._rcuidle(), can you not ensure that RCU is watching by calling the appropriate RCU APIs in your callbacks? Or did I miss the point?

Unless I’ve misunderstood you, the problem is that the callback and the caller are totally different subsystems. I can count the number of people who know which tracepoints need RCU turned on in their callbacks without using any fingers (tglx and I are still at least a bit confused— I’m not convinced *anyone* knows for sure).

I think we need some credible rule for which events need special handling in their callbacks, and then we need to ensure that all subsystems that install callbacks, including BPF, follow the rule. It should not be up to the author of a BPF program to get this right.

Quoted 5 lines

thanks,

- Joel

#36 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

In reply to Andy Lutomirski
Quoted 13 lines · Andy Lutomirski
Quoted 11 lines · Paul E. McKenney
Quoted 3 lines

So tracing itself is fine, but then if you have probes or bpf programs attached to a tracepoint these use rcu_read_lock()/unlock() which is obviosly wrong in rcuidle context.

Definitely, any such code needs to use tricks similar to that of the tracing code. Or instead use something like SRCU, which is OK with readers from idle. Or use something like Steve Rostedt's workqueue-based approach, though please be very careful with this latter, lest the battery-powered embedded guys come after you for waking up idle CPUs too often. ;-)

Quoted 3 lines

Are we okay if we somehow ensure that all the entry code before enter_from_user_mode() only does rcuidle tracing variants and has kprobes off? Including for BPF use cases?

I think this is the right thing to do. The only requirement we have _before_ enter_from_user_mode() is to tell lockdep that interrupts are off. There is not even the need for a real tracepoint IMO. The fact that the lockdep call is hidden in that tracepoint is just an implementation detail.

That would clearly set the rules straight: Anything low level entry code before enter_from_user_mode() returns is neither probable nor traceable.

I know that some people will argue that this is too restrictive in terms of instrumentation, but OTOH the whole low level entry code has to be excluded from instrumentation anyway, so having a dozen instructions more excluded does not matter at all. Keep it simple!

Quoted 6 lines

It would be *really* nice if we could statically verify this, as has been mentioned elsewhere in the thread. It would also probably be good enough if we could do it at runtime. Maybe with lockdep on, we verify rcu state in tracepoints even if the tracepoint isn't active? And we could plausibly have some widget that could inject something into *every* kprobeable function to check rcu state.

That surely would be useful.

Thanks,

tglx

#37 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

In reply to Andy Lutomirski
Quoted 9 lines · On Sun, 1 Mar 2020 08:00:01 -0800 Andy Lutomirski <[email protected]> wrote:

But the DEFINE_EVENT doesn't have the "_rcuidle" part. And that's where I got lost in the macro maze. I looked at the gcc asm output, and there is, indeed:

# ./include/trace/events/preemptirq.h:40:
DEFINE_EVENT(preemptirq_template, irq_enable,

with a bunch of asm magic that looks like it's probably a tracepoint. I still don't quite see where the "_rcuidle" went.

See the code in include/linux/tracepoint.h and search for "rcuidle" there. All defined trace events get a "_rcuidle" version, but as it is declared a static inline, then they only show up if they are used.

-- Steve

#38 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

In reply to Thomas Gleixner
Quoted 11 lines · On Sun, 01 Mar 2020 16:21:15 +0100 Thomas Gleixner <[email protected]> wrote:
Quoted 7 lines · Andy Lutomirski
Quoted 4 lines · Thomas Gleixner

Ok, but for the time being anything before/after CONTEXT_KERNEL is unsafe except trace_hardirq_off/on() as those trace functions do not allow to attach anything AFAICT.

Can you point to whatever makes those particular functions special? I failed to follow the macro maze.

Those are not tracepoints and not going through the macro maze. See kernel/trace/trace_preemptirq.c

For the latency tracing, they do call into the tracing infrastructure, not just lockdep. And Joel Fernandez did try to make these into trace events as well.

-- Steve

Reviewed-by on v1 4/8
#40 lore raw

Re: [patch 4/8] x86/entry: Move irq tracing on syscall entry to C-code

In reply to Thomas Gleixner
Quoted 11 lines · Thomas Gleixner

Now that the C entry points are safe, move the irq flags tracing code into the entry helper.

---
  arch/x86/entry/common.c          |    5 +++++
  arch/x86/entry/entry_32.S        |   12 ------------
  arch/x86/entry/entry_64.S        |    2 --
  arch/x86/entry/entry_64_compat.S |   18 ------------------
  4 files changed, 5 insertions(+), 32 deletions(-)

alex.

#41 lore raw

PATCH 5/8 x86/entry/common: Provide trace/kprobe safe exit to user space functions

In reply to Thomas Gleixner

Split prepare_enter_to_user_mode() and mark it notrace/noprobe so the irq flags tracing on return can be put into it.

---
 arch/x86/entry/common.c |   15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)
arch/x86/entry/common.c +11 -4
@@ -196,7 +196,7 @@ static void exit_to_usermode_loop(struct
 }
 
 /* Called with IRQs disabled. */
-__visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
+static inline void __prepare_exit_to_usermode(struct pt_regs *regs)
 {
 	struct thread_info *ti = current_thread_info();
 	u32 cached_flags;
@@ -241,6 +241,12 @@ static void exit_to_usermode_loop(struct
 	mds_user_clear_cpu_buffers();
 }
 
+__visible inline notrace void prepare_exit_to_usermode(struct pt_regs *regs)
+{
+	__prepare_exit_to_usermode(regs);
+}
+NOKPROBE_SYMBOL(prepare_exit_to_usermode);
+
 #define SYSCALL_EXIT_WORK_FLAGS				\
 	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT |	\
 	 _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT)
@@ -271,7 +277,7 @@ static void syscall_slow_exit_work(struc
  * Called with IRQs on and fully valid regs.  Returns with IRQs off in a
  * state such that we can immediately switch to user mode.
  */
-__visible inline void syscall_return_slowpath(struct pt_regs *regs)
+__visible inline notrace void syscall_return_slowpath(struct pt_regs *regs)
 {
 	struct thread_info *ti = current_thread_info();
 	u32 cached_flags = READ_ONCE(ti->flags);
@@ -292,8 +298,9 @@ static void syscall_slow_exit_work(struc
 		syscall_slow_exit_work(regs, cached_flags);
 
 	local_irq_disable();
-	prepare_exit_to_usermode(regs);
+	__prepare_exit_to_usermode(regs);
 }
+NOKPROBE_SYMBOL(syscall_return_slowpath);
 
 #ifdef CONFIG_X86_64
 static __always_inline
@@ -417,7 +424,7 @@ static __always_inline long do_fast_sysc
 		/* User code screwed up. */
 		local_irq_disable();
 		regs->ax = -EFAULT;
-		prepare_exit_to_usermode(regs);
+		__prepare_exit_to_usermode(regs);
 		return 0;	/* Keep it simple: use IRET. */
 	}
 
maintainer
#42 lore raw

Re: [patch 5/8] x86/entry/common: Provide trace/kprobe safe exit to user space functions

Quoted 2 lines · Thomas Gleixner

Split prepare_enter_to_user_mode() and mark it notrace/noprobe so the irq flags tracing on return can be put into it.

Is our tooling clever enough for thsi to do anything? You have a static inline that is only called in one place, and the caller is notrace and NOKPROBE. Does this actually allow tracing in the static inline callee?

--Andy

#43 lore raw

Re: [patch 5/8] x86/entry/common: Provide trace/kprobe safe exit to user space functions

Quoted 7 lines · Andy Lutomirski
Quoted 2 lines · Thomas Gleixner

Split prepare_enter_to_user_mode() and mark it notrace/noprobe so the irq flags tracing on return can be put into it.

Is our tooling clever enough for thsi to do anything? You have a static inline that is only called in one place, and the caller is notrace and NOKPROBE. Does this actually allow tracing in the static inline callee?

tracing, no, but the NOKPROBE on inline functions is buggered afaiu.

#44 lore raw

Re: [patch 5/8] x86/entry/common: Provide trace/kprobe safe exit to user space functions

In reply to Thomas Gleixner
Quoted 2 lines · Thomas Gleixner

Split prepare_enter_to_user_mode() and mark it notrace/noprobe so the irq flags tracing on return can be put into it.

This splits prepare_exit_to_usermode() not prepare_enter_to_user_mode().

Quoted 17 lines
---
  arch/x86/entry/common.c |   15 +++++++++++----
  1 file changed, 11 insertions(+), 4 deletions(-)
arch/x86/entry/common.c +1 -1
@@ -196,7 +196,7 @@ static void exit_to_usermode_loop(struct
  }
 
  /* Called with IRQs disabled. */
-__visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
+static inline void __prepare_exit_to_usermode(struct pt_regs *regs)
  {
  	struct thread_info *ti = current_thread_info();
  	u32 cached_flags;

arch/x86/entry/common.c static void exit_to_usermode_loop(struct · line 248

Quoted 8 lines
arch/x86/entry/common.c +5 -0
@@ -241,6 +241,12 @@ static void exit_to_usermode_loop(struct
  	mds_user_clear_cpu_buffers();
  }
 
+__visible inline notrace void prepare_exit_to_usermode(struct pt_regs *regs)
+{
+	__prepare_exit_to_usermode(regs);
+}
+NOKPROBE_SYMBOL(prepare_exit_to_usermode);

Would it be worth grouping local_irq_disable() and prepare_exit_to_usermode() (similarly to what was done entry with syscall_entry_fixups()) and then put trace_hardirqs_on() there too. For example:

static __always_inline void syscall_exit_fixups(struct pt_regs *regs)

{
        local_irq_disable();
        prepare_exit_to_usermode(regs);
        trace_hardirqs_on();
}

Or is this planned once prepare_exit_from_usermode() is not used by idtentry anymore?

Thanks,

alex.

Quoted 33 lines
arch/x86/entry/common.c +4 -3
  #define SYSCALL_EXIT_WORK_FLAGS				\
  	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT |	\
  	 _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT)
@@ -271,7 +277,7 @@ static void syscall_slow_exit_work(struc
   * Called with IRQs on and fully valid regs.  Returns with IRQs off in a
   * state such that we can immediately switch to user mode.
   */
-__visible inline void syscall_return_slowpath(struct pt_regs *regs)
+__visible inline notrace void syscall_return_slowpath(struct pt_regs *regs)
  {
  	struct thread_info *ti = current_thread_info();
  	u32 cached_flags = READ_ONCE(ti->flags);
@@ -292,8 +298,9 @@ static void syscall_slow_exit_work(struc
  		syscall_slow_exit_work(regs, cached_flags);
 
  	local_irq_disable();
-	prepare_exit_to_usermode(regs);
+	__prepare_exit_to_usermode(regs);
  }
+NOKPROBE_SYMBOL(syscall_return_slowpath);
 
  #ifdef CONFIG_X86_64
  static __always_inline
@@ -417,7 +424,7 @@ static __always_inline long do_fast_sysc
  		/* User code screwed up. */
  		local_irq_disable();
  		regs->ax = -EFAULT;
-		prepare_exit_to_usermode(regs);
+		__prepare_exit_to_usermode(regs);
  		return 0;	/* Keep it simple: use IRET. */
  	}
 
#45 lore raw

Re: [patch 5/8] x86/entry/common: Provide trace/kprobe safe exit to user space functions

Quoted 5 lines · Alexandre Chartre
Quoted 2 lines · Thomas Gleixner

Split prepare_enter_to_user_mode() and mark it notrace/noprobe so the irq flags tracing on return can be put into it.

This splits prepare_exit_to_usermode() not prepare_enter_to_user_mode().

Ooops

Quoted 22 lines
Quoted 7 lines

/* Called with IRQs disabled. */

arch/x86/entry/common.c +1 -1
-__visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
+static inline void __prepare_exit_to_usermode(struct pt_regs *regs)
  {
  	struct thread_info *ti = current_thread_info();
  	u32 cached_flags;

arch/x86/entry/common.c static void exit_to_usermode_loop(struct · line 248

Quoted 8 lines
arch/x86/entry/common.c +5 -0
@@ -241,6 +241,12 @@ static void exit_to_usermode_loop(struct
  	mds_user_clear_cpu_buffers();
  }
 
+__visible inline notrace void prepare_exit_to_usermode(struct pt_regs *regs)
+{
+	__prepare_exit_to_usermode(regs);
+}
+NOKPROBE_SYMBOL(prepare_exit_to_usermode);

Would it be worth grouping local_irq_disable() and prepare_exit_to_usermode() (similarly to what was done entry with syscall_entry_fixups()) and then put trace_hardirqs_on() there too. For example:

static __always_inline void syscall_exit_fixups(struct pt_regs *regs)

Quoted 8 lines
{
         local_irq_disable();
         prepare_exit_to_usermode(regs);
         trace_hardirqs_on();
}

Or is this planned once prepare_exit_from_usermode() is not used by idtentry anymore?

This should be consolidated at the very end when all the interrupt muck is done, but maybe I forgot.

#46 lore raw

PATCH 6/8 x86/entry: Move irq tracing to syscall_slow_exit_work

In reply to Thomas Gleixner

which removes the ASM IRQ tracepoints.

---
 arch/x86/entry/common.c   |    2 ++
 arch/x86/entry/entry_32.S |    3 ++-
 arch/x86/entry/entry_64.S |    3 ---
 3 files changed, 4 insertions(+), 4 deletions(-)
arch/x86/entry/common.c +2 -0
@@ -299,6 +299,8 @@ static void syscall_slow_exit_work(struc
 
 	local_irq_disable();
 	__prepare_exit_to_usermode(regs);
+	/* Return to user space enables interrupts */
+	trace_hardirqs_on();
 }
 NOKPROBE_SYMBOL(syscall_return_slowpath);
 
arch/x86/entry/entry_32.S +2 -1
@@ -812,7 +812,7 @@ SYM_CODE_START(ret_from_fork)
 	movl    %esp, %eax
 	call    syscall_return_slowpath
 	STACKLEAK_ERASE
-	jmp     restore_all
+	jmp     restore_all_switch_stack
 
 	/* kernel thread */
 1:	movl	%edi, %eax
@@ -1077,6 +1077,7 @@ SYM_FUNC_START(entry_INT80_32)
 
 restore_all:
 	TRACE_IRQS_IRET
+restore_all_switch_stack:
 	SWITCH_TO_ENTRY_STACK
 	CHECK_AND_APPLY_ESPFIX
 .Lrestore_nocheck:
arch/x86/entry/entry_64.S +0 -3
@@ -172,8 +172,6 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_h
 	movq	%rsp, %rsi
 	call	do_syscall_64		/* returns with IRQs disabled */
 
-	TRACE_IRQS_ON			/* return enables interrupts */
-
 	/*
 	 * Try to use SYSRET instead of IRET if we're returning to
 	 * a completely clean 64-bit userspace context.  If we're not,
@@ -340,7 +338,6 @@ SYM_CODE_START(ret_from_fork)
 	UNWIND_HINT_REGS
 	movq	%rsp, %rdi
 	call	syscall_return_slowpath	/* returns with IRQs disabled */
-	TRACE_IRQS_ON			/* user mode is traced as IRQS on */
 	jmp	swapgs_restore_regs_and_return_to_usermode
 
 1:
maintainer
#47 lore raw

Re: [patch 6/8] x86/entry: Move irq tracing to syscall_slow_exit_work

Quoted 1 line · Thomas Gleixner

which removes the ASM IRQ tracepoints.

It's still after we re-enter rcuidle. Is tracing actually okay?

I always had the impression that tracing was okay in rcuidle mode because the tracing code was smart enough to do the right thing, but your patch 3/8 changelog says:

Anything before enter_from_user_mode() is not safe to be traced or probed.

--Andy

#48 lore raw

Re: [patch 6/8] x86/entry: Move irq tracing to syscall_slow_exit_work

In reply to Thomas Gleixner
Quoted 1 line · Thomas Gleixner

which removes the ASM IRQ tracepoints.

This moves irq tracing to syscall_return_slowpath, not syscall_slow_exit_work, right?

alex.

Quoted 57 lines
---
  arch/x86/entry/common.c   |    2 ++
  arch/x86/entry/entry_32.S |    3 ++-
  arch/x86/entry/entry_64.S |    3 ---
  3 files changed, 4 insertions(+), 4 deletions(-)
arch/x86/entry/common.c +2 -0
@@ -299,6 +299,8 @@ static void syscall_slow_exit_work(struc
 
  	local_irq_disable();
  	__prepare_exit_to_usermode(regs);
+	/* Return to user space enables interrupts */
+	trace_hardirqs_on();
  }
  NOKPROBE_SYMBOL(syscall_return_slowpath);
 
arch/x86/entry/entry_32.S +2 -1
@@ -812,7 +812,7 @@ SYM_CODE_START(ret_from_fork)
  	movl    %esp, %eax
  	call    syscall_return_slowpath
  	STACKLEAK_ERASE
-	jmp     restore_all
+	jmp     restore_all_switch_stack
 
  	/* kernel thread */
  1:	movl	%edi, %eax
@@ -1077,6 +1077,7 @@ SYM_FUNC_START(entry_INT80_32)
 
  restore_all:
  	TRACE_IRQS_IRET
+restore_all_switch_stack:
  	SWITCH_TO_ENTRY_STACK
  	CHECK_AND_APPLY_ESPFIX
  .Lrestore_nocheck:
arch/x86/entry/entry_64.S +0 -3
@@ -172,8 +172,6 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_h
  	movq	%rsp, %rsi
  	call	do_syscall_64		/* returns with IRQs disabled */
 
-	TRACE_IRQS_ON			/* return enables interrupts */
-
  	/*
  	 * Try to use SYSRET instead of IRET if we're returning to
  	 * a completely clean 64-bit userspace context.  If we're not,
@@ -340,7 +338,6 @@ SYM_CODE_START(ret_from_fork)
  	UNWIND_HINT_REGS
  	movq	%rsp, %rdi
  	call	syscall_return_slowpath	/* returns with IRQs disabled */
-	TRACE_IRQS_ON			/* user mode is traced as IRQS on */
  	jmp	swapgs_restore_regs_and_return_to_usermode
 
  1:
#49 lore raw

PATCH 7/8 x86/entry: Move irq tracing to prepare_exit_to_user_mode()

In reply to Thomas Gleixner

which again gets it out of the ASM code.

---
 arch/x86/entry/common.c   |    1 +
 arch/x86/entry/entry_32.S |    2 +-
 arch/x86/entry/entry_64.S |    1 -
 3 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/entry/common.c +1 -0
@@ -244,6 +244,7 @@ static inline void __prepare_exit_to_use
 __visible inline notrace void prepare_exit_to_usermode(struct pt_regs *regs)
 {
 	__prepare_exit_to_usermode(regs);
+	trace_hardirqs_on();
 }
 NOKPROBE_SYMBOL(prepare_exit_to_usermode);
 
arch/x86/entry/entry_32.S +1 -1
@@ -855,7 +855,7 @@ SYM_CODE_START_LOCAL(ret_from_exception)
 	TRACE_IRQS_OFF
 	movl	%esp, %eax
 	call	prepare_exit_to_usermode
-	jmp	restore_all
+	jmp	restore_all_switch_stack
 SYM_CODE_END(ret_from_exception)
 
 SYM_ENTRY(__begin_SYSENTER_singlestep_region, SYM_L_GLOBAL, SYM_A_NONE)
arch/x86/entry/entry_64.S +0 -1
@@ -614,7 +614,6 @@ SYM_CODE_START_LOCAL(common_interrupt)
 .Lretint_user:
 	mov	%rsp,%rdi
 	call	prepare_exit_to_usermode
-	TRACE_IRQS_ON
 
 SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
 #ifdef CONFIG_DEBUG_ENTRY
maintainer
#50 lore raw

Re: [patch 7/8] x86/entry: Move irq tracing to prepare_exit_to_user_mode()

Quoted 1 line · Thomas Gleixner

which again gets it out of the ASM code.

Why is this better than just sticking the tracing in __prepare_exit_from_usermode() or just not splitting it in the first place?

(ISTM the real right solution is to make sure that it's okay for trace_hardirqs_... to be safe even when rcuidle. But I may still be missing something.)

#51 lore raw

Re: [patch 7/8] x86/entry: Move irq tracing to prepare_exit_to_user_mode()

Quoted 6 lines · Andy Lutomirski
Quoted 1 line · Thomas Gleixner

which again gets it out of the ASM code.

Why is this better than just sticking the tracing in __prepare_exit_from_usermode() or just not splitting it in the first place?

The split is there because prepare_exit_from_usermode() is used from the idtentry maze as well. Once that stuff is converted in the later series the split goes away again.

Thanks,

tglx

maintainer
#52 lore raw

Re: [patch 7/8] x86/entry: Move irq tracing to prepare_exit_to_user_mode()

Quoted 6 lines · Thomas Gleixner
Quoted 3 lines · Andy Lutomirski
Quoted 1 line · Thomas Gleixner

which again gets it out of the ASM code.

Quoted 8 lines
Quoted 3 lines

Why is this better than just sticking the tracing in __prepare_exit_from_usermode() or just not splitting it in the first place?

The split is there because prepare_exit_from_usermode() is used from the idtentry maze as well. Once that stuff is converted in the later series the split goes away again.

Okay.

#53 lore raw

PATCH 8/8 x86/entry: Move irqflags tracing to do_int80_syscall_32()

In reply to Thomas Gleixner

which cleans up the ASM maze.

---
 arch/x86/entry/common.c          |    8 +++++++-
 arch/x86/entry/entry_32.S        |    9 ++-------
 arch/x86/entry/entry_64_compat.S |   14 +++++---------
 3 files changed, 14 insertions(+), 17 deletions(-)
arch/x86/entry/common.c +7 -1
@@ -333,6 +333,7 @@ void do_syscall_64_irqs_on(unsigned long
 {
 	syscall_entry_fixups();
 	do_syscall_64_irqs_on(nr, regs);
+	trace_hardirqs_on();
 }
 NOKPROBE_SYMBOL(do_syscall_64);
 #endif
@@ -389,6 +390,7 @@ static __always_inline void do_syscall_3
 {
 	syscall_entry_fixups();
 	do_syscall_32_irqs_on(regs);
+	trace_hardirqs_on();
 }
 NOKPROBE_SYMBOL(do_int80_syscall_32);
 
@@ -468,8 +470,12 @@ static __always_inline long do_fast_sysc
 /* Returns 0 to return using IRET or 1 to return using SYSEXIT/SYSRETL. */
 __visible notrace long do_fast_syscall_32(struct pt_regs *regs)
 {
+	long ret;
+
 	syscall_entry_fixups();
-	return do_fast_syscall_32_irqs_on(regs);
+	ret = do_fast_syscall_32_irqs_on(regs);
+	trace_hardirqs_on();
+	return ret;
 }
 NOKPROBE_SYMBOL(do_fast_syscall_32);
 
arch/x86/entry/entry_32.S +2 -7
@@ -811,8 +811,7 @@ SYM_CODE_START(ret_from_fork)
 	/* When we fork, we trace the syscall return in the child, too. */
 	movl    %esp, %eax
 	call    syscall_return_slowpath
-	STACKLEAK_ERASE
-	jmp     restore_all_switch_stack
+	jmp     .Lsyscall_32_done
 
 	/* kernel thread */
 1:	movl	%edi, %eax
@@ -968,8 +967,7 @@ SYM_FUNC_START(entry_SYSENTER_32)
 
 	STACKLEAK_ERASE
 
-/* Opportunistic SYSEXIT */
-	TRACE_IRQS_ON			/* User mode traces as IRQs on. */
+	/* Opportunistic SYSEXIT */
 
 	/*
 	 * Setup entry stack - we keep the pointer in %eax and do the
@@ -1072,11 +1070,8 @@ SYM_FUNC_START(entry_INT80_32)
 	movl	%esp, %eax
 	call	do_int80_syscall_32
 .Lsyscall_32_done:
-
 	STACKLEAK_ERASE
 
-restore_all:
-	TRACE_IRQS_IRET
 restore_all_switch_stack:
 	SWITCH_TO_ENTRY_STACK
 	CHECK_AND_APPLY_ESPFIX
arch/x86/entry/entry_64_compat.S +5 -9
@@ -132,8 +132,8 @@ SYM_FUNC_START(entry_SYSENTER_compat)
 	movq	%rsp, %rdi
 	call	do_fast_syscall_32
 	/* XEN PV guests always use IRET path */
-	ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \
-		    "jmp .Lsyscall_32_done", X86_FEATURE_XENPV
+	ALTERNATIVE "testl %eax, %eax; jz swapgs_restore_regs_and_return_to_usermode", \
+		    "jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV
 	jmp	sysret32_from_system_call
 
 .Lsysenter_fix_flags:
@@ -244,8 +244,8 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_aft
 	movq	%rsp, %rdi
 	call	do_fast_syscall_32
 	/* XEN PV guests always use IRET path */
-	ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \
-		    "jmp .Lsyscall_32_done", X86_FEATURE_XENPV
+	ALTERNATIVE "testl %eax, %eax; jz swapgs_restore_regs_and_return_to_usermode", \
+		    "jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV
 
 	/* Opportunistic SYSRET */
 sysret32_from_system_call:
@@ -254,7 +254,7 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_aft
 	 * stack. So let's erase the thread stack right now.
 	 */
 	STACKLEAK_ERASE
-	TRACE_IRQS_ON			/* User mode traces as IRQs on. */
+
 	movq	RBX(%rsp), %rbx		/* pt_regs->rbx */
 	movq	RBP(%rsp), %rbp		/* pt_regs->rbp */
 	movq	EFLAGS(%rsp), %r11	/* pt_regs->flags (in r11) */
@@ -393,9 +393,5 @@ SYM_CODE_START(entry_INT80_compat)
 
 	movq	%rsp, %rdi
 	call	do_int80_syscall_32
-.Lsyscall_32_done:
-
-	/* Go back to user mode. */
-	TRACE_IRQS_ON
 	jmp	swapgs_restore_regs_and_return_to_usermode
 SYM_CODE_END(entry_INT80_compat)
#54 lore raw

Re: [patch 8/8] x86/entry: Move irqflags tracing to do_int80_syscall_32()

Quoted 12 lines · Thomas Gleixner

which cleans up the ASM maze.

---
  arch/x86/entry/common.c          |    8 +++++++-
  arch/x86/entry/entry_32.S        |    9 ++-------
  arch/x86/entry/entry_64_compat.S |   14 +++++---------
  3 files changed, 14 insertions(+), 17 deletions(-)

arch/x86/entry/common.c void do_syscall_64_irqs_on(unsigned long · line 337

Quoted 5 lines
arch/x86/entry/common.c +1 -0
@@ -333,6 +333,7 @@ void do_syscall_64_irqs_on(unsigned long
  {
  	syscall_entry_fixups();
  	do_syscall_64_irqs_on(nr, regs);
+	trace_hardirqs_on();
  }

trace_hardirqs_on() is already called through syscall_return_slowpath() (from the previous patch):

do_syscall_64()
-> do_syscall_64_irqs_on()

    -> syscall_return_slowpath()
      -> trace_hardirqs_on()

arch/x86/entry/common.c static __always_inline void do_syscall_3 · line 394

Quoted 8 lines
arch/x86/entry/common.c +1 -0
  NOKPROBE_SYMBOL(do_syscall_64);
  #endif
@@ -389,6 +390,7 @@ static __always_inline void do_syscall_3
  {
  	syscall_entry_fixups();
  	do_syscall_32_irqs_on(regs);
+	trace_hardirqs_on();
  }

Same here:

do_int80_syscall_32()
-> do_syscall_32_irqs_on()

    -> syscall_return_slowpath()
      -> trace_hardirqs_on()
Quoted 5 lines
arch/x86/entry/common.c +0 -0
  NOKPROBE_SYMBOL(do_int80_syscall_32);
 
@@ -468,8 +470,12 @@ static __always_inline long do_fast_sysc
  /* Returns 0 to return using IRET or 1 to return using SYSEXIT/SYSRETL. */
  __visible notrace long do_fast_syscall_32(struct pt_regs *regs)

arch/x86/entry/common.c static __always_inline long do_fast_sysc · line 480

Quoted 10 lines
arch/x86/entry/common.c +5 -1
  {
+	long ret;
+
  	syscall_entry_fixups();
-	return do_fast_syscall_32_irqs_on(regs);
+	ret = do_fast_syscall_32_irqs_on(regs);
+	trace_hardirqs_on();
+	return ret;
  }
  NOKPROBE_SYMBOL(do_fast_syscall_32);

Same here:

do_fast_syscall_32()

    -> do_fast_syscall_32_irqs_on()
      -> do_syscall_32_irqs_on()
        -> syscall_return_slowpath()
          -> trace_hardirqs_on()

Except for one case (if the get_user() call is true in do_fast_syscall_32_irqs_on()):

do_fast_syscall_32()

    -> do_fast_syscall_32_irqs_on()
      -> prepare_exit_to_usermode()

So we need to call trace_hardirqs_on() but only in that case:

static __always_inline long do_fast_syscall_32_irqs_on(struct pt_regs *regs)

{
          ...
	if (
#ifdef CONFIG_X86_64
		/*
		 * Micro-optimization: the pointer we're following is explicitly
		 * 32 bits, so it can't be out of range.
		 */
		__get_user(*(u32 *)&regs->bp,
			    (u32 __user __force *)(unsigned long)(u32)regs->sp)
#else
		get_user(*(u32 *)&regs->bp,
			 (u32 __user __force *)(unsigned long)(u32)regs->sp)
#endif
		) {

		/* User code screwed up. */
		local_irq_disable();
		regs->ax = -EFAULT;
		prepare_exit_to_usermode(regs);
                trace_hardirqs_on();                <<<=== HERE
		return 0;	/* Keep it simple: use IRET. */
	}
        ...
}

alex.

Quoted 78 lines
arch/x86/entry/entry_32.S +2 -7
@@ -811,8 +811,7 @@ SYM_CODE_START(ret_from_fork)
  	/* When we fork, we trace the syscall return in the child, too. */
  	movl    %esp, %eax
  	call    syscall_return_slowpath
-	STACKLEAK_ERASE
-	jmp     restore_all_switch_stack
+	jmp     .Lsyscall_32_done
 
  	/* kernel thread */
  1:	movl	%edi, %eax
@@ -968,8 +967,7 @@ SYM_FUNC_START(entry_SYSENTER_32)
 
  	STACKLEAK_ERASE
 
-/* Opportunistic SYSEXIT */
-	TRACE_IRQS_ON			/* User mode traces as IRQs on. */
+	/* Opportunistic SYSEXIT */
 
  	/*
  	 * Setup entry stack - we keep the pointer in %eax and do the
@@ -1072,11 +1070,8 @@ SYM_FUNC_START(entry_INT80_32)
  	movl	%esp, %eax
  	call	do_int80_syscall_32
  .Lsyscall_32_done:
-
  	STACKLEAK_ERASE
 
-restore_all:
-	TRACE_IRQS_IRET
  restore_all_switch_stack:
  	SWITCH_TO_ENTRY_STACK
  	CHECK_AND_APPLY_ESPFIX
arch/x86/entry/entry_64_compat.S +5 -9
@@ -132,8 +132,8 @@ SYM_FUNC_START(entry_SYSENTER_compat)
  	movq	%rsp, %rdi
  	call	do_fast_syscall_32
  	/* XEN PV guests always use IRET path */
-	ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \
-		    "jmp .Lsyscall_32_done", X86_FEATURE_XENPV
+	ALTERNATIVE "testl %eax, %eax; jz swapgs_restore_regs_and_return_to_usermode", \
+		    "jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV
  	jmp	sysret32_from_system_call
 
  .Lsysenter_fix_flags:
@@ -244,8 +244,8 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_aft
  	movq	%rsp, %rdi
  	call	do_fast_syscall_32
  	/* XEN PV guests always use IRET path */
-	ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \
-		    "jmp .Lsyscall_32_done", X86_FEATURE_XENPV
+	ALTERNATIVE "testl %eax, %eax; jz swapgs_restore_regs_and_return_to_usermode", \
+		    "jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV
 
  	/* Opportunistic SYSRET */
  sysret32_from_system_call:
@@ -254,7 +254,7 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_aft
  	 * stack. So let's erase the thread stack right now.
  	 */
  	STACKLEAK_ERASE
-	TRACE_IRQS_ON			/* User mode traces as IRQs on. */
+
  	movq	RBX(%rsp), %rbx		/* pt_regs->rbx */
  	movq	RBP(%rsp), %rbp		/* pt_regs->rbp */
  	movq	EFLAGS(%rsp), %r11	/* pt_regs->flags (in r11) */
@@ -393,9 +393,5 @@ SYM_CODE_START(entry_INT80_compat)
 
  	movq	%rsp, %rdi
  	call	do_int80_syscall_32
-.Lsyscall_32_done:
-
-	/* Go back to user mode. */
-	TRACE_IRQS_ON
  	jmp	swapgs_restore_regs_and_return_to_usermode
  SYM_CODE_END(entry_INT80_compat)
#55 lore raw

Re: [patch 8/8] x86/entry: Move irqflags tracing to do_int80_syscall_32()

Quoted 22 lines · Alexandre Chartre
Quoted 12 lines · Thomas Gleixner

which cleans up the ASM maze.

---
  arch/x86/entry/common.c          |    8 +++++++-
  arch/x86/entry/entry_32.S        |    9 ++-------
  arch/x86/entry/entry_64_compat.S |   14 +++++---------
  3 files changed, 14 insertions(+), 17 deletions(-)

arch/x86/entry/common.c void do_syscall_64_irqs_on(unsigned long · line 337

Quoted 5 lines
arch/x86/entry/common.c +1 -0
@@ -333,6 +333,7 @@ void do_syscall_64_irqs_on(unsigned long
  {
  	syscall_entry_fixups();
  	do_syscall_64_irqs_on(nr, regs);
+	trace_hardirqs_on();
  }

trace_hardirqs_on() is already called through syscall_return_slowpath() (from the previous patch):

Quoted 4 lines

do_syscall_64()
-> do_syscall_64_irqs_on()

     -> syscall_return_slowpath()
       -> trace_hardirqs_on()

Duh, indeed.