113 lines
4.2 KiB
Diff
113 lines
4.2 KiB
Diff
|
From 2c91f2661cb66544c8c8e41721eb48788dfcec52 Mon Sep 17 00:00:00 2001
|
||
|
From: Steven Rostedt <rostedt@goodmis.org>
|
||
|
Date: Tue, 4 Mar 2014 12:28:32 -0500
|
||
|
Subject: [PATCH 216/365] cpu_chill: Add a UNINTERRUPTIBLE hrtimer_nanosleep
|
||
|
|
||
|
We hit another bug that was caused by switching cpu_chill() from
|
||
|
msleep() to hrtimer_nanosleep().
|
||
|
|
||
|
This time it is a livelock. The problem is that hrtimer_nanosleep()
|
||
|
calls schedule with the state == TASK_INTERRUPTIBLE. But these means
|
||
|
that if a signal is pending, the scheduler wont schedule, and will
|
||
|
simply change the current task state back to TASK_RUNNING. This
|
||
|
nullifies the whole point of cpu_chill() in the first place. That is,
|
||
|
if a task is spinning on a try_lock() and it preempted the owner of the
|
||
|
lock, if it has a signal pending, it will never give up the CPU to let
|
||
|
the owner of the lock run.
|
||
|
|
||
|
I made a static function __hrtimer_nanosleep() that takes a fifth
|
||
|
parameter "state", which determines the task state of that the
|
||
|
nanosleep() will be in. The normal hrtimer_nanosleep() will act the
|
||
|
same, but cpu_chill() will call the __hrtimer_nanosleep() directly with
|
||
|
the TASK_UNINTERRUPTIBLE state.
|
||
|
|
||
|
cpu_chill() only cares that the first sleep happens, and does not care
|
||
|
about the state of the restart schedule (in hrtimer_nanosleep_restart).
|
||
|
|
||
|
|
||
|
Reported-by: Ulrich Obergfell <uobergfe@redhat.com>
|
||
|
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
|
||
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||
|
---
|
||
|
kernel/time/hrtimer.c | 25 ++++++++++++++++++-------
|
||
|
1 file changed, 18 insertions(+), 7 deletions(-)
|
||
|
|
||
|
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
|
||
|
index a652e5bcbc37..d2fb17faae9f 100644
|
||
|
--- a/kernel/time/hrtimer.c
|
||
|
+++ b/kernel/time/hrtimer.c
|
||
|
@@ -1669,12 +1669,13 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task)
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(hrtimer_init_sleeper);
|
||
|
|
||
|
-static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)
|
||
|
+static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode,
|
||
|
+ unsigned long state)
|
||
|
{
|
||
|
hrtimer_init_sleeper(t, current);
|
||
|
|
||
|
do {
|
||
|
- set_current_state(TASK_INTERRUPTIBLE);
|
||
|
+ set_current_state(state);
|
||
|
hrtimer_start_expires(&t->timer, mode);
|
||
|
|
||
|
if (likely(t->task))
|
||
|
@@ -1716,7 +1717,8 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
|
||
|
HRTIMER_MODE_ABS);
|
||
|
hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires);
|
||
|
|
||
|
- if (do_nanosleep(&t, HRTIMER_MODE_ABS))
|
||
|
+ /* cpu_chill() does not care about restart state. */
|
||
|
+ if (do_nanosleep(&t, HRTIMER_MODE_ABS, TASK_INTERRUPTIBLE))
|
||
|
goto out;
|
||
|
|
||
|
rmtp = restart->nanosleep.rmtp;
|
||
|
@@ -1733,8 +1735,10 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
-long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
|
||
|
- const enum hrtimer_mode mode, const clockid_t clockid)
|
||
|
+static long
|
||
|
+__hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
|
||
|
+ const enum hrtimer_mode mode, const clockid_t clockid,
|
||
|
+ unsigned long state)
|
||
|
{
|
||
|
struct restart_block *restart;
|
||
|
struct hrtimer_sleeper t;
|
||
|
@@ -1747,7 +1751,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
|
||
|
|
||
|
hrtimer_init_on_stack(&t.timer, clockid, mode);
|
||
|
hrtimer_set_expires_range_ns(&t.timer, timespec_to_ktime(*rqtp), slack);
|
||
|
- if (do_nanosleep(&t, mode))
|
||
|
+ if (do_nanosleep(&t, mode, state))
|
||
|
goto out;
|
||
|
|
||
|
/* Absolute timers do not update the rmtp value and restart: */
|
||
|
@@ -1774,6 +1778,12 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
|
||
|
+ const enum hrtimer_mode mode, const clockid_t clockid)
|
||
|
+{
|
||
|
+ return __hrtimer_nanosleep(rqtp, rmtp, mode, clockid, TASK_INTERRUPTIBLE);
|
||
|
+}
|
||
|
+
|
||
|
SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
|
||
|
struct timespec __user *, rmtp)
|
||
|
{
|
||
|
@@ -1800,7 +1810,8 @@ void cpu_chill(void)
|
||
|
unsigned int freeze_flag = current->flags & PF_NOFREEZE;
|
||
|
|
||
|
current->flags |= PF_NOFREEZE;
|
||
|
- hrtimer_nanosleep(&tu, NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
|
||
|
+ __hrtimer_nanosleep(&tu, NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC,
|
||
|
+ TASK_UNINTERRUPTIBLE);
|
||
|
if (!freeze_flag)
|
||
|
current->flags &= ~PF_NOFREEZE;
|
||
|
}
|
||
|
--
|
||
|
2.28.0
|
||
|
|