diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2022-05-11 16:47:07 +0200 |
---|---|---|
committer | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2022-05-11 16:47:07 +0200 |
commit | bcc43dc58987708e7f68c7a6bac57b92ef5722e8 (patch) | |
tree | c98d272c4395f01ab4760376ae311a2a228a8634 | |
parent | 5ab3e4494dad3d2c934feb52cb3c5b28bb096109 (diff) | |
download | linux-rt-bcc43dc58987708e7f68c7a6bac57b92ef5722e8.tar.gz |
[ANNOUNCE] v5.18-rc6-rt7v5.18-rc6-rt7-patches
Dear RT folks!
I'm pleased to announce the v5.18-rc6-rt7 patch set.
Changes since v5.18-rc6-rt6:
- The irq simulator did not invoke the interrupts in hardirq context,
as it should.
- Provide generic_handle_domain_irq_safe(). It has been reported via
the kernel bugzilla that the amd-pincrl driver reports interrupts in
the wrong context.
- rcutorture could miss pending timers because ktimers runs at the
same priority as the rcutorture thread. Patch by Frederic
Weisbecker.
- Since the introduction of timersd in v5.16-rc3-rt7 there can be a in
the NO_HZ mode. Patch by Frederic Weisbecker.
- A small optimisation in iio's stm32-adc driver.
- An unused macro in lockdep has been removed.
Known issues
- 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.18-rc6-rt6 is appended below and can be found here:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.18/incr/patch-5.18-rc6-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.18-rc6-rt7
The RT patch against v5.18-rc6 can be found here:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.18/older/patch-5.18-rc6-rt7.patch.xz
The split quilt queue is available at:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.18/older/patches-5.18-rc6-rt7.tar.xz
Sebastian
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
8 files changed, 432 insertions, 1 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/genirq-Provide-generic_handle_domain_irq_safe.patch b/patches/genirq-Provide-generic_handle_domain_irq_safe.patch new file mode 100644 index 000000000000..3deba9c63660 --- /dev/null +++ b/patches/genirq-Provide-generic_handle_domain_irq_safe.patch @@ -0,0 +1,152 @@ +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Mon, 9 May 2022 16:04:08 +0200 +Subject: [PATCH] genirq: Provide generic_handle_domain_irq_safe(). + +Provide generic_handle_domain_irq_safe() which can used from any context. +This similar to commit + 509853f9e1e7b ("genirq: Provide generic_handle_irq_safe()") + +but this time for the irq-domains interface. It has been reported for +the amd-pinctrl driver via bugzilla + https://bugzilla.kernel.org/show_bug.cgi?id=215954 + +I looked around and added a few users so it is not just one user API :) +Instead of generic_handle_irq(irq_find_mapping)) one can use +generic_handle_domain_irq(). + +The problem with generic_handle_domain_irq() is that with `threadirqs' +it will trigger "WARN_ON_ONCE(!in_hardirq())". That interrupt handler +can't be marked non-threaded because it is a shared handler (it is +marked as such and I can't tell the interrupt can be really shared on +the system). +Ignoring the just mentioned warning, on PREEMPT_RT the threaded handler +is invoked with enabled interrupts leading other problems. + +Do we do this? + +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Link: https://lore.kernel.org/r/YnkfWFzvusFFktSt@linutronix.de +--- + drivers/bcma/driver_gpio.c | 2 +- + drivers/gpio/gpio-mlxbf2.c | 6 ++---- + drivers/pinctrl/pinctrl-amd.c | 2 +- + drivers/platform/x86/intel/int0002_vgpio.c | 3 +-- + drivers/ssb/driver_gpio.c | 6 ++++-- + include/linux/irqdesc.h | 1 + + kernel/irq/irqdesc.c | 24 ++++++++++++++++++++++++ + 7 files changed, 34 insertions(+), 10 deletions(-) + +--- a/drivers/bcma/driver_gpio.c ++++ b/drivers/bcma/driver_gpio.c +@@ -113,7 +113,7 @@ static irqreturn_t bcma_gpio_irq_handler + return IRQ_NONE; + + for_each_set_bit(gpio, &irqs, gc->ngpio) +- generic_handle_irq(irq_find_mapping(gc->irq.domain, gpio)); ++ generic_handle_domain_irq_safe(gc->irq.domain, gpio); + bcma_chipco_gpio_polarity(cc, irqs, val & irqs); + + return IRQ_HANDLED; +--- a/drivers/gpio/gpio-mlxbf2.c ++++ b/drivers/gpio/gpio-mlxbf2.c +@@ -273,10 +273,8 @@ static irqreturn_t mlxbf2_gpio_irq_handl + pending = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CAUSE_EVTEN0); + writel(pending, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); + +- for_each_set_bit(level, &pending, gc->ngpio) { +- int gpio_irq = irq_find_mapping(gc->irq.domain, level); +- generic_handle_irq(gpio_irq); +- } ++ for_each_set_bit(level, &pending, gc->ngpio) ++ generic_handle_domain_irq_safe(gc->irq.domain, level); + + return IRQ_RETVAL(pending); + } +--- a/drivers/pinctrl/pinctrl-amd.c ++++ b/drivers/pinctrl/pinctrl-amd.c +@@ -638,7 +638,7 @@ static bool do_amd_gpio_irq_handler(int + if (!(regval & PIN_IRQ_PENDING) || + !(regval & BIT(INTERRUPT_MASK_OFF))) + continue; +- generic_handle_domain_irq(gc->irq.domain, irqnr + i); ++ generic_handle_domain_irq_safe(gc->irq.domain, irqnr + i); + + /* Clear interrupt. + * We must read the pin register again, in case the +--- a/drivers/platform/x86/intel/int0002_vgpio.c ++++ b/drivers/platform/x86/intel/int0002_vgpio.c +@@ -125,8 +125,7 @@ static irqreturn_t int0002_irq(int irq, + if (!(gpe_sts_reg & GPE0A_PME_B0_STS_BIT)) + return IRQ_NONE; + +- generic_handle_irq(irq_find_mapping(chip->irq.domain, +- GPE0A_PME_B0_VIRT_GPIO_PIN)); ++ generic_handle_domain_irq_safe(chip->irq.domain, GPE0A_PME_B0_VIRT_GPIO_PIN); + + pm_wakeup_hard_event(chip->parent); + +--- a/drivers/ssb/driver_gpio.c ++++ b/drivers/ssb/driver_gpio.c +@@ -132,7 +132,8 @@ static irqreturn_t ssb_gpio_irq_chipco_h + return IRQ_NONE; + + for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) +- generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ generic_handle_domain_irq_safe(bus->irq_domain, gpio); ++ + ssb_chipco_gpio_polarity(chipco, irqs, val & irqs); + + return IRQ_HANDLED; +@@ -330,7 +331,8 @@ static irqreturn_t ssb_gpio_irq_extif_ha + return IRQ_NONE; + + for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) +- generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ generic_handle_domain_irq_safe(bus->irq_domain, gpio); ++ + ssb_extif_gpio_polarity(extif, irqs, val & irqs); + + return IRQ_HANDLED; +--- a/include/linux/irqdesc.h ++++ b/include/linux/irqdesc.h +@@ -169,6 +169,7 @@ int generic_handle_irq_safe(unsigned int + * conversion failed. + */ + int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq); ++int generic_handle_domain_irq_safe(struct irq_domain *domain, unsigned int hwirq); + int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq); + #endif + +--- a/kernel/irq/irqdesc.c ++++ b/kernel/irq/irqdesc.c +@@ -706,6 +706,30 @@ int generic_handle_domain_irq(struct irq + } + EXPORT_SYMBOL_GPL(generic_handle_domain_irq); + ++ /** ++ * generic_handle_irq_safe - Invoke the handler for a HW irq belonging ++ * to a domain from any context. ++ * @domain: The domain where to perform the lookup ++ * @hwirq: The HW irq number to convert to a logical one ++ * ++ * Returns: 0 on success, a negative value on error. ++ * ++ * This function can be called from any context (IRQ or process context). It ++ * will report an error if not invoked from IRQ context and the irq has been ++ * marked to enforce IRQ-context only. ++ */ ++int generic_handle_domain_irq_safe(struct irq_domain *domain, unsigned int hwirq) ++{ ++ unsigned long flags; ++ int ret; ++ ++ local_irq_save(flags); ++ ret = handle_irq_desc(irq_resolve_mapping(domain, hwirq)); ++ local_irq_restore(flags); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(generic_handle_domain_irq_safe); ++ + /** + * generic_handle_domain_nmi - Invoke the handler for a HW nmi belonging + * to a domain. diff --git a/patches/genirq-irq_sim-Make-the-irq_work-always-run-in-hard-.patch b/patches/genirq-irq_sim-Make-the-irq_work-always-run-in-hard-.patch new file mode 100644 index 000000000000..d00e8b607af5 --- /dev/null +++ b/patches/genirq-irq_sim-Make-the-irq_work-always-run-in-hard-.patch @@ -0,0 +1,37 @@ +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Wed, 11 May 2022 13:07:50 +0200 +Subject: [PATCH] genirq/irq_sim: Make the irq_work always run in hard irq + context. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The IRQ simulator uses irq_work to trigger an interrupt. Without the +IRQ_WORK_HARD_IRQ flag the irq_work will be performed in thread context +on PREEMPT_RT. This causes locking errors later in handle_simple_irq() +which expects to be invoked with disabled interrupts. + +Triggering individual interrupts in hardirq context should not lead to +unexpected high latencies since this is also what the hardware +controller does. Also it is used as a simulator so… + +Use IRQ_WORK_INIT_HARD() to carry out the irq_work in hardirq context on +PREEMPT_RT. + +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Link: https://lore.kernel.org/r/YnuZBoEVMGwKkLm+@linutronix.de +--- + kernel/irq/irq_sim.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/kernel/irq/irq_sim.c ++++ b/kernel/irq/irq_sim.c +@@ -181,7 +181,7 @@ struct irq_domain *irq_domain_create_sim + goto err_free_bitmap; + + work_ctx->irq_count = num_irqs; +- init_irq_work(&work_ctx->work, irq_sim_handle_irq); ++ work_ctx->work = IRQ_WORK_INIT_HARD(irq_sim_handle_irq); + + return work_ctx->domain; + diff --git a/patches/iio-adc-stm32-adc-Use-generic_handle_domain_irq.patch b/patches/iio-adc-stm32-adc-Use-generic_handle_domain_irq.patch new file mode 100644 index 000000000000..485c3e422fbd --- /dev/null +++ b/patches/iio-adc-stm32-adc-Use-generic_handle_domain_irq.patch @@ -0,0 +1,35 @@ +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Wed, 11 May 2022 13:06:09 +0200 +Subject: [PATCH] iio: adc: stm32-adc: Use generic_handle_domain_irq() + +The call chain + generic_handle_irq(irq_find_mapping(domain, x)); + +could be replaced with + generic_handle_domain_irq(domain, x); + +which looks up the struct irq_desc for the interrupt and handles it with +handle_irq_desc(). +This is a slight optimisation given that the driver invokes only one +function and the struct irq_desc is used directly instead being looked +up via irq_to_desc(). + +Use generic_handle_domain_irq(). + +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Link: https://lore.kernel.org/r/YnuYoQIzJoFIyEJY@linutronix.de +--- + drivers/iio/adc/stm32-adc-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/iio/adc/stm32-adc-core.c ++++ b/drivers/iio/adc/stm32-adc-core.c +@@ -356,7 +356,7 @@ static void stm32_adc_irq_handler(struct + if ((status & priv->cfg->regs->eoc_msk[i] && + stm32_adc_eoc_enabled(priv, i)) || + (status & priv->cfg->regs->ovr_msk[i])) +- generic_handle_irq(irq_find_mapping(priv->domain, i)); ++ generic_handle_domain_irq(priv->domain, i); + } + + chained_irq_exit(chip, desc); diff --git a/patches/locking-lockdep-Remove-lockdep_init_map_crosslock.patch b/patches/locking-lockdep-Remove-lockdep_init_map_crosslock.patch new file mode 100644 index 000000000000..92696439986d --- /dev/null +++ b/patches/locking-lockdep-Remove-lockdep_init_map_crosslock.patch @@ -0,0 +1,26 @@ +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Fri, 11 Mar 2022 17:44:57 +0100 +Subject: [PATCH] locking/lockdep: Remove lockdep_init_map_crosslock. + +The cross-release bits have been removed, lockdep_init_map_crosslock() is +a leftover. + +Remove lockdep_init_map_crosslock. + +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Reviewed-by: Waiman Long <longman@redhat.com> +Link: https://lore.kernel.org/r/20220311164457.46461-1-bigeasy@linutronix.de +--- + include/linux/lockdep.h | 1 - + 1 file changed, 1 deletion(-) + +--- a/include/linux/lockdep.h ++++ b/include/linux/lockdep.h +@@ -431,7 +431,6 @@ enum xhlock_context_t { + XHLOCK_CTX_NR, + }; + +-#define lockdep_init_map_crosslock(m, n, k, s) do {} while (0) + /* + * To initialize a lockdep_map statically use this macro. + * Note that _name must not be NULL. diff --git a/patches/rcutorture-Also-force-sched-priority-to-timersd-on-b.patch b/patches/rcutorture-Also-force-sched-priority-to-timersd-on-b.patch new file mode 100644 index 000000000000..81388d4b14c5 --- /dev/null +++ b/patches/rcutorture-Also-force-sched-priority-to-timersd-on-b.patch @@ -0,0 +1,70 @@ +From: Frederic Weisbecker <frederic@kernel.org> +Date: Tue, 5 Apr 2022 03:07:51 +0200 +Subject: [PATCH] rcutorture: Also force sched priority to timersd on + boosting test. + +ksoftirqd is statically boosted to the priority level right above the +one of rcu_torture_boost() so that timers, which torture readers rely on, +get a chance to run while rcu_torture_boost() is polling. + +However timers processing got split from ksoftirqd into their own kthread +(timersd) that isn't boosted. It has the same SCHED_FIFO low prio as +rcu_torture_boost() and therefore timers can't preempt it and may +starve. + +The issue can be triggered in practice on v5.17.1-rt17 using: + + ./kvm.sh --allcpus --configs TREE04 --duration 10m --kconfig "CONFIG_EXPERT=y CONFIG_PREEMPT_RT=y" + +Fix this with statically boosting timersd just like is done with +ksoftirqd in commit + ea6d962e80b61 ("rcutorture: Judge RCU priority boosting on grace periods, not callbacks") + +Suggested-by: Mel Gorman <mgorman@suse.de> +Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Cc: Thomas Gleixner <tglx@linutronix.de> +Signed-off-by: Frederic Weisbecker <frederic@kernel.org> +Link: https://lkml.kernel.org/r/20220405010752.1347437-1-frederic@kernel.org +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + include/linux/interrupt.h | 1 + + kernel/rcu/rcutorture.c | 6 ++++++ + kernel/softirq.c | 2 +- + 3 files changed, 8 insertions(+), 1 deletion(-) + +--- a/include/linux/interrupt.h ++++ b/include/linux/interrupt.h +@@ -624,6 +624,7 @@ extern void raise_softirq_irqoff(unsigne + extern void raise_softirq(unsigned int nr); + + #ifdef CONFIG_PREEMPT_RT ++DECLARE_PER_CPU(struct task_struct *, timersd); + extern void raise_timer_softirq(void); + extern void raise_hrtimer_softirq(void); + +--- a/kernel/rcu/rcutorture.c ++++ b/kernel/rcu/rcutorture.c +@@ -3294,6 +3294,12 @@ rcu_torture_init(void) + WARN_ON_ONCE(!t); + sp.sched_priority = 2; + sched_setscheduler_nocheck(t, SCHED_FIFO, &sp); ++#ifdef CONFIG_PREEMPT_RT ++ t = per_cpu(timersd, cpu); ++ WARN_ON_ONCE(!t); ++ sp.sched_priority = 2; ++ sched_setscheduler_nocheck(t, SCHED_FIFO, &sp); ++#endif + } + } + } +--- a/kernel/softirq.c ++++ b/kernel/softirq.c +@@ -637,7 +637,7 @@ static inline void tick_irq_exit(void) + #endif + } + +-static DEFINE_PER_CPU(struct task_struct *, timersd); ++DEFINE_PER_CPU(struct task_struct *, timersd); + static DEFINE_PER_CPU(unsigned long, pending_timer_softirq); + + static unsigned int local_pending_timers(void) diff --git a/patches/series b/patches/series index db6e53b41582..956481f72a27 100644 --- a/patches/series +++ b/patches/series @@ -47,6 +47,8 @@ SUNRPC-Don-t-disable-preemption-while-calling-svc_po.patch 0002-scsi-fcoe-Use-per-CPU-API-to-update-per-CPU-statisti.patch 0003-scsi-libfc-Remove-get_cpu-semantics-in-fc_exch_em_al.patch 0004-scsi-bnx2fc-Avoid-using-get_cpu-in-bnx2fc_cmd_alloc.patch +genirq-irq_sim-Make-the-irq_work-always-run-in-hard-.patch +genirq-Provide-generic_handle_domain_irq_safe.patch # Eric's ptrace, v4 0001-signal-Rename-send_signal-send_signal_locked.patch @@ -90,11 +92,15 @@ x86__Enable_RT_also_on_32bit.patch # For later, not essencial ########################################################################### softirq-Use-a-dedicated-thread-for-timer-wakeups.patch +rcutorture-Also-force-sched-priority-to-timersd-on-b.patch +tick-Fix-timer-storm-since-introduction-of-timersd.patch tpm_tis__fix_stall_after_iowrites.patch drivers_block_zram__Replace_bit_spinlocks_with_rtmutex_for_-rt.patch generic-softirq-Disable-softirq-stacks-on-PREEMPT_RT.patch softirq-Disable-softirq-stacks-on-PREEMPT_RT.patch crypto-cryptd-Protect-per-CPU-resource-by-disabling-.patch +iio-adc-stm32-adc-Use-generic_handle_domain_irq.patch +locking-lockdep-Remove-lockdep_init_map_crosslock.patch ########################################################################### # DRM: diff --git a/patches/tick-Fix-timer-storm-since-introduction-of-timersd.patch b/patches/tick-Fix-timer-storm-since-introduction-of-timersd.patch new file mode 100644 index 000000000000..3febe509a913 --- /dev/null +++ b/patches/tick-Fix-timer-storm-since-introduction-of-timersd.patch @@ -0,0 +1,105 @@ +From: Frederic Weisbecker <frederic@kernel.org> +Date: Tue, 5 Apr 2022 03:07:52 +0200 +Subject: [PATCH] tick: Fix timer storm since introduction of timersd + +If timers are pending while the tick is reprogrammed on nohz_mode, the +next expiry is not armed to fire now, it is delayed one jiffy forward +instead so as not to raise an inextinguishable timer storm with such +scenario: + +1) IRQ triggers and queue a timer +2) ksoftirqd() is woken up +3) IRQ tail: timer is reprogrammed to fire now +4) IRQ exit +5) TIMER interrupt +6) goto 3) + +...all that until we finally reach ksoftirqd. + +Unfortunately we are checking the wrong softirq vector bitmask since +timersd kthread has split from ksoftirqd. Timers now have their own +vector state field that must be checked separately. As a result, the +old timer storm is back. This shows up early on boot with extremely long +initcalls: + + [ 333.004807] initcall dquot_init+0x0/0x111 returned 0 after 323822879 usecs + +and the cause is uncovered with the right trace events showing just +10 microseconds between ticks (~100 000 Hz): + +|swapper/-1 1dn.h111 60818582us : hrtimer_expire_entry: hrtimer=00000000e0ef0f6b function=tick_sched_timer now=60415486608 +|swapper/-1 1dn.h111 60818592us : hrtimer_expire_entry: hrtimer=00000000e0ef0f6b function=tick_sched_timer now=60415496082 +|swapper/-1 1dn.h111 60818601us : hrtimer_expire_entry: hrtimer=00000000e0ef0f6b function=tick_sched_timer now=60415505550 + +Fix this by checking the right timer vector state from the nohz code. + +Signed-off-by: Frederic Weisbecker <frederic@kernel.org> +Cc: Mel Gorman <mgorman@suse.de> +Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Cc: Thomas Gleixner <tglx@linutronix.de> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Link: https://lkml.kernel.org/r/20220405010752.1347437-2-frederic@kernel.org +--- + include/linux/interrupt.h | 12 ++++++++++++ + kernel/softirq.c | 7 +------ + kernel/time/tick-sched.c | 2 +- + 3 files changed, 14 insertions(+), 7 deletions(-) + +--- a/include/linux/interrupt.h ++++ b/include/linux/interrupt.h +@@ -625,9 +625,16 @@ extern void raise_softirq(unsigned int n + + #ifdef CONFIG_PREEMPT_RT + DECLARE_PER_CPU(struct task_struct *, timersd); ++DECLARE_PER_CPU(unsigned long, pending_timer_softirq); ++ + extern void raise_timer_softirq(void); + extern void raise_hrtimer_softirq(void); + ++static inline unsigned int local_pending_timers(void) ++{ ++ return __this_cpu_read(pending_timer_softirq); ++} ++ + #else + static inline void raise_timer_softirq(void) + { +@@ -638,6 +645,11 @@ static inline void raise_hrtimer_softirq + { + raise_softirq_irqoff(HRTIMER_SOFTIRQ); + } ++ ++static inline unsigned int local_pending_timers(void) ++{ ++ return local_softirq_pending(); ++} + #endif + + DECLARE_PER_CPU(struct task_struct *, ksoftirqd); +--- a/kernel/softirq.c ++++ b/kernel/softirq.c +@@ -638,12 +638,7 @@ static inline void tick_irq_exit(void) + } + + 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); +-} ++DEFINE_PER_CPU(unsigned long, pending_timer_softirq); + + static void wake_timersd(void) + { +--- a/kernel/time/tick-sched.c ++++ b/kernel/time/tick-sched.c +@@ -780,7 +780,7 @@ static void tick_nohz_restart(struct tic + + static inline bool local_timer_softirq_pending(void) + { +- return local_softirq_pending() & BIT(TIMER_SOFTIRQ); ++ return local_pending_timers() & BIT(TIMER_SOFTIRQ); + } + + static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu) |