Hook compat_sys_nanosleep up to high res timer code
PATCH 1/1 Hook compat_sys_nanosleep up to high res timer code
Now we have high res timers on ppc64 I thought Id test them. It turns out compat_sys_nanosleep hasnt been converted to the hrtimer code and so is limited to HZ resolution.
The following patch makes compat_sys_nanosleep call hrtimer_nanosleep and uses compat_alloc_user_space to avoid setting KERNEL_DS.
---
kernel/compat.c +13 -46
@@ -40,62 +40,29 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; } -static long compat_nanosleep_restart (struct restart_block *restart) -{ -unsigned long expire = restart->arg0, now = jiffies; -struct compat_timespec __user *rmtp; - -/* Did it expire while we handled signals? */ -if (!time_after (expire, now)) -return 0 ; - - expire =schedule_timeout_interruptible (expire - now); -if (expire ==0 ) -return 0 ; - - rmtp = (struct compat_timespec __user *)restart->arg1; -if (rmtp) { -struct compat_timespec ct; -struct timespec t; - -jiffies_to_timespec (expire, &t); - ct.tv_sec = t.tv_sec; - ct.tv_nsec = t.tv_nsec; -if (copy_to_user (rmtp, &ct,sizeof (ct))) -return -EFAULT ; - } -/* The 'restart' block is already filled in */ -return -ERESTART_RESTARTBLOCK ; -} -asmlinkage long compat_sys_nanosleep (struct compat_timespec __user *rqtp, -struct compat_timespec __user *rmtp) +struct compat_timespec __user *rmtp) { -struct timespec t; -struct restart_block *restart; -unsigned long expire; +struct timespec tu; +struct timespec __user *rmtp64; +long ret; -if (get_compat_timespec (&t, rqtp)) +if (get_compat_timespec (&tu, rqtp))return -EFAULT ; -if ((t.tv_nsec >=1000000000L ) || (t.tv_nsec <0 ) || (t.tv_sec <0 )) +if (!timespec_valid (&tu))return -EINVAL ; - expire =timespec_to_jiffies (&t) + (t.tv_sec || t.tv_nsec); - expire =schedule_timeout_interruptible (expire); -if (expire ==0 ) -return 0 ; + rmtp64 =compat_alloc_user_space (sizeof (*rmtp64)); + ret =hrtimer_nanosleep (&tu, rmtp64,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); -if (rmtp) { -jiffies_to_timespec (expire, &t); -if (put_compat_timespec (&t, rmtp)) +if (ret) { +if (copy_from_user (&tu, rmtp64,sizeof (*rmtp64)) || +put_compat_timespec (&tu, rmtp))return -EFAULT ; } - restart = ¤t_thread_info ()->restart_block; - restart->fn = compat_nanosleep_restart; - restart->arg0 = jiffies + expire; - restart->arg1 = (unsigned long ) rmtp; -return -ERESTART_RESTARTBLOCK ; + +return ret; } static inline long get_compat_itimerval(struct itimerval *o,
Quoted 8 lines · Anton Blanchard
Now we have high res timers on ppc64 I thought Id test them. It turns out
compat_sys_nanosleephasnt been converted to the hrtimer code and so is limited to HZ resolution.The following patch makes
compat_sys_nanosleepcallhrtimer_nanosleepand usescompat_alloc_user_spaceto avoid settingKERNEL_DS.Signed-off-by Anton Blanchard <[email protected]>
The code looks correct, but I think it would be nicer to change hrtimer_nanosleep to take a kernel pointer and have all three callers (common_nsleep, sys_nanosleep and compat_sys_nanosleep) do the copy_to_user/put_compat_timespec in the caller.
This would also make it possible to get rid of set_fs() in compat_sys_clock_nanosleep().
Arnd <><
Hi Arnd,
Quoted 4 lines
The code looks correct, but I think it would be nicer to change
hrtimer_nanosleepto take a kernel pointer and have all three callers (common_nsleep,sys_nanosleepandcompat_sys_nanosleep) do the copy_to_user/put_compat_timespec in the caller.
Good idea, I had considered that but thought a larger cleanup might run afoul of the merge rules :)
Regardless, here it is. Id appreciate a once over since it does affect more code than the previous patch :)
Anton
--
Now we have high res timers on ppc64 I thought Id test them. It turns out compat_sys_nanosleep hasnt been converted to the hrtimer code and so is limited to HZ resolution.
The following patch pulls the copy_to_user out of hrtimer_nanosleep and into the callers (common_nsleep, sys_nanosleep and compat_sys_nanosleep) thus avoiding any set_fs(KERNEL_DS) or compat_alloc_userspace tricks.
---
include/linux/hrtimer.h +1 -1
@@ -300,7 +300,7 @@ hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);/* Precise sleep: */ extern long hrtimer_nanosleep (struct timespec *rqtp, -struct timespec __user *rmtp, +struct timespec *rmtp,const enum hrtimer_mode mode,const clockid_t clockid);extern long hrtimer_nanosleep_restart (struct restart_block *restart_block);
kernel/compat.c +10 -46
72 lines not on this page · raw message
kernel/hrtimer.c +15 -13
@@ -1286,8 +1286,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode modlong __sched hrtimer_nanosleep_restart (struct restart_block *restart) {struct hrtimer_sleeper t; -struct timespec __user *rmtp; -struct timespec tu; +struct timespec *rmtp;ktime_t time; restart->fn = do_no_restart_syscall;
@@ -1298,14 +1297,12 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)if (do_nanosleep (&t,HRTIMER_MODE_ABS ))return 0 ; - rmtp = (struct timespec __user *) restart->arg1; + rmtp = (struct timespec *)restart->arg1;if (rmtp) { time =ktime_sub (t.timer.expires, t.timer.base->get_time ());if (time.tv64 <=0 )return 0 ; - tu =ktime_to_timespec (time); -if (copy_to_user (rmtp, &tu,sizeof (tu))) -return -EFAULT ; + *rmtp =ktime_to_timespec (time); } restart->fn = hrtimer_nanosleep_restart;
@@ -1314,12 +1311,11 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)return -ERESTART_RESTARTBLOCK ; } -long hrtimer_nanosleep (struct timespec *rqtp,struct timespec __user *rmtp, +long hrtimer_nanosleep (struct timespec *rqtp,struct timespec *rmtp,const enum hrtimer_mode mode,const clockid_t clockid) {struct restart_block *restart;struct hrtimer_sleeper t; -struct timespec tu;ktime_t rem;hrtimer_init (&t.timer, clockid, mode);
@@ -1335,9 +1331,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, rem =ktime_sub (t.timer.expires, t.timer.base->get_time ());if (rem.tv64 <=0 )return 0 ; - tu =ktime_to_timespec (rem); -if (copy_to_user (rmtp, &tu,sizeof (tu))) -return -EFAULT ; + *rmtp =ktime_to_timespec (rem); } restart = ¤t_thread_info ()->restart_block;
@@ -1353,7 +1347,8 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,asmlinkage long sys_nanosleep (struct timespec __user *rqtp,struct timespec __user *rmtp) { -struct timespec tu; +struct timespec tu, rmt; +int ret;if (copy_from_user (&tu, rqtp,sizeof (tu)))return -EFAULT ;
@@ -1361,7 +1356,14 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)if (!timespec_valid (&tu))return -EINVAL ; -return hrtimer_nanosleep (&tu, rmtp,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); + ret =hrtimer_nanosleep (&tu, &rmt,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); + +if (ret) { +if (copy_to_user (rmtp, &rmt,sizeof (*rmtp))) +return -EFAULT ; + } + +return ret; }/*
kernel/posix-timers.c +11 -1
@@ -980,9 +980,19 @@ sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp)static int common_nsleep (const clockid_t which_clock,int flags,struct timespec *tsave,struct timespec __user *rmtp) { -return hrtimer_nanosleep (tsave, rmtp, flags &TIMER_ABSTIME ? +struct timespec rmt; +int ret; + + ret =hrtimer_nanosleep (tsave, &rmt, flags &TIMER_ABSTIME ?HRTIMER_MODE_ABS :HRTIMER_MODE_REL , which_clock); + +if (ret) { +if (copy_to_user (rmtp, &rmt,sizeof (*rmtp))) +return -EFAULT ; + } + +return ret; }asmlinkage long
Quoted 9 lines · Anton Blanchard
Hi Arnd,
Quoted 4 lines
The code looks correct, but I think it would be nicer to change
hrtimer_nanosleepto take a kernel pointer and have all three callers (common_nsleep,sys_nanosleepandcompat_sys_nanosleep) do the copy_to_user/put_compat_timespec in the caller.Good idea, I had considered that but thought a larger cleanup might run afoul of the merge rules :)
Looks good, except ....
kernel/compat.c int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user · line 41
Quoted 5 lines
kernel/compat.c +0
-0@@ -40,62 +40,26 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; }
Can you put this into a separate patch please ?
Quoted 14 lines
kernel/hrtimer.c +2
-1restart = ¤t_thread_info ()->restart_block;@@ -1353,7 +1347,8 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,asmlinkage long sys_nanosleep (struct timespec __user *rqtp,struct timespec __user *rmtp) { -struct timespec tu; +struct timespec tu, rmt; +int ret;if (copy_from_user (&tu, rqtp,sizeof (tu)))return -EFAULT ;
kernel/hrtimer.c sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp) · line 1361
Quoted 7 lines
kernel/hrtimer.c +3
-1@@ -1361,7 +1356,14 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)if (!timespec_valid (&tu))return -EINVAL ; -return hrtimer_nanosleep (&tu, rmtp,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); + ret =hrtimer_nanosleep (&tu, &rmt,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); + +if (ret) {
Can you check for rmtp as well ? rmtp is optional and can be NULL
Quoted 15 lines
kernel/hrtimer.c +5
-0+if (copy_to_user (rmtp, &rmt,sizeof (*rmtp))) +return -EFAULT ; + } + +return ret; }/* kernel/posix-timers.c +0
-0@@ -980,9 +980,19 @@ sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp)static int common_nsleep (const clockid_t which_clock,int flags,struct timespec *tsave,struct timespec __user *rmtp)
kernel/posix-timers.c sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp) · line 990
Quoted 10 lines
kernel/posix-timers.c +6
-1{ -return hrtimer_nanosleep (tsave, rmtp, flags &TIMER_ABSTIME ? +struct timespec rmt; +int ret; + + ret =hrtimer_nanosleep (tsave, &rmt, flags &TIMER_ABSTIME ?HRTIMER_MODE_ABS :HRTIMER_MODE_REL , which_clock); + +if (ret) {
Ditto.
kernel/posix-timers.c sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp) · line 996
Quoted 6 lines
kernel/posix-timers.c +5
-0+if (copy_to_user (rmtp, &rmt,sizeof (*rmtp))) +return -EFAULT ; + } + +return ret; }
Thanks,
tglx
PATCH 1/1 Rework hrtimer_nanosleep to make sys_compat_nanosleep easier
Hi Thomas,
Thanks for the review, updates to follow.
Anton
--
Pull the copy_to_user out of hrtimer_nanosleep and into the callers (common_nsleep, sys_nanosleep) in preparation for converting compat_sys_nanosleep to use hrtimers.
---
include/linux/hrtimer.h +1 -1
@@ -300,7 +300,7 @@ hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);/* Precise sleep: */ extern long hrtimer_nanosleep (struct timespec *rqtp, -struct timespec __user *rmtp, +struct timespec *rmtp,const enum hrtimer_mode mode,const clockid_t clockid);extern long hrtimer_nanosleep_restart (struct restart_block *restart_block);
kernel/hrtimer.c +15 -13
@@ -1286,8 +1286,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode modlong __sched hrtimer_nanosleep_restart (struct restart_block *restart) {struct hrtimer_sleeper t; -struct timespec __user *rmtp; -struct timespec tu; +struct timespec *rmtp;ktime_t time; restart->fn = do_no_restart_syscall;
@@ -1298,14 +1297,12 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)if (do_nanosleep (&t,HRTIMER_MODE_ABS ))return 0 ; - rmtp = (struct timespec __user *) restart->arg1; + rmtp = (struct timespec *)restart->arg1;if (rmtp) { time =ktime_sub (t.timer.expires, t.timer.base->get_time ());if (time.tv64 <=0 )return 0 ; - tu =ktime_to_timespec (time); -if (copy_to_user (rmtp, &tu,sizeof (tu))) -return -EFAULT ; + *rmtp =ktime_to_timespec (time); } restart->fn = hrtimer_nanosleep_restart;
@@ -1314,12 +1311,11 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)return -ERESTART_RESTARTBLOCK ; } -long hrtimer_nanosleep (struct timespec *rqtp,struct timespec __user *rmtp, +long hrtimer_nanosleep (struct timespec *rqtp,struct timespec *rmtp,const enum hrtimer_mode mode,const clockid_t clockid) {struct restart_block *restart;struct hrtimer_sleeper t; -struct timespec tu;ktime_t rem;hrtimer_init (&t.timer, clockid, mode);
@@ -1335,9 +1331,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, rem =ktime_sub (t.timer.expires, t.timer.base->get_time ());if (rem.tv64 <=0 )return 0 ; - tu =ktime_to_timespec (rem); -if (copy_to_user (rmtp, &tu,sizeof (tu))) -return -EFAULT ; + *rmtp =ktime_to_timespec (rem); } restart = ¤t_thread_info ()->restart_block;
@@ -1353,7 +1347,8 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,asmlinkage long sys_nanosleep (struct timespec __user *rqtp,struct timespec __user *rmtp) { -struct timespec tu; +struct timespec tu, rmt; +int ret;if (copy_from_user (&tu, rqtp,sizeof (tu)))return -EFAULT ;
@@ -1361,7 +1356,14 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)if (!timespec_valid (&tu))return -EINVAL ; -return hrtimer_nanosleep (&tu, rmtp,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); + ret =hrtimer_nanosleep (&tu, &rmt,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); + +if (ret && rmtp) { +if (copy_to_user (rmtp, &rmt,sizeof (*rmtp))) +return -EFAULT ; + } + +return ret; }/*
kernel/posix-timers.c +11 -1
@@ -980,9 +980,19 @@ sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp)static int common_nsleep (const clockid_t which_clock,int flags,struct timespec *tsave,struct timespec __user *rmtp) { -return hrtimer_nanosleep (tsave, rmtp, flags &TIMER_ABSTIME ? +struct timespec rmt; +int ret; + + ret =hrtimer_nanosleep (tsave, &rmt, flags &TIMER_ABSTIME ?HRTIMER_MODE_ABS :HRTIMER_MODE_REL , which_clock); + +if (ret && rmtp) { +if (copy_to_user (rmtp, &rmt,sizeof (*rmtp))) +return -EFAULT ; + } + +return ret; }asmlinkage long
PATCH 1/1 Hook compat_sys_nanosleep up to high res timer code
Now we have high res timers on ppc64 I thought Id test them. It turns out compat_sys_nanosleep hasnt been converted to the hrtimer code and so is limited to HZ resolution.
The follow patch converts compat_sys_nanosleep to use high res timers.
---
kernel/compat.c +10 -46
@@ -40,62 +40,26 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; } -static long compat_nanosleep_restart (struct restart_block *restart) -{ -unsigned long expire = restart->arg0, now = jiffies; -struct compat_timespec __user *rmtp; - -/* Did it expire while we handled signals? */ -if (!time_after (expire, now)) -return 0 ; - - expire =schedule_timeout_interruptible (expire - now); -if (expire ==0 ) -return 0 ; - - rmtp = (struct compat_timespec __user *)restart->arg1; -if (rmtp) { -struct compat_timespec ct; -struct timespec t; - -jiffies_to_timespec (expire, &t); - ct.tv_sec = t.tv_sec; - ct.tv_nsec = t.tv_nsec; -if (copy_to_user (rmtp, &ct,sizeof (ct))) -return -EFAULT ; - } -/* The 'restart' block is already filled in */ -return -ERESTART_RESTARTBLOCK ; -} -asmlinkage long compat_sys_nanosleep (struct compat_timespec __user *rqtp, -struct compat_timespec __user *rmtp) +struct compat_timespec __user *rmtp) { -struct timespec t; -struct restart_block *restart; -unsigned long expire; +struct timespec tu, rmt; +long ret; -if (get_compat_timespec (&t, rqtp)) +if (get_compat_timespec (&tu, rqtp))return -EFAULT ; -if ((t.tv_nsec >=1000000000L ) || (t.tv_nsec <0 ) || (t.tv_sec <0 )) +if (!timespec_valid (&tu))return -EINVAL ; - expire =timespec_to_jiffies (&t) + (t.tv_sec || t.tv_nsec); - expire =schedule_timeout_interruptible (expire); -if (expire ==0 ) -return 0 ; + ret =hrtimer_nanosleep (&tu, &rmt,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); -if (rmtp) { -jiffies_to_timespec (expire, &t); -if (put_compat_timespec (&t, rmtp)) +if (ret && rmtp) { +if (put_compat_timespec (&rmt, rmtp))return -EFAULT ; } - restart = ¤t_thread_info ()->restart_block; - restart->fn = compat_nanosleep_restart; - restart->arg0 = jiffies + expire; - restart->arg1 = (unsigned long ) rmtp; -return -ERESTART_RESTARTBLOCK ; + +return ret; } static inline long get_compat_itimerval(struct itimerval *o,
Re: [PATCH] Rework hrtimer_nanosleep to make sys_compat_nanosleep easier
In reply to Anton BlanchardQuoted 3 lines · Anton Blanchard
Pull the
copy_to_userout ofhrtimer_nanosleepand into the callers (common_nsleep,sys_nanosleep) in preparation for convertingcompat_sys_nanosleepto use hrtimers.
Looks good, except for two micro-optimization:
Quoted 1 line
Signed-off-by Anton Blanchard <[email protected]>
Review sys_nanosleep(struct timespec __user *rqtp, struct=
Quoted 1 line
(quoted diff) +0
-0@@ -1361,7 +1356,14 @@ sys_nanosleep(struct timespec __user *rqtp, struct=
timespec __user *rmtp)
Quoted 4 lines
(quoted diff) +0
-0=A0=A0=A0=A0=A0=A0=A0=A0if (!timespec_valid(&tu)) =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -EINVAL;=A0
-=A0=A0=A0=A0=A0=A0=A0return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_RE=
L, CLOCK_MONOTONIC);
Quoted 1 line
+=A0=A0=A0=A0=A0=A0=A0ret =3D hrtimer_nanosleep(&tu, &rmt, HRTIMER_MODE_R=
EL, CLOCK_MONOTONIC);
Quoted 3 lines
+
+=A0=A0=A0=A0=A0=A0=A0if (ret && rmtp) { +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0if (copy_to_user(rmtp, &rmt=
, sizeof(*rmtp)))
Quoted 1 line
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0ret=
urn -EFAULT;
Quoted 5 lines
+=A0=A0=A0=A0=A0=A0=A0}
+
+=A0=A0=A0=A0=A0=A0=A0return ret;
=A0}
=A0
If it's common to call sys_nanosleep with a NULL rmtp argument, we could sa= ve a
few cycles using=20
return hrtimer_nanosleep(&tu, rmtp ? &rmp : NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
kernel/posix-timers.c sys_clock_getres(const clockid_t which_clock, struct=
Quoted 5 lines
kernel/posix-timers.c +0
-0@@ -980,9 +980,19 @@ sys_clock_getres(const clockid_t which_clock, struct=
timespec __user *tp)
Quoted 2 lines
kernel/posix-timers.c +0
-0=A0static int common_nsleep(const clockid_t which_clock, int flags,=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =
struct timespec *tsave, struct timespec __user *rmtp)
Quoted 2 lines
=A0{
-=A0=A0=A0=A0=A0=A0=A0return hrtimer_nanosleep(tsave, rmtp, flags & TIMER=
_ABSTIME ?
Quoted 4 lines
+=A0=A0=A0=A0=A0=A0=A0struct timespec rmt; +=A0=A0=A0=A0=A0=A0=A0int ret;+
+=A0=A0=A0=A0=A0=A0=A0ret =3D hrtimer_nanosleep(tsave, &rmt, flags & TIME=
R_ABSTIME ?
Quoted 1 line
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=
=A0=A0=A0=A0=A0=A0=A0=A0 HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
Quoted 1 line
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=
=A0=A0=A0=A0=A0=A0=A0=A0 which_clock);
Quoted 3 lines
+
+=A0=A0=A0=A0=A0=A0=A0if (ret && rmtp) { +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0if (copy_to_user(rmtp, &rmt=
, sizeof(*rmtp)))
Quoted 1 line
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0ret=
urn -EFAULT;
Quoted 4 lines
+=A0=A0=A0=A0=A0=A0=A0}
+
+=A0=A0=A0=A0=A0=A0=A0return ret;
=A0}
I think it would be better here to propagate the move to a kernel *rmtp down to sys_clock_nanosleep so we get the same optimization in compat_sys_clock_nanosleep. That should probably also be a separate patch. I can do one if you don't do it first.
Arnd <><
PATCH 1/1 Rework hrtimer_nanosleep to make sys_compat_nanosleep easier
Hi,
Quoted 5 lines
If it's common to call
sys_nanosleepwith a NULL rmtp argument, we could save a few cycles usingreturn hrtimer_nanosleep(&tu, rmtp ? &rmp : NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
Good idea, patches updated.
Quoted 4 lines
I think it would be better here to propagate the move to a kernel *rmtp down to
sys_clock_nanosleepso we get the same optimization incompat_sys_clock_nanosleep. That should probably also be a separate patch. I can do one if you don't do it first.
I can get to this later in the week, if you feel the urge in the meantime go for it :)
Anton
--
Pull the copy_to_user out of hrtimer_nanosleep and into the callers (common_nsleep, sys_nanosleep) in preparation for converting compat_sys_nanosleep to use hrtimers.
---
include/linux/hrtimer.h +1 -1
@@ -300,7 +300,7 @@ hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);/* Precise sleep: */ extern long hrtimer_nanosleep (struct timespec *rqtp, -struct timespec __user *rmtp, +struct timespec *rmtp,const enum hrtimer_mode mode,const clockid_t clockid);extern long hrtimer_nanosleep_restart (struct restart_block *restart_block);
kernel/hrtimer.c +16 -13
@@ -1286,8 +1286,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode modlong __sched hrtimer_nanosleep_restart (struct restart_block *restart) {struct hrtimer_sleeper t; -struct timespec __user *rmtp; -struct timespec tu; +struct timespec *rmtp;ktime_t time; restart->fn = do_no_restart_syscall;
@@ -1298,14 +1297,12 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)if (do_nanosleep (&t,HRTIMER_MODE_ABS ))return 0 ; - rmtp = (struct timespec __user *) restart->arg1; + rmtp = (struct timespec *)restart->arg1;if (rmtp) { time =ktime_sub (t.timer.expires, t.timer.base->get_time ());if (time.tv64 <=0 )return 0 ; - tu =ktime_to_timespec (time); -if (copy_to_user (rmtp, &tu,sizeof (tu))) -return -EFAULT ; + *rmtp =ktime_to_timespec (time); } restart->fn = hrtimer_nanosleep_restart;
@@ -1314,12 +1311,11 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)return -ERESTART_RESTARTBLOCK ; } -long hrtimer_nanosleep (struct timespec *rqtp,struct timespec __user *rmtp, +long hrtimer_nanosleep (struct timespec *rqtp,struct timespec *rmtp,const enum hrtimer_mode mode,const clockid_t clockid) {struct restart_block *restart;struct hrtimer_sleeper t; -struct timespec tu;ktime_t rem;hrtimer_init (&t.timer, clockid, mode);
@@ -1335,9 +1331,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, rem =ktime_sub (t.timer.expires, t.timer.base->get_time ());if (rem.tv64 <=0 )return 0 ; - tu =ktime_to_timespec (rem); -if (copy_to_user (rmtp, &tu,sizeof (tu))) -return -EFAULT ; + *rmtp =ktime_to_timespec (rem); } restart = ¤t_thread_info ()->restart_block;
@@ -1353,7 +1347,8 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,asmlinkage long sys_nanosleep (struct timespec __user *rqtp,struct timespec __user *rmtp) { -struct timespec tu; +struct timespec tu, rmt; +int ret;if (copy_from_user (&tu, rqtp,sizeof (tu)))return -EFAULT ;
@@ -1361,7 +1356,15 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)if (!timespec_valid (&tu))return -EINVAL ; -return hrtimer_nanosleep (&tu, rmtp,HRTIMER_MODE_REL ,CLOCK_MONOTONIC ); + ret =hrtimer_nanosleep (&tu, rmtp ? &rmt :NULL ,HRTIMER_MODE_REL , +CLOCK_MONOTONIC ); + +if (ret && rmtp) { +if (copy_to_user (rmtp, &rmt,sizeof (*rmtp))) +return -EFAULT ; + } + +return ret; }/*
kernel/posix-timers.c +14 -3
@@ -980,9 +980,20 @@ sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp)static int common_nsleep (const clockid_t which_clock,int flags,struct timespec *tsave,struct timespec __user *rmtp) { -return hrtimer_nanosleep (tsave, rmtp, flags &TIMER_ABSTIME ? -HRTIMER_MODE_ABS :HRTIMER_MODE_REL , - which_clock); +struct timespec rmt; +int ret; + + ret =hrtimer_nanosleep (tsave, rmtp ? &rmt :NULL , + flags &TIMER_ABSTIME ? +HRTIMER_MODE_ABS :HRTIMER_MODE_REL , + which_clock); + +if (ret && rmtp) { +if (copy_to_user (rmtp, &rmt,sizeof (*rmtp))) +return -EFAULT ; + } + +return ret; }asmlinkage long
PATCH 1/1 Hook compat_sys_nanosleep up to high res timer code
In reply to Arnd BergmannNow we have high res timers on ppc64 I thought Id test them. It turns out compat_sys_nanosleep hasnt been converted to the hrtimer code and so is limited to HZ resolution.
The follow patch converts compat_sys_nanosleep to use high res timers.
---
kernel/compat.c +11 -46
@@ -40,62 +40,27 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; } -static long compat_nanosleep_restart (struct restart_block *restart) -{ -unsigned long expire = restart->arg0, now = jiffies; -struct compat_timespec __user *rmtp; - -/* Did it expire while we handled signals? */ -if (!time_after (expire, now)) -return 0 ; - - expire =schedule_timeout_interruptible (expire - now); -if (expire ==0 ) -return 0 ; - - rmtp = (struct compat_timespec __user *)restart->arg1; -if (rmtp) { -struct compat_timespec ct; -struct timespec t; - -jiffies_to_timespec (expire, &t); - ct.tv_sec = t.tv_sec; - ct.tv_nsec = t.tv_nsec; -if (copy_to_user (rmtp, &ct,sizeof (ct))) -return -EFAULT ; - } -/* The 'restart' block is already filled in */ -return -ERESTART_RESTARTBLOCK ; -} -asmlinkage long compat_sys_nanosleep (struct compat_timespec __user *rqtp, -struct compat_timespec __user *rmtp) +struct compat_timespec __user *rmtp) { -struct timespec t; -struct restart_block *restart; -unsigned long expire; +struct timespec tu, rmt; +long ret; -if (get_compat_timespec (&t, rqtp)) +if (get_compat_timespec (&tu, rqtp))return -EFAULT ; -if ((t.tv_nsec >=1000000000L ) || (t.tv_nsec <0 ) || (t.tv_sec <0 )) +if (!timespec_valid (&tu))return -EINVAL ; - expire =timespec_to_jiffies (&t) + (t.tv_sec || t.tv_nsec); - expire =schedule_timeout_interruptible (expire); -if (expire ==0 ) -return 0 ; + ret =hrtimer_nanosleep (&tu, rmtp ? &rmt :NULL ,HRTIMER_MODE_REL , +CLOCK_MONOTONIC ); -if (rmtp) { -jiffies_to_timespec (expire, &t); -if (put_compat_timespec (&t, rmtp)) +if (ret && rmtp) { +if (put_compat_timespec (&rmt, rmtp))return -EFAULT ; } - restart = ¤t_thread_info ()->restart_block; - restart->fn = compat_nanosleep_restart; - restart->arg0 = jiffies + expire; - restart->arg1 = (unsigned long ) rmtp; -return -ERESTART_RESTARTBLOCK ; + +return ret; } static inline long get_compat_itimerval(struct itimerval *o,