|
@@ -819,31 +819,21 @@ int common_timer_set(struct k_itimer *timr, int flags,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* Set a POSIX.1b interval timer */
|
|
|
-SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
|
|
|
- const struct itimerspec __user *, new_setting,
|
|
|
- struct itimerspec __user *, old_setting)
|
|
|
+static int do_timer_settime(timer_t timer_id, int flags,
|
|
|
+ struct itimerspec64 *new_spec64,
|
|
|
+ struct itimerspec64 *old_spec64)
|
|
|
{
|
|
|
- struct itimerspec64 new_spec64, old_spec64;
|
|
|
- struct itimerspec64 *rtn = old_setting ? &old_spec64 : NULL;
|
|
|
- struct itimerspec new_spec, old_spec;
|
|
|
+ const struct k_clock *kc;
|
|
|
struct k_itimer *timr;
|
|
|
unsigned long flag;
|
|
|
- const struct k_clock *kc;
|
|
|
int error = 0;
|
|
|
|
|
|
- if (!new_setting)
|
|
|
+ if (!timespec64_valid(&new_spec64->it_interval) ||
|
|
|
+ !timespec64_valid(&new_spec64->it_value))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (copy_from_user(&new_spec, new_setting, sizeof (new_spec)))
|
|
|
- return -EFAULT;
|
|
|
- new_spec64 = itimerspec_to_itimerspec64(&new_spec);
|
|
|
-
|
|
|
- if (!timespec64_valid(&new_spec64.it_interval) ||
|
|
|
- !timespec64_valid(&new_spec64.it_value))
|
|
|
- return -EINVAL;
|
|
|
- if (rtn)
|
|
|
- memset(rtn, 0, sizeof(*rtn));
|
|
|
+ if (old_spec64)
|
|
|
+ memset(old_spec64, 0, sizeof(*old_spec64));
|
|
|
retry:
|
|
|
timr = lock_timer(timer_id, &flag);
|
|
|
if (!timr)
|
|
@@ -853,22 +843,71 @@ retry:
|
|
|
if (WARN_ON_ONCE(!kc || !kc->timer_set))
|
|
|
error = -EINVAL;
|
|
|
else
|
|
|
- error = kc->timer_set(timr, flags, &new_spec64, rtn);
|
|
|
+ error = kc->timer_set(timr, flags, new_spec64, old_spec64);
|
|
|
|
|
|
unlock_timer(timr, flag);
|
|
|
if (error == TIMER_RETRY) {
|
|
|
- rtn = NULL; // We already got the old time...
|
|
|
+ old_spec64 = NULL; // We already got the old time...
|
|
|
goto retry;
|
|
|
}
|
|
|
|
|
|
- old_spec = itimerspec64_to_itimerspec(&old_spec64);
|
|
|
- if (old_setting && !error &&
|
|
|
- copy_to_user(old_setting, &old_spec, sizeof (old_spec)))
|
|
|
- error = -EFAULT;
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
+/* Set a POSIX.1b interval timer */
|
|
|
+SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
|
|
|
+ const struct itimerspec __user *, new_setting,
|
|
|
+ struct itimerspec __user *, old_setting)
|
|
|
+{
|
|
|
+ struct itimerspec64 new_spec64, old_spec64;
|
|
|
+ struct itimerspec64 *rtn = old_setting ? &old_spec64 : NULL;
|
|
|
+ struct itimerspec new_spec;
|
|
|
+ int error = 0;
|
|
|
+
|
|
|
+ if (!new_setting)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
+ if (copy_from_user(&new_spec, new_setting, sizeof (new_spec)))
|
|
|
+ return -EFAULT;
|
|
|
+ new_spec64 = itimerspec_to_itimerspec64(&new_spec);
|
|
|
+
|
|
|
+ error = do_timer_settime(timer_id, flags, &new_spec64, rtn);
|
|
|
+ if (!error && old_setting) {
|
|
|
+ struct itimerspec old_spec;
|
|
|
+ old_spec = itimerspec64_to_itimerspec(&old_spec64);
|
|
|
+ if (copy_to_user(old_setting, &old_spec, sizeof (old_spec)))
|
|
|
+ error = -EFAULT;
|
|
|
+ }
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_COMPAT
|
|
|
+COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
|
|
|
+ struct compat_itimerspec __user *, new,
|
|
|
+ struct compat_itimerspec __user *, old)
|
|
|
+{
|
|
|
+ struct itimerspec64 new_spec64, old_spec64;
|
|
|
+ struct itimerspec64 *rtn = old ? &old_spec64 : NULL;
|
|
|
+ struct itimerspec new_spec;
|
|
|
+ int error = 0;
|
|
|
+
|
|
|
+ if (!new)
|
|
|
+ return -EINVAL;
|
|
|
+ if (get_compat_itimerspec(&new_spec, new))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ new_spec64 = itimerspec_to_itimerspec64(&new_spec);
|
|
|
+ error = do_timer_settime(timer_id, flags, &new_spec64, rtn);
|
|
|
+ if (!error && old) {
|
|
|
+ struct itimerspec old_spec;
|
|
|
+ old_spec = itimerspec64_to_itimerspec(&old_spec64);
|
|
|
+ if (put_compat_itimerspec(old, &old_spec))
|
|
|
+ error = -EFAULT;
|
|
|
+ }
|
|
|
+ return error;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
int common_timer_del(struct k_itimer *timer)
|
|
|
{
|
|
|
const struct k_clock *kc = timer->kclock;
|