Commit 15f27ce2 authored by Al Viro's avatar Al Viro Committed by Thomas Gleixner

alarmtimer: Move copyout and freeze handling into alarmtimer_do_nsleep()

The alarmtimer nanosleep() implementation can be simplified by moving the
copy out of the remaining time to alarmtimer_do_nsleep() which is shared
between the real nanosleep function and the restart function.

The pointer to the timespec64 which is updated has to be stored in the
restart block anyway. Instead of storing it only in the restart case, store
it before calling alarmtimer_do_nsleep() and copy the remaining time in the
signal exit path.

[ tglx: Added changelog ]
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20170607084241.28657-2-viro@ZenIV.linux.org.uk
parent 86a9c446
...@@ -688,8 +688,10 @@ static enum alarmtimer_restart alarmtimer_nsleep_wakeup(struct alarm *alarm, ...@@ -688,8 +688,10 @@ static enum alarmtimer_restart alarmtimer_nsleep_wakeup(struct alarm *alarm,
* *
* Sets the alarm timer and sleeps until it is fired or interrupted. * Sets the alarm timer and sleeps until it is fired or interrupted.
*/ */
static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp) static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp,
enum alarmtimer_type type)
{ {
struct timespec __user *rmtp;
alarm->data = (void *)current; alarm->data = (void *)current;
do { do {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
...@@ -702,36 +704,26 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp) ...@@ -702,36 +704,26 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp)
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
return (alarm->data == NULL); if (!alarm->data)
}
/**
* update_rmtp - Update remaining timespec value
* @exp: expiration time
* @type: timer type
* @rmtp: user pointer to remaining timepsec value
*
* Helper function that fills in rmtp value with time between
* now and the exp value
*/
static int update_rmtp(ktime_t exp, enum alarmtimer_type type,
struct timespec __user *rmtp)
{
struct timespec rmt;
ktime_t rem;
rem = ktime_sub(exp, alarm_bases[type].gettime());
if (rem <= 0)
return 0; return 0;
rmt = ktime_to_timespec(rem);
if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) if (freezing(current))
return -EFAULT; alarmtimer_freezerset(absexp, type);
rmtp = current->restart_block.nanosleep.rmtp;
if (rmtp) {
struct timespec rmt;
ktime_t rem;
return 1; rem = ktime_sub(absexp, alarm_bases[type].gettime());
if (rem <= 0)
return 0;
rmt = ktime_to_timespec(rem);
if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
return -EFAULT;
}
return -ERESTART_RESTARTBLOCK;
} }
/** /**
...@@ -743,32 +735,12 @@ static int update_rmtp(ktime_t exp, enum alarmtimer_type type, ...@@ -743,32 +735,12 @@ static int update_rmtp(ktime_t exp, enum alarmtimer_type type,
static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) static long __sched alarm_timer_nsleep_restart(struct restart_block *restart)
{ {
enum alarmtimer_type type = restart->nanosleep.clockid; enum alarmtimer_type type = restart->nanosleep.clockid;
ktime_t exp; ktime_t exp = restart->nanosleep.expires;
struct timespec __user *rmtp;
struct alarm alarm; struct alarm alarm;
int ret = 0;
exp = restart->nanosleep.expires;
alarm_init(&alarm, type, alarmtimer_nsleep_wakeup); alarm_init(&alarm, type, alarmtimer_nsleep_wakeup);
if (alarmtimer_do_nsleep(&alarm, exp)) return alarmtimer_do_nsleep(&alarm, exp, type);
goto out;
if (freezing(current))
alarmtimer_freezerset(exp, type);
rmtp = restart->nanosleep.rmtp;
if (rmtp) {
ret = update_rmtp(exp, type, rmtp);
if (ret <= 0)
goto out;
}
/* The other values in restart are already filled in */
ret = -ERESTART_RESTARTBLOCK;
out:
return ret;
} }
/** /**
...@@ -785,11 +757,16 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, ...@@ -785,11 +757,16 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
struct timespec __user *rmtp) struct timespec __user *rmtp)
{ {
enum alarmtimer_type type = clock2alarm(which_clock); enum alarmtimer_type type = clock2alarm(which_clock);
struct restart_block *restart; struct restart_block *restart = &current->restart_block;
struct alarm alarm; struct alarm alarm;
ktime_t exp; ktime_t exp;
int ret = 0; int ret = 0;
if (flags & TIMER_ABSTIME)
rmtp = NULL;
restart->nanosleep.rmtp = rmtp;
if (!alarmtimer_get_rtcdev()) if (!alarmtimer_get_rtcdev())
return -ENOTSUPP; return -ENOTSUPP;
...@@ -808,32 +785,17 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, ...@@ -808,32 +785,17 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
exp = ktime_add(now, exp); exp = ktime_add(now, exp);
} }
if (alarmtimer_do_nsleep(&alarm, exp)) ret = alarmtimer_do_nsleep(&alarm, exp, type);
goto out; if (ret != -ERESTART_RESTARTBLOCK)
return ret;
if (freezing(current))
alarmtimer_freezerset(exp, type);
/* abs timers don't set remaining time or restart */ /* abs timers don't set remaining time or restart */
if (flags == TIMER_ABSTIME) { if (flags == TIMER_ABSTIME)
ret = -ERESTARTNOHAND; return -ERESTARTNOHAND;
goto out;
}
if (rmtp) {
ret = update_rmtp(exp, type, rmtp);
if (ret <= 0)
goto out;
}
restart = &current->restart_block;
restart->fn = alarm_timer_nsleep_restart; restart->fn = alarm_timer_nsleep_restart;
restart->nanosleep.clockid = type; restart->nanosleep.clockid = type;
restart->nanosleep.expires = exp; restart->nanosleep.expires = exp;
restart->nanosleep.rmtp = rmtp;
ret = -ERESTART_RESTARTBLOCK;
out:
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment