Skip to content

Commit 7a5201e

Browse files
KAGA-KOKOingomolnar
authored andcommitted
rseq: Split up rseq_exit_to_user_mode()
Separate the interrupt and syscall exit handling. Syscall exit does not require to clear the user_irq bit as it can't be set. On interrupt exit it can be set when the interrupt did not result in a scheduling event and therefore the return path did not invoke the TIF work handling, which would have cleared it. The debug check for the event state is also not really required even when debug mode is enabled via the static key. Debug mode is largely aiding user space by enabling a larger amount of validation checks, which cause a segfault when a malformed critical section is detected. In production mode the critical section handling takes the content mostly as is and lets user space keep the pieces when it screwed up. On kernel changes in that area the state check is useful, but that can be done when lockdep is enabled, which is anyway a required test scenario for fundamental changes. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Link: https://patch.msgid.link/20251027084307.842785700@linutronix.de
1 parent 70fe25a commit 7a5201e

2 files changed

Lines changed: 37 additions & 5 deletions

File tree

include/linux/irq-entry-common.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ static __always_inline void __exit_to_user_mode_validate(void)
240240
static __always_inline void exit_to_user_mode_prepare_legacy(struct pt_regs *regs)
241241
{
242242
__exit_to_user_mode_prepare(regs);
243-
rseq_exit_to_user_mode();
243+
rseq_exit_to_user_mode_legacy();
244244
__exit_to_user_mode_validate();
245245
}
246246

@@ -254,7 +254,7 @@ static __always_inline void exit_to_user_mode_prepare_legacy(struct pt_regs *reg
254254
static __always_inline void syscall_exit_to_user_mode_prepare(struct pt_regs *regs)
255255
{
256256
__exit_to_user_mode_prepare(regs);
257-
rseq_exit_to_user_mode();
257+
rseq_syscall_exit_to_user_mode();
258258
__exit_to_user_mode_validate();
259259
}
260260

@@ -268,7 +268,7 @@ static __always_inline void syscall_exit_to_user_mode_prepare(struct pt_regs *re
268268
static __always_inline void irqentry_exit_to_user_mode_prepare(struct pt_regs *regs)
269269
{
270270
__exit_to_user_mode_prepare(regs);
271-
rseq_exit_to_user_mode();
271+
rseq_irqentry_exit_to_user_mode();
272272
__exit_to_user_mode_validate();
273273
}
274274

include/linux/rseq_entry.h

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,37 @@ static __always_inline bool rseq_exit_to_user_mode_restart(struct pt_regs *regs)
521521
static inline bool rseq_exit_to_user_mode_restart(struct pt_regs *regs) { return false; }
522522
#endif /* !CONFIG_GENERIC_ENTRY */
523523

524-
static __always_inline void rseq_exit_to_user_mode(void)
524+
static __always_inline void rseq_syscall_exit_to_user_mode(void)
525+
{
526+
struct rseq_event *ev = &current->rseq.event;
527+
528+
rseq_stat_inc(rseq_stats.exit);
529+
530+
/* Needed to remove the store for the !lockdep case */
531+
if (IS_ENABLED(CONFIG_LOCKDEP)) {
532+
WARN_ON_ONCE(ev->sched_switch);
533+
ev->events = 0;
534+
}
535+
}
536+
537+
static __always_inline void rseq_irqentry_exit_to_user_mode(void)
538+
{
539+
struct rseq_event *ev = &current->rseq.event;
540+
541+
rseq_stat_inc(rseq_stats.exit);
542+
543+
lockdep_assert_once(!ev->sched_switch);
544+
545+
/*
546+
* Ensure that event (especially user_irq) is cleared when the
547+
* interrupt did not result in a schedule and therefore the
548+
* rseq processing could not clear it.
549+
*/
550+
ev->events = 0;
551+
}
552+
553+
/* Required to keep ARM64 working */
554+
static __always_inline void rseq_exit_to_user_mode_legacy(void)
525555
{
526556
struct rseq_event *ev = &current->rseq.event;
527557

@@ -551,7 +581,9 @@ static inline bool rseq_exit_to_user_mode_restart(struct pt_regs *regs)
551581
{
552582
return false;
553583
}
554-
static inline void rseq_exit_to_user_mode(void) { }
584+
static inline void rseq_syscall_exit_to_user_mode(void) { }
585+
static inline void rseq_irqentry_exit_to_user_mode(void) { }
586+
static inline void rseq_exit_to_user_mode_legacy(void) { }
555587
static inline void rseq_debug_syscall_return(struct pt_regs *regs) { }
556588
#endif /* !CONFIG_RSEQ */
557589

0 commit comments

Comments
 (0)