forked from Minki/linux
sparc64: add custom adjtimex/clock_adjtime functions
sparc64 is the only architecture on Linux that has a 'timeval' definition with a 32-bit tv_usec but a 64-bit tv_sec. This causes problems for sparc32 compat mode when we convert it to use the new __kernel_timex type that has the same layout as all other 64-bit architectures. To avoid adding sparc64 specific code into the generic adjtimex implementation, this adds a wrapper in the sparc64 system call handling that converts the sparc64 'timex' into the new '__kernel_timex'. At this point, the two structures are defined to be identical, but that will change in the next step once we convert sparc32. Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
parent
50b93f30f6
commit
1a596398a3
@ -28,8 +28,9 @@
|
||||
#include <linux/random.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/context_tracking.h>
|
||||
|
||||
#include <linux/timex.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/utrap.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
@ -544,6 +545,62 @@ out_unlock:
|
||||
return err;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE1(sparc_adjtimex, struct timex __user *, txc_p)
|
||||
{
|
||||
struct timex txc; /* Local copy of parameter */
|
||||
struct timex *kt = (void *)&txc;
|
||||
int ret;
|
||||
|
||||
/* Copy the user data space into the kernel copy
|
||||
* structure. But bear in mind that the structures
|
||||
* may change
|
||||
*/
|
||||
if (copy_from_user(&txc, txc_p, sizeof(struct timex)))
|
||||
return -EFAULT;
|
||||
|
||||
/*
|
||||
* override for sparc64 specific timeval type: tv_usec
|
||||
* is 32 bit wide instead of 64-bit in __kernel_timex
|
||||
*/
|
||||
kt->time.tv_usec = txc.time.tv_usec;
|
||||
ret = do_adjtimex(kt);
|
||||
txc.time.tv_usec = kt->time.tv_usec;
|
||||
|
||||
return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(sparc_clock_adjtime, const clockid_t, which_clock,struct timex __user *, txc_p)
|
||||
{
|
||||
struct timex txc; /* Local copy of parameter */
|
||||
struct timex *kt = (void *)&txc;
|
||||
int ret;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_POSIX_TIMERS)) {
|
||||
pr_err_once("process %d (%s) attempted a POSIX timer syscall "
|
||||
"while CONFIG_POSIX_TIMERS is not set\n",
|
||||
current->pid, current->comm);
|
||||
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/* Copy the user data space into the kernel copy
|
||||
* structure. But bear in mind that the structures
|
||||
* may change
|
||||
*/
|
||||
if (copy_from_user(&txc, txc_p, sizeof(struct timex)))
|
||||
return -EFAULT;
|
||||
|
||||
/*
|
||||
* override for sparc64 specific timeval type: tv_usec
|
||||
* is 32 bit wide instead of 64-bit in __kernel_timex
|
||||
*/
|
||||
kt->time.tv_usec = txc.time.tv_usec;
|
||||
ret = do_clock_adjtime(which_clock, kt);
|
||||
txc.time.tv_usec = kt->time.tv_usec;
|
||||
|
||||
return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE5(utrap_install, utrap_entry_t, type,
|
||||
utrap_handler_t, new_p, utrap_handler_t, new_d,
|
||||
utrap_handler_t __user *, old_p,
|
||||
|
@ -258,7 +258,8 @@
|
||||
216 64 sigreturn sys_nis_syscall
|
||||
217 common clone sys_clone
|
||||
218 common ioprio_get sys_ioprio_get
|
||||
219 common adjtimex sys_adjtimex compat_sys_adjtimex
|
||||
219 32 adjtimex sys_adjtimex compat_sys_adjtimex
|
||||
219 64 adjtimex sys_sparc_adjtimex
|
||||
220 32 sigprocmask sys_sigprocmask compat_sys_sigprocmask
|
||||
220 64 sigprocmask sys_nis_syscall
|
||||
221 common create_module sys_ni_syscall
|
||||
@ -377,7 +378,8 @@
|
||||
331 common prlimit64 sys_prlimit64
|
||||
332 common name_to_handle_at sys_name_to_handle_at
|
||||
333 common open_by_handle_at sys_open_by_handle_at compat_sys_open_by_handle_at
|
||||
334 common clock_adjtime sys_clock_adjtime compat_sys_clock_adjtime
|
||||
334 32 clock_adjtime sys_clock_adjtime compat_sys_clock_adjtime
|
||||
334 64 clock_adjtime sys_sparc_clock_adjtime
|
||||
335 common syncfs sys_syncfs
|
||||
336 common sendmmsg sys_sendmmsg compat_sys_sendmmsg
|
||||
337 common setns sys_setns
|
||||
|
@ -159,6 +159,8 @@ extern unsigned long tick_nsec; /* SHIFTED_HZ period (nsec) */
|
||||
#define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ)
|
||||
|
||||
extern int do_adjtimex(struct timex *);
|
||||
extern int do_clock_adjtime(const clockid_t which_clock, struct timex * ktx);
|
||||
|
||||
extern void hardpps(const struct timespec64 *, const struct timespec64 *);
|
||||
|
||||
int read_current_timer(unsigned long *timer_val);
|
||||
|
@ -1047,22 +1047,28 @@ SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,
|
||||
struct timex __user *, utx)
|
||||
int do_clock_adjtime(const clockid_t which_clock, struct timex * ktx)
|
||||
{
|
||||
const struct k_clock *kc = clockid_to_kclock(which_clock);
|
||||
struct timex ktx;
|
||||
int err;
|
||||
|
||||
if (!kc)
|
||||
return -EINVAL;
|
||||
if (!kc->clock_adj)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return kc->clock_adj(which_clock, ktx);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,
|
||||
struct timex __user *, utx)
|
||||
{
|
||||
struct timex ktx;
|
||||
int err;
|
||||
|
||||
if (copy_from_user(&ktx, utx, sizeof(ktx)))
|
||||
return -EFAULT;
|
||||
|
||||
err = kc->clock_adj(which_clock, &ktx);
|
||||
err = do_clock_adjtime(which_clock, &ktx);
|
||||
|
||||
if (err >= 0 && copy_to_user(utx, &ktx, sizeof(ktx)))
|
||||
return -EFAULT;
|
||||
@ -1126,20 +1132,14 @@ COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock,
|
||||
COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock,
|
||||
struct old_timex32 __user *, utp)
|
||||
{
|
||||
const struct k_clock *kc = clockid_to_kclock(which_clock);
|
||||
struct timex ktx;
|
||||
int err;
|
||||
|
||||
if (!kc)
|
||||
return -EINVAL;
|
||||
if (!kc->clock_adj)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
err = get_old_timex32(&ktx, utp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = kc->clock_adj(which_clock, &ktx);
|
||||
err = do_clock_adjtime(which_clock, &ktx);
|
||||
|
||||
if (err >= 0)
|
||||
err = put_old_timex32(utp, &ktx);
|
||||
|
Loading…
Reference in New Issue
Block a user