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

Configure Feed

Select the types of activity you want to include in your feed.

hrtimer: Unbreak hrtimer_force_reprogram()

Since the recent consoliation of reprogramming functions,
hrtimer_force_reprogram() is affected by a check whether the new expiry
time is past the current expiry time.

This breaks the NOHZ logic as that relies on the fact that the tick hrtimer
is moved into the future. That means cpu_base->expires_next becomes stale
and subsequent reprogramming attempts fail as well until the situation is
cleaned up by an hrtimer interrupts.

For some yet unknown reason this leads to a complete stall, so for now
partially revert the offending commit to a known working state. The root
cause for the stall is still investigated and will be fixed in a subsequent
commit.

Fixes: b14bca97c9f5 ("hrtimer: Consolidate reprogramming code")
Reported-by: Mike Galbraith <efault@gmx.de>
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Mike Galbraith <efault@gmx.de>
Link: https://lore.kernel.org/r/8735recskh.ffs@tglx

+20 -20
+20 -20
kernel/time/hrtimer.c
··· 652 652 return __hrtimer_hres_active(this_cpu_ptr(&hrtimer_bases)); 653 653 } 654 654 655 - static void 656 - __hrtimer_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal, 657 - struct hrtimer *next_timer, ktime_t expires_next) 655 + static void __hrtimer_reprogram(struct hrtimer_cpu_base *cpu_base, 656 + struct hrtimer *next_timer, 657 + ktime_t expires_next) 658 658 { 659 - /* 660 - * If the hrtimer interrupt is running, then it will reevaluate the 661 - * clock bases and reprogram the clock event device. 662 - */ 663 - if (cpu_base->in_hrtirq) 664 - return; 665 - 666 - if (expires_next > cpu_base->expires_next) 667 - return; 668 - 669 - if (skip_equal && expires_next == cpu_base->expires_next) 670 - return; 671 - 672 - cpu_base->next_timer = next_timer; 673 659 cpu_base->expires_next = expires_next; 674 660 675 661 /* ··· 693 707 694 708 expires_next = hrtimer_update_next_event(cpu_base); 695 709 696 - __hrtimer_reprogram(cpu_base, skip_equal, cpu_base->next_timer, 697 - expires_next); 710 + if (skip_equal && expires_next == cpu_base->expires_next) 711 + return; 712 + 713 + __hrtimer_reprogram(cpu_base, cpu_base->next_timer, expires_next); 698 714 } 699 715 700 716 /* High resolution timer related functions */ ··· 851 863 if (base->cpu_base != cpu_base) 852 864 return; 853 865 854 - __hrtimer_reprogram(cpu_base, true, timer, expires); 866 + if (expires >= cpu_base->expires_next) 867 + return; 868 + 869 + /* 870 + * If the hrtimer interrupt is running, then it will reevaluate the 871 + * clock bases and reprogram the clock event device. 872 + */ 873 + if (cpu_base->in_hrtirq) 874 + return; 875 + 876 + cpu_base->next_timer = timer; 877 + 878 + __hrtimer_reprogram(cpu_base, timer, expires); 855 879 } 856 880 857 881 static bool update_needs_ipi(struct hrtimer_cpu_base *cpu_base,