On Thu, Apr 06, 2023 at 09:56:07AM -0700, Ankur Arora wrote: > > Right, so: > > CONFIG_PREEMPTION: raw_foo() > CONFIG_PREEMPTION && (preempt_dynamic_mode == preempt_dynamic_full): raw_foo() > > This is NOP if CONFIG_PREEMPTION && preempt_dynamic_mode != preempt_dynamic_full. > > > if (!A) > > raw_foo(); > > So I would call raw_foo() for the CONFIG_PREEMPTION=n case. > > > What you really care about is the CONFIG_PREEMPTION=n case, but that you > > don't actually handle. > > I don't see that. The CONFIG_PREEMPTION=n (or its dynamic version) > is being handled here. Bah, I overlooked we have multiple definitions of the preempt_model_foo() things. For some reason I thought all that was only for DYNAMIC_PREEMPT. > > And yeah, you've got the extra resched_allowed() thing in there, but > > that doesn't make it any better -- this is all quite horrible. > > I don't disagree. There's a quite a lot of static/dynamic config options > here and adding this clause didn't improve things. > > I think just going with a static call here for the allow-resched case > might have been cleaner. Alternately I'll see if it can be cleanly > folded in with the irqentry_exit_cond_resched() logic. Something like the below perhaps? --- include/linux/entry-common.h | 6 ++++++ kernel/entry/common.c | 23 +++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h index d95ab85f96ba..0c365dc1f1c2 100644 --- a/include/linux/entry-common.h +++ b/include/linux/entry-common.h @@ -415,10 +415,16 @@ irqentry_state_t noinstr irqentry_enter(struct pt_regs *regs); * Conditional reschedule with additional sanity checks. */ void raw_irqentry_exit_cond_resched(void); +void irqentry_exit_cond_resched_tif(void); + #ifdef CONFIG_PREEMPT_DYNAMIC #if defined(CONFIG_HAVE_PREEMPT_DYNAMIC_CALL) #define irqentry_exit_cond_resched_dynamic_enabled raw_irqentry_exit_cond_resched +#ifdef TIF_RESCHED_ALLOW +#define irqentry_exit_cond_resched_dynamic_disabled irqentry_exit_cond_resched_tif +#else #define irqentry_exit_cond_resched_dynamic_disabled NULL +#endif DECLARE_STATIC_CALL(irqentry_exit_cond_resched, raw_irqentry_exit_cond_resched); #define irqentry_exit_cond_resched() static_call(irqentry_exit_cond_resched)() #elif defined(CONFIG_HAVE_PREEMPT_DYNAMIC_KEY) diff --git a/kernel/entry/common.c b/kernel/entry/common.c index be61332c66b5..211d118aa672 100644 --- a/kernel/entry/common.c +++ b/kernel/entry/common.c @@ -390,6 +390,21 @@ void raw_irqentry_exit_cond_resched(void) preempt_schedule_irq(); } } + +void irqentry_exit_cond_resched_tif(void) +{ +#ifdef TIF_RESCHED_ALLOW + if (resched_allowed()) { + /* Sanity check RCU and thread stack */ + rcu_irq_exit_check_preempt(); + if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) + WARN_ON_ONCE(!on_thread_stack()); + if (need_resched()) + preempt_schedule_irq(); + } +#endif +} + #ifdef CONFIG_PREEMPT_DYNAMIC #if defined(CONFIG_HAVE_PREEMPT_DYNAMIC_CALL) DEFINE_STATIC_CALL(irqentry_exit_cond_resched, raw_irqentry_exit_cond_resched); @@ -397,8 +412,10 @@ DEFINE_STATIC_CALL(irqentry_exit_cond_resched, raw_irqentry_exit_cond_resched); DEFINE_STATIC_KEY_TRUE(sk_dynamic_irqentry_exit_cond_resched); void dynamic_irqentry_exit_cond_resched(void) { - if (!static_branch_unlikely(&sk_dynamic_irqentry_exit_cond_resched)) - return; + if (!static_branch_unlikely(&sk_dynamic_irqentry_exit_cond_resched)) { + irqentry_exit_cond_resched_tif(); + return + } raw_irqentry_exit_cond_resched(); } #endif @@ -431,6 +448,8 @@ noinstr void irqentry_exit(struct pt_regs *regs, irqentry_state_t state) instrumentation_begin(); if (IS_ENABLED(CONFIG_PREEMPTION)) irqentry_exit_cond_resched(); + else + irqentry_exit_cond_resched_tif(); /* Covers both tracing and lockdep */ trace_hardirqs_on();