diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2019-01-03 15:12:39 -0500 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2019-02-06 18:13:27 -0500 |
| commit | 1a596398a3d75f966b75f428e992cf1f242f9a5b (patch) | |
| tree | 41f323cd7eceec2b40df53cb805586c4df05d9b8 | |
| parent | 50b93f30f6d8672f9ec80e90af94d733f11a20e0 (diff) | |
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>
| -rw-r--r-- | arch/sparc/kernel/sys_sparc_64.c | 59 | ||||
| -rw-r--r-- | arch/sparc/kernel/syscalls/syscall.tbl | 6 | ||||
| -rw-r--r-- | include/linux/timex.h | 2 | ||||
| -rw-r--r-- | kernel/time/posix-timers.c | 24 |
4 files changed, 76 insertions, 15 deletions
diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 1c079e7bab09..37de18a11207 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c | |||
| @@ -28,8 +28,9 @@ | |||
| 28 | #include <linux/random.h> | 28 | #include <linux/random.h> |
| 29 | #include <linux/export.h> | 29 | #include <linux/export.h> |
| 30 | #include <linux/context_tracking.h> | 30 | #include <linux/context_tracking.h> |
| 31 | 31 | #include <linux/timex.h> | |
| 32 | #include <linux/uaccess.h> | 32 | #include <linux/uaccess.h> |
| 33 | |||
| 33 | #include <asm/utrap.h> | 34 | #include <asm/utrap.h> |
| 34 | #include <asm/unistd.h> | 35 | #include <asm/unistd.h> |
| 35 | 36 | ||
| @@ -544,6 +545,62 @@ out_unlock: | |||
| 544 | return err; | 545 | return err; |
| 545 | } | 546 | } |
| 546 | 547 | ||
| 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 | |||
| 547 | SYSCALL_DEFINE5(utrap_install, utrap_entry_t, type, | 604 | SYSCALL_DEFINE5(utrap_install, utrap_entry_t, type, |
| 548 | utrap_handler_t, new_p, utrap_handler_t, new_d, | 605 | utrap_handler_t, new_p, utrap_handler_t, new_d, |
| 549 | utrap_handler_t __user *, old_p, | 606 | utrap_handler_t __user *, old_p, |
diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl index 6992d17cce37..e63cd013cc77 100644 --- a/arch/sparc/kernel/syscalls/syscall.tbl +++ b/arch/sparc/kernel/syscalls/syscall.tbl | |||
| @@ -258,7 +258,8 @@ | |||
| 258 | 216 64 sigreturn sys_nis_syscall | 258 | 216 64 sigreturn sys_nis_syscall |
| 259 | 217 common clone sys_clone | 259 | 217 common clone sys_clone |
| 260 | 218 common ioprio_get sys_ioprio_get | 260 | 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 | ||
| 262 | 220 32 sigprocmask sys_sigprocmask compat_sys_sigprocmask | 263 | 220 32 sigprocmask sys_sigprocmask compat_sys_sigprocmask |
| 263 | 220 64 sigprocmask sys_nis_syscall | 264 | 220 64 sigprocmask sys_nis_syscall |
| 264 | 221 common create_module sys_ni_syscall | 265 | 221 common create_module sys_ni_syscall |
| @@ -377,7 +378,8 @@ | |||
| 377 | 331 common prlimit64 sys_prlimit64 | 378 | 331 common prlimit64 sys_prlimit64 |
| 378 | 332 common name_to_handle_at sys_name_to_handle_at | 379 | 332 common name_to_handle_at sys_name_to_handle_at |
| 379 | 333 common open_by_handle_at sys_open_by_handle_at compat_sys_open_by_handle_at | 380 | 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 | ||
| 381 | 335 common syncfs sys_syncfs | 383 | 335 common syncfs sys_syncfs |
| 382 | 336 common sendmmsg sys_sendmmsg compat_sys_sendmmsg | 384 | 336 common sendmmsg sys_sendmmsg compat_sys_sendmmsg |
| 383 | 337 common setns sys_setns | 385 | 337 common setns sys_setns |
diff --git a/include/linux/timex.h b/include/linux/timex.h index 7f40e9e42ecc..a15e6aeb8d49 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h | |||
| @@ -159,6 +159,8 @@ extern unsigned long tick_nsec; /* SHIFTED_HZ period (nsec) */ | |||
| 159 | #define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ) | 159 | #define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ) |
| 160 | 160 | ||
| 161 | extern int do_adjtimex(struct timex *); | 161 | extern int do_adjtimex(struct timex *); |
| 162 | extern int do_clock_adjtime(const clockid_t which_clock, struct timex * ktx); | ||
| 163 | |||
| 162 | extern void hardpps(const struct timespec64 *, const struct timespec64 *); | 164 | extern void hardpps(const struct timespec64 *, const struct timespec64 *); |
| 163 | 165 | ||
| 164 | int read_current_timer(unsigned long *timer_val); | 166 | int read_current_timer(unsigned long *timer_val); |
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 8955f32f2a36..8f7f1dd95940 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c | |||
| @@ -1047,22 +1047,28 @@ SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, | |||
| 1047 | return error; | 1047 | return error; |
| 1048 | } | 1048 | } |
| 1049 | 1049 | ||
| 1050 | SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock, | 1050 | int do_clock_adjtime(const clockid_t which_clock, struct timex * ktx) |
| 1051 | struct timex __user *, utx) | ||
| 1052 | { | 1051 | { |
| 1053 | const struct k_clock *kc = clockid_to_kclock(which_clock); | 1052 | const struct k_clock *kc = clockid_to_kclock(which_clock); |
| 1054 | struct timex ktx; | ||
| 1055 | int err; | ||
| 1056 | 1053 | ||
| 1057 | if (!kc) | 1054 | if (!kc) |
| 1058 | return -EINVAL; | 1055 | return -EINVAL; |
| 1059 | if (!kc->clock_adj) | 1056 | if (!kc->clock_adj) |
| 1060 | return -EOPNOTSUPP; | 1057 | return -EOPNOTSUPP; |
| 1061 | 1058 | ||
| 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 | |||
| 1062 | if (copy_from_user(&ktx, utx, sizeof(ktx))) | 1068 | if (copy_from_user(&ktx, utx, sizeof(ktx))) |
| 1063 | return -EFAULT; | 1069 | return -EFAULT; |
| 1064 | 1070 | ||
| 1065 | err = kc->clock_adj(which_clock, &ktx); | 1071 | err = do_clock_adjtime(which_clock, &ktx); |
| 1066 | 1072 | ||
| 1067 | if (err >= 0 && copy_to_user(utx, &ktx, sizeof(ktx))) | 1073 | if (err >= 0 && copy_to_user(utx, &ktx, sizeof(ktx))) |
| 1068 | return -EFAULT; | 1074 | return -EFAULT; |
| @@ -1126,20 +1132,14 @@ COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock, | |||
| 1126 | COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock, | 1132 | COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock, |
| 1127 | struct old_timex32 __user *, utp) | 1133 | struct old_timex32 __user *, utp) |
| 1128 | { | 1134 | { |
| 1129 | const struct k_clock *kc = clockid_to_kclock(which_clock); | ||
| 1130 | struct timex ktx; | 1135 | struct timex ktx; |
| 1131 | int err; | 1136 | int err; |
| 1132 | 1137 | ||
| 1133 | if (!kc) | ||
| 1134 | return -EINVAL; | ||
| 1135 | if (!kc->clock_adj) | ||
| 1136 | return -EOPNOTSUPP; | ||
| 1137 | |||
| 1138 | err = get_old_timex32(&ktx, utp); | 1138 | err = get_old_timex32(&ktx, utp); |
| 1139 | if (err) | 1139 | if (err) |
| 1140 | return err; | 1140 | return err; |
| 1141 | 1141 | ||
| 1142 | err = kc->clock_adj(which_clock, &ktx); | 1142 | err = do_clock_adjtime(which_clock, &ktx); |
| 1143 | 1143 | ||
| 1144 | if (err >= 0) | 1144 | if (err >= 0) |
| 1145 | err = put_old_timex32(utp, &ktx); | 1145 | err = put_old_timex32(utp, &ktx); |
