Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ia64: fix timer cleanup regression

A cleanup patch from my legacy timer series broke ia64 and led
to RCU stall errors and a fast system clock:

[ 909.360108] INFO: task systemd-sysv-ge:200 blocked for more than 127 seconds.
[ 909.360108] Not tainted 5.10.0+ #130
[ 909.360108] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[ 909.360108] task:systemd-sysv-ge state:D stack: 0 pid: 200 ppid: 189 flags:0x00000000
[ 909.364108]
[ 909.364108] Call Trace:
[ 909.364423] [<a00000010109b210>] __schedule+0x890/0x21e0
[ 909.364423] sp=e0000100487d7b70 bsp=e0000100487d1748
[ 909.368423] [<a00000010109cc00>] schedule+0xa0/0x240
[ 909.368423] sp=e0000100487d7b90 bsp=e0000100487d16e0
[ 909.368558] [<a00000010109ce70>] io_schedule+0x70/0xa0
[ 909.368558] sp=e0000100487d7b90 bsp=e0000100487d16c0
[ 909.372290] [<a00000010109e1c0>] bit_wait_io+0x20/0xe0
[ 909.372290] sp=e0000100487d7b90 bsp=e0000100487d1698
[ 909.374168] rcu: INFO: rcu_sched detected stalls on CPUs/tasks:
[ 909.376290] [<a00000010109d860>] __wait_on_bit+0xc0/0x1c0
[ 909.376290] sp=e0000100487d7b90 bsp=e0000100487d1648
[ 909.374168] rcu: 3-....: (2 ticks this GP) idle=19e/1/0x4000000000000002 softirq=1581/1581 fqs=2
[ 909.374168] (detected by 0, t=5661 jiffies, g=1089, q=3)
[ 909.376290] [<a00000010109da80>] out_of_line_wait_on_bit+0x120/0x140
[ 909.376290] sp=e0000100487d7b90 bsp=e0000100487d1610
[ 909.374168] Task dump for CPU 3:
[ 909.374168] task:khungtaskd state:R running task

Revert most of my patch to make this work again, including the extra
update_process_times()/profile_tick() and the local_irq_enable() in the
loop that I expected not to be needed here.

I have not found out exactly what goes wrong, and would suggest that
someone with hardware access tries to convert this code into a singleshot
clockevent driver, which should give better behavior in all cases.

Reported-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Fixes: 2b49ddcef297 ("ia64: convert to legacy_timer_tick")
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

+19 -14
+19 -14
arch/ia64/kernel/time.c
··· 171 171 static irqreturn_t 172 172 timer_interrupt (int irq, void *dev_id) 173 173 { 174 - unsigned long cur_itm, new_itm, ticks; 174 + unsigned long new_itm; 175 175 176 176 if (cpu_is_offline(smp_processor_id())) { 177 177 return IRQ_HANDLED; 178 178 } 179 179 180 180 new_itm = local_cpu_data->itm_next; 181 - cur_itm = ia64_get_itc(); 182 181 183 - if (!time_after(cur_itm, new_itm)) { 182 + if (!time_after(ia64_get_itc(), new_itm)) 184 183 printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n", 185 - cur_itm, new_itm); 186 - ticks = 1; 187 - } else { 188 - ticks = DIV_ROUND_UP(cur_itm - new_itm, 189 - local_cpu_data->itm_delta); 190 - new_itm += ticks * local_cpu_data->itm_delta; 184 + ia64_get_itc(), new_itm); 185 + 186 + while (1) { 187 + new_itm += local_cpu_data->itm_delta; 188 + 189 + legacy_timer_tick(smp_processor_id() == time_keeper_id); 190 + 191 + local_cpu_data->itm_next = new_itm; 192 + 193 + if (time_after(new_itm, ia64_get_itc())) 194 + break; 195 + 196 + /* 197 + * Allow IPIs to interrupt the timer loop. 198 + */ 199 + local_irq_enable(); 200 + local_irq_disable(); 191 201 } 192 - 193 - if (smp_processor_id() != time_keeper_id) 194 - ticks = 0; 195 - 196 - legacy_timer_tick(ticks); 197 202 198 203 do { 199 204 /*