Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ extern long hrtimer_nanosleep(struct timespec *rqtp,
			      struct timespec __user *rmtp,
			      const enum hrtimer_mode mode,
			      const clockid_t clockid);
extern long hrtimer_nanosleep_restart(struct restart_block *restart_block);

extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
				 struct task_struct *tsk);
+4 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ struct k_clock {
	int (*timer_create) (struct k_itimer *timer);
	int (*nsleep) (const clockid_t which_clock, int flags,
		       struct timespec *, struct timespec __user *);
	long (*nsleep_restart) (struct restart_block *restart_block);
	int (*timer_set) (struct k_itimer * timr, int flags,
			  struct itimerspec * new_setting,
			  struct itimerspec * old_setting);
@@ -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_nsleep(const clockid_t which_clock, int flags,
		     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,
			struct itimerspec *new, struct itimerspec *old);
int posix_cpu_timer_del(struct k_itimer *timer);
@@ -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,
			   cputime_t *newval, cputime_t *oldval);

long clock_nanosleep_restart(struct restart_block *restart_block);

#endif
+33 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/security.h>
#include <linux/timex.h>
#include <linux/migrate.h>
#include <linux/posix-timers.h>

#include <asm/uaccess.h>

@@ -601,6 +602,30 @@ long compat_sys_clock_getres(clockid_t which_clock,
	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,
			    struct compat_timespec __user *rqtp,
			    struct compat_timespec __user *rmtp)
@@ -608,6 +633,7 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
	long err;
	mm_segment_t oldfs;
	struct timespec in, out; 
	struct restart_block *restart;

	if (get_compat_timespec(&in, rqtp)) 
		return -EFAULT;
@@ -618,9 +644,16 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
				  (struct timespec __user *) &in,
				  (struct timespec __user *) &out);
	set_fs(oldfs);

	if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
	    put_compat_timespec(&out, rmtp))
		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;	
} 

+10 −10
Original line number Diff line number Diff line
@@ -693,7 +693,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
	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 timespec __user *rmtp;
@@ -702,13 +702,13 @@ static long __sched nanosleep_restart(struct restart_block *restart)

	restart->fn = do_no_restart_syscall;

	hrtimer_init(&t.timer, restart->arg3, HRTIMER_ABS);
	t.timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0;
	hrtimer_init(&t.timer, restart->arg0, HRTIMER_ABS);
	t.timer.expires.tv64 = ((u64)restart->arg3 << 32) | (u64) restart->arg2;

	if (do_nanosleep(&t, HRTIMER_ABS))
		return 0;

	rmtp = (struct timespec __user *) restart->arg2;
	rmtp = (struct timespec __user *) restart->arg1;
	if (rmtp) {
		time = ktime_sub(t.timer.expires, t.timer.base->get_time());
		if (time.tv64 <= 0)
@@ -718,7 +718,7 @@ static long __sched nanosleep_restart(struct restart_block *restart)
			return -EFAULT;
	}

	restart->fn = nanosleep_restart;
	restart->fn = hrtimer_nanosleep_restart;

	/* The other values in restart are already filled in */
	return -ERESTART_RESTARTBLOCK;
@@ -751,11 +751,11 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
	}

	restart = &current_thread_info()->restart_block;
	restart->fn = nanosleep_restart;
	restart->arg0 = t.timer.expires.tv64 & 0xFFFFFFFF;
	restart->arg1 = t.timer.expires.tv64 >> 32;
	restart->arg2 = (unsigned long) rmtp;
	restart->arg3 = (unsigned long) t.timer.base->index;
	restart->fn = hrtimer_nanosleep_restart;
	restart->arg0 = (unsigned long) t.timer.base->index;
	restart->arg1 = (unsigned long) rmtp;
	restart->arg2 = t.timer.expires.tv64 & 0xFFFFFFFF;
	restart->arg3 = t.timer.expires.tv64 >> 32;

	return -ERESTART_RESTARTBLOCK;
}
+12 −5
Original line number Diff line number Diff line
@@ -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,
		     struct timespec *rqtp, struct timespec __user *rmtp)
{
@@ -1471,7 +1469,7 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags,
		    copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
			return -EFAULT;

		restart_block->fn = posix_cpu_clock_nanosleep_restart;
		restart_block->fn = posix_cpu_nsleep_restart;
		/* Caller already set restart_block->arg1 */
		restart_block->arg0 = which_clock;
		restart_block->arg1 = (unsigned long) rmtp;
@@ -1484,8 +1482,7 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags,
	return error;
}

static long
posix_cpu_clock_nanosleep_restart(struct restart_block *restart_block)
long posix_cpu_nsleep_restart(struct restart_block *restart_block)
{
	clockid_t which_clock = restart_block->arg0;
	struct timespec __user *rmtp;
@@ -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);
}
static long process_cpu_nsleep_restart(struct restart_block *restart_block)
{
	return -EINVAL;
}
static int thread_cpu_clock_getres(const clockid_t which_clock,
				   struct timespec *tp)
{
@@ -1544,6 +1545,10 @@ static int thread_cpu_nsleep(const clockid_t which_clock, int flags,
{
	return -EINVAL;
}
static long thread_cpu_nsleep_restart(struct restart_block *restart_block)
{
	return -EINVAL;
}

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,
		.timer_create = process_cpu_timer_create,
		.nsleep = process_cpu_nsleep,
		.nsleep_restart = process_cpu_nsleep_restart,
	};
	struct k_clock thread = {
		.clock_getres = thread_cpu_clock_getres,
@@ -1560,6 +1566,7 @@ static __init int init_posix_cpu_timers(void)
		.clock_set = do_posix_clock_nosettime,
		.timer_create = thread_cpu_timer_create,
		.nsleep = thread_cpu_nsleep,
		.nsleep_restart = thread_cpu_nsleep_restart,
	};

	register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process);
Loading