summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2019-07-26 14:30:58 -0400
committerThomas Gleixner <tglx@linutronix.de>2019-08-01 14:51:22 -0400
commit1842f5a427f5323f5c19ab99b55d09b3ab5172a5 (patch)
tree273a4d23da40d208ed187f09ae9c9a0007b2b35e
parentf5c2f0215e36d76fbb9605283dd7535af09f5770 (diff)
hrtimer: Determine hard/soft expiry mode for hrtimer sleepers on RT
On PREEMPT_RT enabled kernels hrtimers which are not explicitely marked for hard interrupt expiry mode are moved into soft interrupt context either for latency reasons or because the hrtimer callback takes regular spinlocks or invokes other functions which are not suitable for hard interrupt context on PREEMPT_RT. The hrtimer_sleeper callback is RT compatible in hard interrupt context, but there is a latency concern: Untrusted userspace can spawn many threads which arm timers for the same expiry time on the same CPU. On expiry that causes a latency spike due to the wakeup of a gazillion threads. OTOH, priviledged real-time user space applications rely on the low latency of hard interrupt wakeups. These syscall related wakeups are all based on hrtimer sleepers. If the current task is in a real-time scheduling class, mark the mode for hard interrupt expiry. [ tglx: Split out of a larger combo patch. Added changelog ] Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Steven Rostedt (VMware) <rostedt@goodmis.org> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lkml.kernel.org/r/20190726185753.645792403@linutronix.de
-rw-r--r--kernel/time/hrtimer.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 90dcc4d95e91..c101f88ae8aa 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -1676,6 +1676,16 @@ static enum hrtimer_restart hrtimer_wakeup(struct hrtimer *timer)
1676void hrtimer_sleeper_start_expires(struct hrtimer_sleeper *sl, 1676void hrtimer_sleeper_start_expires(struct hrtimer_sleeper *sl,
1677 enum hrtimer_mode mode) 1677 enum hrtimer_mode mode)
1678{ 1678{
1679 /*
1680 * Make the enqueue delivery mode check work on RT. If the sleeper
1681 * was initialized for hard interrupt delivery, force the mode bit.
1682 * This is a special case for hrtimer_sleepers because
1683 * hrtimer_init_sleeper() determines the delivery mode on RT so the
1684 * fiddling with this decision is avoided at the call sites.
1685 */
1686 if (IS_ENABLED(CONFIG_PREEMPT_RT) && sl->timer.is_hard)
1687 mode |= HRTIMER_MODE_HARD;
1688
1679 hrtimer_start_expires(&sl->timer, mode); 1689 hrtimer_start_expires(&sl->timer, mode);
1680} 1690}
1681EXPORT_SYMBOL_GPL(hrtimer_sleeper_start_expires); 1691EXPORT_SYMBOL_GPL(hrtimer_sleeper_start_expires);
@@ -1683,6 +1693,30 @@ EXPORT_SYMBOL_GPL(hrtimer_sleeper_start_expires);
1683static void __hrtimer_init_sleeper(struct hrtimer_sleeper *sl, 1693static void __hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
1684 clockid_t clock_id, enum hrtimer_mode mode) 1694 clockid_t clock_id, enum hrtimer_mode mode)
1685{ 1695{
1696 /*
1697 * On PREEMPT_RT enabled kernels hrtimers which are not explicitely
1698 * marked for hard interrupt expiry mode are moved into soft
1699 * interrupt context either for latency reasons or because the
1700 * hrtimer callback takes regular spinlocks or invokes other
1701 * functions which are not suitable for hard interrupt context on
1702 * PREEMPT_RT.
1703 *
1704 * The hrtimer_sleeper callback is RT compatible in hard interrupt
1705 * context, but there is a latency concern: Untrusted userspace can
1706 * spawn many threads which arm timers for the same expiry time on
1707 * the same CPU. That causes a latency spike due to the wakeup of
1708 * a gazillion threads.
1709 *
1710 * OTOH, priviledged real-time user space applications rely on the
1711 * low latency of hard interrupt wakeups. If the current task is in
1712 * a real-time scheduling class, mark the mode for hard interrupt
1713 * expiry.
1714 */
1715 if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
1716 if (task_is_realtime(current) && !(mode & HRTIMER_MODE_SOFT))
1717 mode |= HRTIMER_MODE_HARD;
1718 }
1719
1686 __hrtimer_init(&sl->timer, clock_id, mode); 1720 __hrtimer_init(&sl->timer, clock_id, mode);
1687 sl->timer.function = hrtimer_wakeup; 1721 sl->timer.function = hrtimer_wakeup;
1688 sl->task = current; 1722 sl->task = current;