Commit 1711ef38 authored by Toyo Abe's avatar Toyo Abe Committed by Linus Torvalds

[PATCH] posix-timers: Fix clock_nanosleep() doesn't return the remaining time in compatibility mode

The clock_nanosleep() function does not return the time remaining when the
sleep is interrupted by a signal.

This patch creates a new call out, compat_clock_nanosleep_restart(), which
handles returning the remaining time after a sleep is interrupted.  This
patch revives clock_nanosleep_restart().  It is now accessed via the new
call out.  The compat_clock_nanosleep_restart() is used for compatibility
access.

Since this is implemented in compatibility mode the normal path is
virtually unaffected - no real performance impact.
Signed-off-by: default avatarToyo Abe <toyoa@mvista.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9c4751fd
...@@ -138,6 +138,7 @@ extern long hrtimer_nanosleep(struct timespec *rqtp, ...@@ -138,6 +138,7 @@ extern long hrtimer_nanosleep(struct timespec *rqtp,
struct timespec __user *rmtp, struct timespec __user *rmtp,
const enum hrtimer_mode mode, const enum hrtimer_mode mode,
const clockid_t clockid); const clockid_t clockid);
extern long hrtimer_nanosleep_restart(struct restart_block *restart_block);
extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
struct task_struct *tsk); struct task_struct *tsk);
......
...@@ -72,6 +72,7 @@ struct k_clock { ...@@ -72,6 +72,7 @@ struct k_clock {
int (*timer_create) (struct k_itimer *timer); int (*timer_create) (struct k_itimer *timer);
int (*nsleep) (const clockid_t which_clock, int flags, int (*nsleep) (const clockid_t which_clock, int flags,
struct timespec *, struct timespec __user *); struct timespec *, struct timespec __user *);
long (*nsleep_restart) (struct restart_block *restart_block);
int (*timer_set) (struct k_itimer * timr, int flags, int (*timer_set) (struct k_itimer * timr, int flags,
struct itimerspec * new_setting, struct itimerspec * new_setting,
struct itimerspec * old_setting); struct itimerspec * old_setting);
...@@ -97,6 +98,7 @@ int posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *ts); ...@@ -97,6 +98,7 @@ int posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *ts);
int posix_cpu_timer_create(struct k_itimer *timer); int posix_cpu_timer_create(struct k_itimer *timer);
int posix_cpu_nsleep(const clockid_t which_clock, int flags, int posix_cpu_nsleep(const clockid_t which_clock, int flags,
struct timespec *rqtp, struct timespec __user *rmtp); struct timespec *rqtp, struct timespec __user *rmtp);
long posix_cpu_nsleep_restart(struct restart_block *restart_block);
int posix_cpu_timer_set(struct k_itimer *timer, int flags, int posix_cpu_timer_set(struct k_itimer *timer, int flags,
struct itimerspec *new, struct itimerspec *old); struct itimerspec *new, struct itimerspec *old);
int posix_cpu_timer_del(struct k_itimer *timer); int posix_cpu_timer_del(struct k_itimer *timer);
...@@ -111,4 +113,6 @@ void posix_cpu_timers_exit_group(struct task_struct *task); ...@@ -111,4 +113,6 @@ void posix_cpu_timers_exit_group(struct task_struct *task);
void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,
cputime_t *newval, cputime_t *oldval); cputime_t *newval, cputime_t *oldval);
long clock_nanosleep_restart(struct restart_block *restart_block);
#endif #endif
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/security.h> #include <linux/security.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/migrate.h> #include <linux/migrate.h>
#include <linux/posix-timers.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -601,6 +602,30 @@ long compat_sys_clock_getres(clockid_t which_clock, ...@@ -601,6 +602,30 @@ long compat_sys_clock_getres(clockid_t which_clock,
return err; return err;
} }
static long compat_clock_nanosleep_restart(struct restart_block *restart)
{
long err;
mm_segment_t oldfs;
struct timespec tu;
struct compat_timespec *rmtp = (struct compat_timespec *)(restart->arg1);
restart->arg1 = (unsigned long) &tu;
oldfs = get_fs();
set_fs(KERNEL_DS);
err = clock_nanosleep_restart(restart);
set_fs(oldfs);
if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
put_compat_timespec(&tu, rmtp))
return -EFAULT;
if (err == -ERESTART_RESTARTBLOCK) {
restart->fn = compat_clock_nanosleep_restart;
restart->arg1 = (unsigned long) rmtp;
}
return err;
}
long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
struct compat_timespec __user *rqtp, struct compat_timespec __user *rqtp,
struct compat_timespec __user *rmtp) struct compat_timespec __user *rmtp)
...@@ -608,6 +633,7 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, ...@@ -608,6 +633,7 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
long err; long err;
mm_segment_t oldfs; mm_segment_t oldfs;
struct timespec in, out; struct timespec in, out;
struct restart_block *restart;
if (get_compat_timespec(&in, rqtp)) if (get_compat_timespec(&in, rqtp))
return -EFAULT; return -EFAULT;
...@@ -618,9 +644,16 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, ...@@ -618,9 +644,16 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
(struct timespec __user *) &in, (struct timespec __user *) &in,
(struct timespec __user *) &out); (struct timespec __user *) &out);
set_fs(oldfs); set_fs(oldfs);
if ((err == -ERESTART_RESTARTBLOCK) && rmtp && if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
put_compat_timespec(&out, rmtp)) put_compat_timespec(&out, rmtp))
return -EFAULT; return -EFAULT;
if (err == -ERESTART_RESTARTBLOCK) {
restart = &current_thread_info()->restart_block;
restart->fn = compat_clock_nanosleep_restart;
restart->arg1 = (unsigned long) rmtp;
}
return err; return err;
} }
......
...@@ -693,7 +693,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod ...@@ -693,7 +693,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
return t->task == NULL; return t->task == NULL;
} }
static long __sched nanosleep_restart(struct restart_block *restart) long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
{ {
struct hrtimer_sleeper t; struct hrtimer_sleeper t;
struct timespec __user *rmtp; struct timespec __user *rmtp;
...@@ -702,13 +702,13 @@ static long __sched nanosleep_restart(struct restart_block *restart) ...@@ -702,13 +702,13 @@ static long __sched nanosleep_restart(struct restart_block *restart)
restart->fn = do_no_restart_syscall; restart->fn = do_no_restart_syscall;
hrtimer_init(&t.timer, restart->arg3, HRTIMER_ABS); hrtimer_init(&t.timer, restart->arg0, HRTIMER_ABS);
t.timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0; t.timer.expires.tv64 = ((u64)restart->arg3 << 32) | (u64) restart->arg2;
if (do_nanosleep(&t, HRTIMER_ABS)) if (do_nanosleep(&t, HRTIMER_ABS))
return 0; return 0;
rmtp = (struct timespec __user *) restart->arg2; rmtp = (struct timespec __user *) restart->arg1;
if (rmtp) { if (rmtp) {
time = ktime_sub(t.timer.expires, t.timer.base->get_time()); time = ktime_sub(t.timer.expires, t.timer.base->get_time());
if (time.tv64 <= 0) if (time.tv64 <= 0)
...@@ -718,7 +718,7 @@ static long __sched nanosleep_restart(struct restart_block *restart) ...@@ -718,7 +718,7 @@ static long __sched nanosleep_restart(struct restart_block *restart)
return -EFAULT; return -EFAULT;
} }
restart->fn = nanosleep_restart; restart->fn = hrtimer_nanosleep_restart;
/* The other values in restart are already filled in */ /* The other values in restart are already filled in */
return -ERESTART_RESTARTBLOCK; return -ERESTART_RESTARTBLOCK;
...@@ -751,11 +751,11 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, ...@@ -751,11 +751,11 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
} }
restart = &current_thread_info()->restart_block; restart = &current_thread_info()->restart_block;
restart->fn = nanosleep_restart; restart->fn = hrtimer_nanosleep_restart;
restart->arg0 = t.timer.expires.tv64 & 0xFFFFFFFF; restart->arg0 = (unsigned long) t.timer.base->index;
restart->arg1 = t.timer.expires.tv64 >> 32; restart->arg1 = (unsigned long) rmtp;
restart->arg2 = (unsigned long) rmtp; restart->arg2 = t.timer.expires.tv64 & 0xFFFFFFFF;
restart->arg3 = (unsigned long) t.timer.base->index; restart->arg3 = t.timer.expires.tv64 >> 32;
return -ERESTART_RESTARTBLOCK; return -ERESTART_RESTARTBLOCK;
} }
......
...@@ -1393,8 +1393,6 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx, ...@@ -1393,8 +1393,6 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
} }
} }
static long posix_cpu_clock_nanosleep_restart(struct restart_block *);
int posix_cpu_nsleep(const clockid_t which_clock, int flags, int posix_cpu_nsleep(const clockid_t which_clock, int flags,
struct timespec *rqtp, struct timespec __user *rmtp) struct timespec *rqtp, struct timespec __user *rmtp)
{ {
...@@ -1471,7 +1469,7 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags, ...@@ -1471,7 +1469,7 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags,
copy_to_user(rmtp, &it.it_value, sizeof *rmtp)) copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
return -EFAULT; return -EFAULT;
restart_block->fn = posix_cpu_clock_nanosleep_restart; restart_block->fn = posix_cpu_nsleep_restart;
/* Caller already set restart_block->arg1 */ /* Caller already set restart_block->arg1 */
restart_block->arg0 = which_clock; restart_block->arg0 = which_clock;
restart_block->arg1 = (unsigned long) rmtp; restart_block->arg1 = (unsigned long) rmtp;
...@@ -1484,8 +1482,7 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags, ...@@ -1484,8 +1482,7 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags,
return error; return error;
} }
static long long posix_cpu_nsleep_restart(struct restart_block *restart_block)
posix_cpu_clock_nanosleep_restart(struct restart_block *restart_block)
{ {
clockid_t which_clock = restart_block->arg0; clockid_t which_clock = restart_block->arg0;
struct timespec __user *rmtp; struct timespec __user *rmtp;
...@@ -1524,6 +1521,10 @@ static int process_cpu_nsleep(const clockid_t which_clock, int flags, ...@@ -1524,6 +1521,10 @@ static int process_cpu_nsleep(const clockid_t which_clock, int flags,
{ {
return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp); return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp);
} }
static long process_cpu_nsleep_restart(struct restart_block *restart_block)
{
return -EINVAL;
}
static int thread_cpu_clock_getres(const clockid_t which_clock, static int thread_cpu_clock_getres(const clockid_t which_clock,
struct timespec *tp) struct timespec *tp)
{ {
...@@ -1544,6 +1545,10 @@ static int thread_cpu_nsleep(const clockid_t which_clock, int flags, ...@@ -1544,6 +1545,10 @@ static int thread_cpu_nsleep(const clockid_t which_clock, int flags,
{ {
return -EINVAL; return -EINVAL;
} }
static long thread_cpu_nsleep_restart(struct restart_block *restart_block)
{
return -EINVAL;
}
static __init int init_posix_cpu_timers(void) static __init int init_posix_cpu_timers(void)
{ {
...@@ -1553,6 +1558,7 @@ static __init int init_posix_cpu_timers(void) ...@@ -1553,6 +1558,7 @@ static __init int init_posix_cpu_timers(void)
.clock_set = do_posix_clock_nosettime, .clock_set = do_posix_clock_nosettime,
.timer_create = process_cpu_timer_create, .timer_create = process_cpu_timer_create,
.nsleep = process_cpu_nsleep, .nsleep = process_cpu_nsleep,
.nsleep_restart = process_cpu_nsleep_restart,
}; };
struct k_clock thread = { struct k_clock thread = {
.clock_getres = thread_cpu_clock_getres, .clock_getres = thread_cpu_clock_getres,
...@@ -1560,6 +1566,7 @@ static __init int init_posix_cpu_timers(void) ...@@ -1560,6 +1566,7 @@ static __init int init_posix_cpu_timers(void)
.clock_set = do_posix_clock_nosettime, .clock_set = do_posix_clock_nosettime,
.timer_create = thread_cpu_timer_create, .timer_create = thread_cpu_timer_create,
.nsleep = thread_cpu_nsleep, .nsleep = thread_cpu_nsleep,
.nsleep_restart = thread_cpu_nsleep_restart,
}; };
register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process); register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process);
......
...@@ -973,3 +973,24 @@ sys_clock_nanosleep(const clockid_t which_clock, int flags, ...@@ -973,3 +973,24 @@ sys_clock_nanosleep(const clockid_t which_clock, int flags,
return CLOCK_DISPATCH(which_clock, nsleep, return CLOCK_DISPATCH(which_clock, nsleep,
(which_clock, flags, &t, rmtp)); (which_clock, flags, &t, rmtp));
} }
/*
* nanosleep_restart for monotonic and realtime clocks
*/
static int common_nsleep_restart(struct restart_block *restart_block)
{
return hrtimer_nanosleep_restart(restart_block);
}
/*
* This will restart clock_nanosleep. This is required only by
* compat_clock_nanosleep_restart for now.
*/
long
clock_nanosleep_restart(struct restart_block *restart_block)
{
clockid_t which_clock = restart_block->arg0;
return CLOCK_DISPATCH(which_clock, nsleep_restart,
(restart_block));
}
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