[PATCH v2 08/20] rseq: Always inline the empty stubs called from noinstr code

From: Sasha Levin

Date: Mon Nov 02 2026 - 20:54:30 EST


The !CONFIG_RSEQ stubs in rseq_entry.h, and the !CONFIG_GENERIC_ENTRY
version of rseq_exit_to_user_mode_restart(), are plain static inline
functions, while their counterparts are __always_inline. They are called
from noinstr entry code, directly or through the __always_inline exit to
user mode helpers, and the compiler won't inline them there when
building with code coverage instrumentation.

On x86 that's rseq_note_user_irq_entry(). arm64 calls the exit to user
mode helpers from noinstr code outside of instrumentation_begin()
sections, so with Clang, asm_exit_to_user_mode() and the el0 exception
handlers end up calling rseq_syscall_exit_to_user_mode() and
rseq_irqentry_exit_to_user_mode() out of line.

Make the stubs __always_inline as well.

Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---
include/linux/rseq_entry.h | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/include/linux/rseq_entry.h b/include/linux/rseq_entry.h
index 31ce349ed42ce..7f9f1590d73fd 100644
--- a/include/linux/rseq_entry.h
+++ b/include/linux/rseq_entry.h
@@ -716,7 +716,7 @@ rseq_exit_to_user_mode_restart(struct pt_regs *regs, unsigned long ti_work)
}

#else /* CONFIG_GENERIC_ENTRY */
-static inline bool rseq_exit_to_user_mode_restart(struct pt_regs *regs, unsigned long ti_work)
+static __always_inline bool rseq_exit_to_user_mode_restart(struct pt_regs *regs, unsigned long ti_work)
{
return false;
}
@@ -759,15 +759,15 @@ static __always_inline void rseq_debug_syscall_return(struct pt_regs *regs)
__rseq_debug_syscall_return(regs);
}
#else /* CONFIG_RSEQ */
-static inline void rseq_note_user_irq_entry(void) { }
-static inline bool rseq_exit_to_user_mode_restart(struct pt_regs *regs, unsigned long ti_work)
+static __always_inline void rseq_note_user_irq_entry(void) { }
+static __always_inline bool rseq_exit_to_user_mode_restart(struct pt_regs *regs, unsigned long ti_work)
{
return false;
}
-static inline void rseq_syscall_exit_to_user_mode(void) { }
-static inline void rseq_irqentry_exit_to_user_mode(void) { }
-static inline void rseq_debug_syscall_return(struct pt_regs *regs) { }
-static inline bool rseq_grant_slice_extension(unsigned long ti_work, unsigned long mask) { return false; }
+static __always_inline void rseq_syscall_exit_to_user_mode(void) { }
+static __always_inline void rseq_irqentry_exit_to_user_mode(void) { }
+static __always_inline void rseq_debug_syscall_return(struct pt_regs *regs) { }
+static __always_inline bool rseq_grant_slice_extension(unsigned long ti_work, unsigned long mask) { return false; }
#endif /* !CONFIG_RSEQ */

#endif /* _LINUX_RSEQ_ENTRY_H */
--
2.53.0