Skip to content

Commit 1a59639

Browse files
committed
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 <[email protected]>
1 parent 50b93f3 commit 1a59639

File tree

4 files changed

+76
-15
lines changed

4 files changed

+76
-15
lines changed

arch/sparc/kernel/sys_sparc_64.c

+58-1
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@
2828
#include <linux/random.h>
2929
#include <linux/export.h>
3030
#include <linux/context_tracking.h>
31-
31+
#include <linux/timex.h>
3232
#include <linux/uaccess.h>
33+
3334
#include <asm/utrap.h>
3435
#include <asm/unistd.h>
3536

@@ -544,6 +545,62 @@ SYSCALL_DEFINE2(getdomainname, char __user *, name, int, len)
544545
return err;
545546
}
546547

548+
SYSCALL_DEFINE1(sparc_adjtimex, struct timex __user *, txc_p)
549+
{
550+
struct timex txc; /* Local copy of parameter */
551+
struct timex *kt = (void *)&txc;
552+
int ret;
553+
554+
/* Copy the user data space into the kernel copy
555+
* structure. But bear in mind that the structures
556+
* may change
557+
*/
558+
if (copy_from_user(&txc, txc_p, sizeof(struct timex)))
559+
return -EFAULT;
560+
561+
/*
562+
* override for sparc64 specific timeval type: tv_usec
563+
* is 32 bit wide instead of 64-bit in __kernel_timex
564+
*/
565+
kt->time.tv_usec = txc.time.tv_usec;
566+
ret = do_adjtimex(kt);
567+
txc.time.tv_usec = kt->time.tv_usec;
568+
569+
return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret;
570+
}
571+
572+
SYSCALL_DEFINE2(sparc_clock_adjtime, const clockid_t, which_clock,struct timex __user *, txc_p)
573+
{
574+
struct timex txc; /* Local copy of parameter */
575+
struct timex *kt = (void *)&txc;
576+
int ret;
577+
578+
if (!IS_ENABLED(CONFIG_POSIX_TIMERS)) {
579+
pr_err_once("process %d (%s) attempted a POSIX timer syscall "
580+
"while CONFIG_POSIX_TIMERS is not set\n",
581+
current->pid, current->comm);
582+
583+
return -ENOSYS;
584+
}
585+
586+
/* Copy the user data space into the kernel copy
587+
* structure. But bear in mind that the structures
588+
* may change
589+
*/
590+
if (copy_from_user(&txc, txc_p, sizeof(struct timex)))
591+
return -EFAULT;
592+
593+
/*
594+
* override for sparc64 specific timeval type: tv_usec
595+
* is 32 bit wide instead of 64-bit in __kernel_timex
596+
*/
597+
kt->time.tv_usec = txc.time.tv_usec;
598+
ret = do_clock_adjtime(which_clock, kt);
599+
txc.time.tv_usec = kt->time.tv_usec;
600+
601+
return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret;
602+
}
603+
547604
SYSCALL_DEFINE5(utrap_install, utrap_entry_t, type,
548605
utrap_handler_t, new_p, utrap_handler_t, new_d,
549606
utrap_handler_t __user *, old_p,

arch/sparc/kernel/syscalls/syscall.tbl

+4-2
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,8 @@
258258
216 64 sigreturn sys_nis_syscall
259259
217 common clone sys_clone
260260
218 common ioprio_get sys_ioprio_get
261-
219 common adjtimex sys_adjtimex compat_sys_adjtimex
261+
219 32 adjtimex sys_adjtimex compat_sys_adjtimex
262+
219 64 adjtimex sys_sparc_adjtimex
262263
220 32 sigprocmask sys_sigprocmask compat_sys_sigprocmask
263264
220 64 sigprocmask sys_nis_syscall
264265
221 common create_module sys_ni_syscall
@@ -377,7 +378,8 @@
377378
331 common prlimit64 sys_prlimit64
378379
332 common name_to_handle_at sys_name_to_handle_at
379380
333 common open_by_handle_at sys_open_by_handle_at compat_sys_open_by_handle_at
380-
334 common clock_adjtime sys_clock_adjtime compat_sys_clock_adjtime
381+
334 32 clock_adjtime sys_clock_adjtime compat_sys_clock_adjtime
382+
334 64 clock_adjtime sys_sparc_clock_adjtime
381383
335 common syncfs sys_syncfs
382384
336 common sendmmsg sys_sendmmsg compat_sys_sendmmsg
383385
337 common setns sys_setns

include/linux/timex.h

+2
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ extern unsigned long tick_nsec; /* SHIFTED_HZ period (nsec) */
159159
#define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ)
160160

161161
extern int do_adjtimex(struct timex *);
162+
extern int do_clock_adjtime(const clockid_t which_clock, struct timex * ktx);
163+
162164
extern void hardpps(const struct timespec64 *, const struct timespec64 *);
163165

164166
int read_current_timer(unsigned long *timer_val);

kernel/time/posix-timers.c

+12-12
Original file line numberDiff line numberDiff line change
@@ -1047,22 +1047,28 @@ SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
10471047
return error;
10481048
}
10491049

1050-
SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,
1051-
struct timex __user *, utx)
1050+
int do_clock_adjtime(const clockid_t which_clock, struct timex * ktx)
10521051
{
10531052
const struct k_clock *kc = clockid_to_kclock(which_clock);
1054-
struct timex ktx;
1055-
int err;
10561053

10571054
if (!kc)
10581055
return -EINVAL;
10591056
if (!kc->clock_adj)
10601057
return -EOPNOTSUPP;
10611058

1059+
return kc->clock_adj(which_clock, ktx);
1060+
}
1061+
1062+
SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,
1063+
struct timex __user *, utx)
1064+
{
1065+
struct timex ktx;
1066+
int err;
1067+
10621068
if (copy_from_user(&ktx, utx, sizeof(ktx)))
10631069
return -EFAULT;
10641070

1065-
err = kc->clock_adj(which_clock, &ktx);
1071+
err = do_clock_adjtime(which_clock, &ktx);
10661072

10671073
if (err >= 0 && copy_to_user(utx, &ktx, sizeof(ktx)))
10681074
return -EFAULT;
@@ -1126,20 +1132,14 @@ COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock,
11261132
COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock,
11271133
struct old_timex32 __user *, utp)
11281134
{
1129-
const struct k_clock *kc = clockid_to_kclock(which_clock);
11301135
struct timex ktx;
11311136
int err;
11321137

1133-
if (!kc)
1134-
return -EINVAL;
1135-
if (!kc->clock_adj)
1136-
return -EOPNOTSUPP;
1137-
11381138
err = get_old_timex32(&ktx, utp);
11391139
if (err)
11401140
return err;
11411141

1142-
err = kc->clock_adj(which_clock, &ktx);
1142+
err = do_clock_adjtime(which_clock, &ktx);
11431143

11441144
if (err >= 0)
11451145
err = put_old_timex32(utp, &ktx);

0 commit comments

Comments
 (0)