Skip to content

hrtimers: Prevent hrtimer interrupt starvation

Thomas Gleixner linux-fsdevel linux-pm lkml netfilter-devel 2 versions – Applied

Status from this message: The following commit has been merged into the timers/core branch of tip:

Get series with b4
b4 am [email protected]

Versions newest first · linked by author and title

  1. v2 Latest11 patches 12 repliesApplied
  2. v112 patches 52 repliesApplied

Changes in v2 from the cover letter

- Dropped the clockevents patch as it is already merged

- Rebased on tip timers/core

- Moved the user check into hrtimer_start_range_ns_user() - Peter

- Renamed alarmtimer_start() to alarm_start_timer() - Peter

- Picked up tags as appropriate

Patches in v2 Applied

#Subject and filesSizeRepliesApplied
1/11hrtimer: Provide hrtimer_start_range_ns_user()include/linux/hrtimer.h include/trace/events/timer.h kernel/time/hrtimer.c+148 -193 replies
2/11hrtimer: Use hrtimer_start_expires_user() for hrtimer sleeperskernel/time/hrtimer.c+5 -11 reply
3/11posix-timers: Expand timer_[re]arm() callbacks with a boolean return valuekernel/time/alarmtimer.c kernel/time/posix-cpu-timers.c kernel/time/posix-timers.c +1 more+20 -141 reply
4/11posix-timers: Handle the timer_[re]arm() return valuekernel/time/posix-timers.c+17 -51 reply
5/11posix-timers: Switch to hrtimer_start_expires_user()kernel/time/posix-timers.c+6 -51 reply
6/11alarmtimer: Provide alarm_start_timer()include/linux/alarmtimer.h kernel/time/alarmtimer.c+34 -01 reply
7/11alarmtimer: Convert posix timer functions to alarm_start_timer()kernel/time/alarmtimer.c+13 -71 reply
8/11fs/timerfd: Use the new alarm/hrtimer functionsfs/timerfd.c+68 -491 reply
9/11power: supply: charger-manager: Switch to alarm_start_timer()drivers/power/supply/charger-manager.c+7 -51 reply
10/11netfilter: xt_IDLETIMER: Switch to alarm_start_timer()net/netfilter/xt_IDLETIMER.c+18 -60 replies
11/11alarmtimer: Remove unused interfacesinclude/linux/alarmtimer.h kernel/time/alarmtimer.c+0 -471 reply

Reviews trailers per patch

10 of 11 patches have a Reviewed-by or Acked-by.

PatchPeter Zijlstra (Intel)John StultzFrederic WeisbeckerSebastian Reichel
1/11R-b
2/11A-b R-b
3/11A-b A-b R-b
4/11A-b R-b
5/11A-b R-b
6/11A-b R-b
7/11A-b R-b
8/11R-b
9/11A-b
10/11
11/11R-b

Trailers given in replies are filled; those carried in the patches from earlier versions are outlined with dashes. Scroll the table sideways for all 4 reviewers.

Read the v2 thread

Cover letter [patch V2 00/11] hrtimers: Prevent hrtimer interrupt starvation

This is a follow up to V1 which can be found here:

https://lore.kernel.org/lkml/[email protected]

Calvin reported an odd NMI watchdog lockup which claims that the CPU locked up in user space:

https://lore.kernel.org/lkml/[email protected]/

He provided a reproducer, which sets up a timerfd based timer and then rearms it in a loop with an absolute expiry time of 1ns.

As the expiry time is in the past, the timer ends up as the first expiring timer in the per CPU hrtimer base and the clockevent device is programmed with the minimum delta value. If the machine is fast enough, this ends up in a endless loop of programming the delta value to the minimum value defined by the clock event device, before the timer interrupt can fire, which starves the interrupt and consequently triggers the lockup detector because the hrtimer callback of the lockup mechanism is never invoked.

The first patch in the V1 series changes the clockevent set next event mechanism to prevent reprogramming of the clockevent device when the minimum delta value was programmed unless the new delta is larger than that. It's a less convoluted variant of the patch which was posted in the above linked thread and was confirmed to prevent the starvation problem.

But that's only to be considered the last resort because it results in an insane amount of avoidable hrtimer interrupts. That patch has been merged into the tip tree already.

The problem of user controlled timers is that the input value is only sanity checked vs. validity of the provided timespec and clamped to be in the maximum allowable range. But for performance reasons for in kernel usage there is no check whether a to be armed timer might have been expired already at enqueue time.

This series addresses this by providing a separate interface to arm user controlled timers. This works the same way as the existing hrtimer_start_range_ns(), but in case that the timer ends up as the first timer in the clock base after enqueue it provides additional checks:

- Whether the timer becomes the first expiring timer in the CPU base.

If not the timer is considered to expire in the future as there is already an earlier event programmed.

- Whether the timer has expired already by comparing the expiry value against current time.

If it is expired, the timer is removed from the clock base and the function returns false, so that the caller can handle it. That's required because the function cannot invoke the callback as that might need to acquire a lock which is held by the caller.

This function is then used for the user controlled timer arming interfaces mainly by converting hrtimer sleeper over to it. That affects a few in kernel users too, but the overhead is minimal in that case and it spares a tedious whack the mole game all over the tree.

The other usage sites in posixtimers, alarmtimers and timerfd are converted as well, which should cover the vast majority of user space controllable timers as far as my investigation goes.

Changes vs. V1:

- Dropped the clockevents patch as it is already merged

- Rebased on tip timers/core

- Moved the user check into hrtimer_start_range_ns_user() - Peter

- Renamed alarmtimer_start() to alarm_start_timer() - Peter

- Picked up tags as appropriate

The series applies against tip timers/core and is also available from git:

git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git hrtimer-exp-v2

Thanks,

tglx

---
 drivers/power/supply/charger-manager.c |   12 +-
 fs/timerfd.c                           |  117 ++++++++++++++++-----------
 include/linux/alarmtimer.h             |    9 +-
 include/linux/hrtimer.h                |   20 ++++
 include/trace/events/timer.h           |   13 +++
 kernel/time/alarmtimer.c               |   70 +++++++---------
 kernel/time/hrtimer.c                  |  140 ++++++++++++++++++++++++++++-----
 kernel/time/posix-cpu-timers.c         |   18 ++--
 kernel/time/posix-timers.c             |   35 +++++---
 kernel/time/posix-timers.h             |    4 
 net/netfilter/xt_IDLETIMER.c           |   24 ++++-
 11 files changed, 320 insertions(+), 142 deletions(-)