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:
@@ -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,
|
||||
|
Reference in New Issue
Block a user