summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2021-12-01 18:28:28 +0100
committerSebastian Andrzej Siewior <bigeasy@linutronix.de>2021-12-01 18:28:28 +0100
commitbec6ba2d99203bdfa6b25abc409a3d4891b8b121 (patch)
tree14df1ff4e1a76a54ff3e2eef5d6b45b6a4c6a63f
parent1cb608242f364b19931feba543329a8380de8e63 (diff)
downloadlinux-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.patch2
-rw-r--r--patches/series2
-rw-r--r--patches/softirq-Use-a-dedicated-thread-for-timer-wakeups.patch204
-rw-r--r--patches/x86__stackprotector__Avoid_random_pool_on_rt.patch49
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;