diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2021-12-01 18:28:28 +0100 |
---|---|---|
committer | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2021-12-01 18:28:28 +0100 |
commit | bec6ba2d99203bdfa6b25abc409a3d4891b8b121 (patch) | |
tree | 14df1ff4e1a76a54ff3e2eef5d6b45b6a4c6a63f | |
parent | 1cb608242f364b19931feba543329a8380de8e63 (diff) | |
download | linux-rt-bec6ba2d99203bdfa6b25abc409a3d4891b8b121.tar.gz |
[ANNOUNCE] v5.16-rc3-rt7v5.16-rc3-rt7-patches
Dear RT folks!
I'm pleased to announce the v5.16-rc3-rt7 patch set.
Changes since v5.16-rc3-rt6:
- Drop the workaround for the initialisation of the stack canary on
x86. It is no longer needed.
- Introduce the `ktimers' thread which handles the softirq work of
HRTIMER_SOFTIRQ and TIMER_SOFTIRQ. This avoids the wake up of
ksoftirqd which then collects all softirqs.
Known issues
- netconsole triggers WARN.
- The "Memory controller" (CONFIG_MEMCG) has been disabled.
- Valentin Schneider reported a few splats on ARM64, see
https://lkml.kernel.org/r/20210810134127.1394269-1-valentin.schneider@arm.com
The delta patch against v5.16-rc3-rt6 is appended below and can be found here:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.16/incr/patch-5.16-rc3-rt6-rt7.patch.xz
You can get this release via the git tree at:
git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git v5.16-rc3-rt7
The RT patch against v5.16-rc3 can be found here:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.16/older/patch-5.16-rc3-rt7.patch.xz
The split quilt queue is available at:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.16/older/patches-5.16-rc3-rt7.tar.xz
Sebastian
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-rw-r--r-- | patches/Add_localversion_for_-RT_release.patch | 2 | ||||
-rw-r--r-- | patches/series | 2 | ||||
-rw-r--r-- | patches/softirq-Use-a-dedicated-thread-for-timer-wakeups.patch | 204 | ||||
-rw-r--r-- | patches/x86__stackprotector__Avoid_random_pool_on_rt.patch | 49 |
4 files changed, 206 insertions, 51 deletions
diff --git a/patches/Add_localversion_for_-RT_release.patch b/patches/Add_localversion_for_-RT_release.patch index 7b3d2414e699..e58a29adc4af 100644 --- a/patches/Add_localversion_for_-RT_release.patch +++ b/patches/Add_localversion_for_-RT_release.patch @@ -15,4 +15,4 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- /dev/null +++ b/localversion-rt @@ -0,0 +1 @@ -+-rt6 ++-rt7 diff --git a/patches/series b/patches/series index 5d996621aa32..3a51bfbf1013 100644 --- a/patches/series +++ b/patches/series @@ -70,6 +70,7 @@ tcp-Don-t-acquire-inet_listen_hashbucket-lock-with-d.patch ########################################################################### cgroup__use_irqsave_in_cgroup_rstat_flush_locked.patch mm__workingset__replace_IRQ-off_check_with_a_lockdep_assert..patch +softirq-Use-a-dedicated-thread-for-timer-wakeups.patch ########################################################################### # Kconfig bits: @@ -142,7 +143,6 @@ net__dev__always_take_qdiscs_busylock_in___dev_xmit_skb.patch # randomness: ########################################################################### panic__skip_get_random_bytes_for_RT_FULL_in_init_oops_id.patch -x86__stackprotector__Avoid_random_pool_on_rt.patch random__Make_it_work_on_rt.patch ########################################################################### diff --git a/patches/softirq-Use-a-dedicated-thread-for-timer-wakeups.patch b/patches/softirq-Use-a-dedicated-thread-for-timer-wakeups.patch new file mode 100644 index 000000000000..92d63a22cd6e --- /dev/null +++ b/patches/softirq-Use-a-dedicated-thread-for-timer-wakeups.patch @@ -0,0 +1,204 @@ +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Wed, 1 Dec 2021 17:41:09 +0100 +Subject: [PATCH] softirq: Use a dedicated thread for timer wakeups. + +A timer/hrtimer softirq is raised in-IRQ context. With threaded +interrupts enabled or on PREEMPT_RT this leads to waking the ksoftirqd +for the processing of the softirq. +Once the ksoftirqd is marked as pending (or is running) it will collect +all raised softirqs. This in turn means that a softirq which would have +been processed at the end of the threaded interrupt, which runs at an +elevated priority, is now moved to ksoftirqd which runs at SCHED_OTHER +priority and competes with every regular task for CPU resources. +This introduces long delays on heavy loaded systems and is not desired +especially if the system is not overloaded by the softirqs. + +Split the TIMER_SOFTIRQ and HRTIMER_SOFTIRQ processing into a dedicated +timers thread and let it run at the lowest SCHED_FIFO priority. +RT tasks are are woken up from hardirq context so only timer_list timers +and hrtimers for "regular" tasks are processed here. The higher priority +ensures that wakeups are performed before scheduling SCHED_OTHER tasks. + +Using a dedicated variable to store the pending softirq bits values +ensure that the timer are not accidentally picked up by ksoftirqd and +other threaded interrupts. +It shouldn't be picked up by ksoftirqd since it runs at lower priority. +However if the timer bits are ORed while a threaded interrupt is +running, then the timer softirq would be performed at higher priority. +The new timer thread will block on the softirq lock before it starts +softirq work. This "race window" isn't closed because while timer thread +is performing the softirq it can get PI-boosted via the softirq lock by +a random force-threaded thread. +The timer thread can pick up pending softirqs from ksoftirqd but only +if the softirq load is high. It is not be desired that the picked up +softirqs are processed at SCHED_FIFO priority under high softirq load +but this can already happen by a PI-boost by a force-threaded interrupt. + +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + include/linux/interrupt.h | 16 +++++++++ + kernel/softirq.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++ + kernel/time/hrtimer.c | 4 +- + kernel/time/timer.c | 2 - + 4 files changed, 95 insertions(+), 3 deletions(-) + +--- a/include/linux/interrupt.h ++++ b/include/linux/interrupt.h +@@ -554,6 +554,22 @@ extern void __raise_softirq_irqoff(unsig + extern void raise_softirq_irqoff(unsigned int nr); + extern void raise_softirq(unsigned int nr); + ++#ifdef CONFIG_PREEMPT_RT ++extern void raise_timer_softirq(void); ++extern void raise_hrtimer_softirq(void); ++ ++#else ++static inline void raise_timer_softirq(void) ++{ ++ raise_softirq(TIMER_SOFTIRQ); ++} ++ ++static inline void raise_hrtimer_softirq(void) ++{ ++ raise_softirq_irqoff(HRTIMER_SOFTIRQ); ++} ++#endif ++ + DECLARE_PER_CPU(struct task_struct *, ksoftirqd); + + static inline struct task_struct *this_cpu_ksoftirqd(void) +--- a/kernel/softirq.c ++++ b/kernel/softirq.c +@@ -623,6 +623,22 @@ static inline void tick_irq_exit(void) + #endif + } + ++static DEFINE_PER_CPU(struct task_struct *, timersd); ++static DEFINE_PER_CPU(unsigned long, pending_timer_softirq); ++ ++static unsigned int local_pending_timers(void) ++{ ++ return __this_cpu_read(pending_timer_softirq); ++} ++ ++static void wake_timersd(void) ++{ ++ struct task_struct *tsk = __this_cpu_read(timersd); ++ ++ if (tsk) ++ wake_up_process(tsk); ++} ++ + static inline void __irq_exit_rcu(void) + { + #ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED +@@ -634,6 +650,8 @@ static inline void __irq_exit_rcu(void) + preempt_count_sub(HARDIRQ_OFFSET); + if (!in_interrupt() && local_softirq_pending()) + invoke_softirq(); ++ if (IS_ENABLED(CONFIG_PREEMPT_RT) && !in_interrupt() && local_pending_timers()) ++ wake_timersd(); + + tick_irq_exit(); + } +@@ -962,11 +980,69 @@ static struct smp_hotplug_thread softirq + .thread_comm = "ksoftirqd/%u", + }; + ++static void timersd_setup(unsigned int cpu) ++{ ++ sched_set_fifo_low(current); ++} ++ ++static int timersd_should_run(unsigned int cpu) ++{ ++ return local_pending_timers(); ++} ++ ++static void run_timersd(unsigned int cpu) ++{ ++ unsigned int timer_si; ++ ++ ksoftirqd_run_begin(); ++ ++ timer_si = local_pending_timers(); ++ __this_cpu_write(pending_timer_softirq, 0); ++ or_softirq_pending(timer_si); ++ ++ __do_softirq(); ++ ++ ksoftirqd_run_end(); ++} ++ ++#ifdef CONFIG_PREEMPT_RT ++static void raise_ktimers_thread(unsigned int nr) ++{ ++ trace_softirq_raise(nr); ++ __this_cpu_or(pending_timer_softirq, 1 << nr); ++} ++ ++void raise_hrtimer_softirq(void) ++{ ++ raise_ktimers_thread(HRTIMER_SOFTIRQ); ++} ++ ++void raise_timer_softirq(void) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ raise_ktimers_thread(TIMER_SOFTIRQ); ++ wake_timersd(); ++ local_irq_restore(flags); ++} ++#endif ++ ++struct smp_hotplug_thread timer_threads = { ++ .store = &timersd, ++ .setup = timersd_setup, ++ .thread_should_run = timersd_should_run, ++ .thread_fn = run_timersd, ++ .thread_comm = "ktimers/%u", ++}; ++ + static __init int spawn_ksoftirqd(void) + { + cpuhp_setup_state_nocalls(CPUHP_SOFTIRQ_DEAD, "softirq:dead", NULL, + takeover_tasklets); + BUG_ON(smpboot_register_percpu_thread(&softirq_threads)); ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ BUG_ON(smpboot_register_percpu_thread(&timer_threads)); + + return 0; + } +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1805,7 +1805,7 @@ void hrtimer_interrupt(struct clock_even + if (!ktime_before(now, cpu_base->softirq_expires_next)) { + cpu_base->softirq_expires_next = KTIME_MAX; + cpu_base->softirq_activated = 1; +- raise_softirq_irqoff(HRTIMER_SOFTIRQ); ++ raise_hrtimer_softirq(); + } + + __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD); +@@ -1918,7 +1918,7 @@ void hrtimer_run_queues(void) + if (!ktime_before(now, cpu_base->softirq_expires_next)) { + cpu_base->softirq_expires_next = KTIME_MAX; + cpu_base->softirq_activated = 1; +- raise_softirq_irqoff(HRTIMER_SOFTIRQ); ++ raise_hrtimer_softirq(); + } + + __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD); +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1766,7 +1766,7 @@ static void run_local_timers(void) + if (time_before(jiffies, base->next_expiry)) + return; + } +- raise_softirq(TIMER_SOFTIRQ); ++ raise_timer_softirq(); + } + + /* diff --git a/patches/x86__stackprotector__Avoid_random_pool_on_rt.patch b/patches/x86__stackprotector__Avoid_random_pool_on_rt.patch deleted file mode 100644 index 32d1a877335f..000000000000 --- a/patches/x86__stackprotector__Avoid_random_pool_on_rt.patch +++ /dev/null @@ -1,49 +0,0 @@ -Subject: x86: stackprotector: Avoid random pool on rt -From: Thomas Gleixner <tglx@linutronix.de> -Date: Thu Dec 16 14:25:18 2010 +0100 - -From: Thomas Gleixner <tglx@linutronix.de> - -CPU bringup calls into the random pool to initialize the stack -canary. During boot that works nicely even on RT as the might sleep -checks are disabled. During CPU hotplug the might sleep checks -trigger. Making the locks in random raw is a major PITA, so avoid the -call on RT is the only sensible solution. This is basically the same -randomness which we get during boot where the random pool has no -entropy and we rely on the TSC randomnness. - -Reported-by: Carsten Emde <carsten.emde@osadl.org> -Signed-off-by: Thomas Gleixner <tglx@linutronix.de> - - - ---- - arch/x86/include/asm/stackprotector.h | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) ---- ---- a/arch/x86/include/asm/stackprotector.h -+++ b/arch/x86/include/asm/stackprotector.h -@@ -50,7 +50,7 @@ - */ - static __always_inline void boot_init_stack_canary(void) - { -- u64 canary; -+ u64 canary = 0; - u64 tsc; - - #ifdef CONFIG_X86_64 -@@ -61,8 +61,14 @@ static __always_inline void boot_init_st - * of randomness. The TSC only matters for very early init, - * there it already has some randomness on most systems. Later - * on during the bootup the random pool has true entropy too. -+ * For preempt-rt we need to weaken the randomness a bit, as -+ * we can't call into the random generator from atomic context -+ * due to locking constraints. We just leave canary -+ * uninitialized and use the TSC based randomness on top of it. - */ -+#ifndef CONFIG_PREEMPT_RT - get_random_bytes(&canary, sizeof(canary)); -+#endif - tsc = rdtsc(); - canary += tsc + (tsc << 32UL); - canary &= CANARY_MASK; |