diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2017-06-07 04:42:31 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2017-06-13 18:00:42 -0400 |
| commit | edbeda46322fbcb15af2d2d0f2daffb0cd349a5a (patch) | |
| tree | a4aa5436d4e5dcce6f4d041d13c521e1660331b7 /kernel/compat.c | |
| parent | 99e6c0e6ec349575886ca7daffc9cb7ec583176f (diff) | |
time/posix-timers: Move the compat copyouts to the nanosleep implementations
Turn restart_block.nanosleep.{rmtp,compat_rmtp} into a tagged union (kind =
1 -> native, kind = 2 -> compat, kind = 0 -> nothing) and make the places
doing actual copyout handle compat as well as native (that will become a
helper in the next commit). Result: compat wrappers, messing with
reassignments, etc. are gone.
[ tglx: Folded in a variant of Peter Zijlstras enum patch ]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20170607084241.28657-6-viro@ZenIV.linux.org.uk
Diffstat (limited to 'kernel/compat.c')
| -rw-r--r-- | kernel/compat.c | 131 |
1 files changed, 0 insertions, 131 deletions
diff --git a/kernel/compat.c b/kernel/compat.c index cc9ba9d29b47..23afa26f574b 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
| @@ -213,82 +213,6 @@ int compat_convert_timespec(struct timespec __user **kts, | |||
| 213 | return 0; | 213 | return 0; |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | static long compat_nanosleep_restart(struct restart_block *restart) | ||
| 217 | { | ||
| 218 | struct compat_timespec __user *rmtp; | ||
| 219 | struct timespec rmt; | ||
| 220 | mm_segment_t oldfs; | ||
| 221 | long ret; | ||
| 222 | |||
| 223 | restart->nanosleep.rmtp = (struct timespec __user *) &rmt; | ||
| 224 | oldfs = get_fs(); | ||
| 225 | set_fs(KERNEL_DS); | ||
| 226 | ret = hrtimer_nanosleep_restart(restart); | ||
| 227 | set_fs(oldfs); | ||
| 228 | |||
| 229 | if (ret == -ERESTART_RESTARTBLOCK) { | ||
| 230 | rmtp = restart->nanosleep.compat_rmtp; | ||
| 231 | |||
| 232 | if (rmtp && compat_put_timespec(&rmt, rmtp)) | ||
| 233 | return -EFAULT; | ||
| 234 | } | ||
| 235 | |||
| 236 | return ret; | ||
| 237 | } | ||
| 238 | |||
| 239 | COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, | ||
| 240 | struct compat_timespec __user *, rmtp) | ||
| 241 | { | ||
| 242 | struct timespec tu, rmt; | ||
| 243 | struct timespec64 tu64; | ||
| 244 | mm_segment_t oldfs; | ||
| 245 | long ret; | ||
| 246 | |||
| 247 | if (compat_get_timespec(&tu, rqtp)) | ||
| 248 | return -EFAULT; | ||
| 249 | |||
| 250 | tu64 = timespec_to_timespec64(tu); | ||
| 251 | if (!timespec64_valid(&tu64)) | ||
| 252 | return -EINVAL; | ||
| 253 | |||
| 254 | oldfs = get_fs(); | ||
| 255 | set_fs(KERNEL_DS); | ||
| 256 | current->restart_block.nanosleep.rmtp = | ||
| 257 | rmtp ? (struct timespec __user *)&rmt : NULL; | ||
| 258 | ret = hrtimer_nanosleep(&tu64, HRTIMER_MODE_REL, CLOCK_MONOTONIC); | ||
| 259 | set_fs(oldfs); | ||
| 260 | |||
| 261 | /* | ||
| 262 | * hrtimer_nanosleep() can only return 0 or | ||
| 263 | * -ERESTART_RESTARTBLOCK here because: | ||
| 264 | * | ||
| 265 | * - we call it with HRTIMER_MODE_REL and therefor exclude the | ||
| 266 | * -ERESTARTNOHAND return path. | ||
| 267 | * | ||
| 268 | * - we supply the rmtp argument from the task stack (due to | ||
| 269 | * the necessary compat conversion. So the update cannot | ||
| 270 | * fail, which excludes the -EFAULT return path as well. If | ||
| 271 | * it fails nevertheless we have a bigger problem and wont | ||
| 272 | * reach this place anymore. | ||
| 273 | * | ||
| 274 | * - if the return value is 0, we do not have to update rmtp | ||
| 275 | * because there is no remaining time. | ||
| 276 | * | ||
| 277 | * We check for -ERESTART_RESTARTBLOCK nevertheless if the | ||
| 278 | * core implementation decides to return random nonsense. | ||
| 279 | */ | ||
| 280 | if (ret == -ERESTART_RESTARTBLOCK) { | ||
| 281 | struct restart_block *restart = ¤t->restart_block; | ||
| 282 | |||
| 283 | restart->fn = compat_nanosleep_restart; | ||
| 284 | restart->nanosleep.compat_rmtp = rmtp; | ||
| 285 | |||
| 286 | if (rmtp && compat_put_timespec(&rmt, rmtp)) | ||
| 287 | return -EFAULT; | ||
| 288 | } | ||
| 289 | return ret; | ||
| 290 | } | ||
| 291 | |||
| 292 | static inline long get_compat_itimerval(struct itimerval *o, | 216 | static inline long get_compat_itimerval(struct itimerval *o, |
| 293 | struct compat_itimerval __user *i) | 217 | struct compat_itimerval __user *i) |
| 294 | { | 218 | { |
| @@ -821,61 +745,6 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, | |||
| 821 | return err; | 745 | return err; |
| 822 | } | 746 | } |
| 823 | 747 | ||
| 824 | static long compat_clock_nanosleep_restart(struct restart_block *restart) | ||
| 825 | { | ||
| 826 | long err; | ||
| 827 | mm_segment_t oldfs; | ||
| 828 | struct timespec tu; | ||
| 829 | struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp; | ||
| 830 | |||
| 831 | restart->nanosleep.rmtp = (struct timespec __user *) &tu; | ||
| 832 | oldfs = get_fs(); | ||
| 833 | set_fs(KERNEL_DS); | ||
| 834 | err = clock_nanosleep_restart(restart); | ||
| 835 | set_fs(oldfs); | ||
| 836 | |||
| 837 | if ((err == -ERESTART_RESTARTBLOCK) && rmtp && | ||
| 838 | compat_put_timespec(&tu, rmtp)) | ||
| 839 | return -EFAULT; | ||
| 840 | |||
| 841 | if (err == -ERESTART_RESTARTBLOCK) { | ||
| 842 | restart->fn = compat_clock_nanosleep_restart; | ||
| 843 | restart->nanosleep.compat_rmtp = rmtp; | ||
| 844 | } | ||
| 845 | return err; | ||
| 846 | } | ||
| 847 | |||
| 848 | COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, | ||
| 849 | struct compat_timespec __user *, rqtp, | ||
| 850 | struct compat_timespec __user *, rmtp) | ||
| 851 | { | ||
| 852 | long err; | ||
| 853 | mm_segment_t oldfs; | ||
| 854 | struct timespec in, out; | ||
| 855 | struct restart_block *restart; | ||
| 856 | |||
| 857 | if (compat_get_timespec(&in, rqtp)) | ||
| 858 | return -EFAULT; | ||
| 859 | |||
| 860 | oldfs = get_fs(); | ||
| 861 | set_fs(KERNEL_DS); | ||
| 862 | err = sys_clock_nanosleep(which_clock, flags, | ||
| 863 | (struct timespec __user *) &in, | ||
| 864 | (struct timespec __user *) &out); | ||
| 865 | set_fs(oldfs); | ||
| 866 | |||
| 867 | if ((err == -ERESTART_RESTARTBLOCK) && rmtp && | ||
| 868 | compat_put_timespec(&out, rmtp)) | ||
| 869 | return -EFAULT; | ||
| 870 | |||
| 871 | if (err == -ERESTART_RESTARTBLOCK) { | ||
| 872 | restart = ¤t->restart_block; | ||
| 873 | restart->fn = compat_clock_nanosleep_restart; | ||
| 874 | restart->nanosleep.compat_rmtp = rmtp; | ||
| 875 | } | ||
| 876 | return err; | ||
| 877 | } | ||
| 878 | |||
| 879 | /* | 748 | /* |
| 880 | * We currently only need the following fields from the sigevent | 749 | * We currently only need the following fields from the sigevent |
| 881 | * structure: sigev_value, sigev_signo, sig_notify and (sometimes | 750 | * structure: sigev_value, sigev_signo, sig_notify and (sometimes |
