xref: /freebsd/sys/compat/linux/linux_time.c (revision e87ec409fa9b21abf79895837fe375ab3d7e408a)
1 /*	$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */
2 
3 /*-
4  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
5  *
6  * Copyright (c) 2001 The NetBSD Foundation, Inc.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to The NetBSD Foundation
10  * by Emmanuel Dreyfus.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 #if 0
37 __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $");
38 #endif
39 
40 #include "opt_compat.h"
41 
42 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/ucred.h>
46 #include <sys/limits.h>
47 #include <sys/mount.h>
48 #include <sys/mutex.h>
49 #include <sys/resourcevar.h>
50 #include <sys/sdt.h>
51 #include <sys/signal.h>
52 #include <sys/stdint.h>
53 #include <sys/syscallsubr.h>
54 #include <sys/sysproto.h>
55 #include <sys/time.h>
56 #include <sys/systm.h>
57 #include <sys/proc.h>
58 
59 #ifdef COMPAT_LINUX32
60 #include <machine/../linux32/linux.h>
61 #include <machine/../linux32/linux32_proto.h>
62 #else
63 #include <machine/../linux/linux.h>
64 #include <machine/../linux/linux_proto.h>
65 #endif
66 
67 #include <compat/linux/linux_dtrace.h>
68 #include <compat/linux/linux_misc.h>
69 #include <compat/linux/linux_timer.h>
70 #include <compat/linux/linux_util.h>
71 
72 /* DTrace init */
73 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
74 
75 /**
76  * DTrace probes in this module.
77  */
78 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid,
79     "clockid_t");
80 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid,
81     "clockid_t");
82 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_gettime, conversion_error, "int");
83 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int");
84 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int");
85 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
86 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime64, gettime_error, "int");
87 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime64, copyout_error, "int");
88 #endif
89 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int");
90 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_settime, settime_error, "int");
91 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_settime, conversion_error, "int");
92 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int");
93 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
94 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime64, conversion_error, "int");
95 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime64, copyin_error, "int");
96 #endif
97 LIN_SDT_PROBE_DEFINE0(time, linux_common_clock_getres, nullcall);
98 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_getres, conversion_error, "int");
99 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_getres, getres_error, "int");
100 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int");
101 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
102 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres_time64, copyout_error, "int");
103 #endif
104 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, conversion_error, "int");
105 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int");
106 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int");
107 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, conversion_error, "int");
108 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int");
109 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int");
110 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_nanosleep, unsupported_flags, "int");
111 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_nanosleep, unsupported_clockid, "int");
112 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
113 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep_time64, conversion_error, "int");
114 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep_time64, copyout_error, "int");
115 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep_time64, copyin_error, "int");
116 #endif
117 
118 static int	linux_common_clock_gettime(struct thread *, clockid_t,
119 		    struct timespec *);
120 static int	linux_common_clock_settime(struct thread *, clockid_t,
121 		    struct timespec *);
122 static int	linux_common_clock_getres(struct thread *, clockid_t,
123 		    struct timespec *);
124 static int	linux_common_clock_nanosleep(struct thread *, clockid_t,
125 		    l_int, struct timespec *, struct timespec *);
126 
127 int
128 native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp)
129 {
130 
131 #ifdef COMPAT_LINUX32
132 	if (ntp->tv_sec > INT_MAX || ntp->tv_sec < INT_MIN)
133 		return (EOVERFLOW);
134 #endif
135 	ltp->tv_sec = ntp->tv_sec;
136 	ltp->tv_nsec = ntp->tv_nsec;
137 
138 	return (0);
139 }
140 
141 int
142 linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp)
143 {
144 
145 	if (ltp->tv_sec < 0 || ltp->tv_nsec < 0 || ltp->tv_nsec > 999999999)
146 		return (EINVAL);
147 	ntp->tv_sec = ltp->tv_sec;
148 	ntp->tv_nsec = ltp->tv_nsec;
149 
150 	return (0);
151 }
152 
153 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
154 int
155 native_to_linux_timespec64(struct l_timespec64 *ltp64, struct timespec *ntp)
156 {
157 
158 	ltp64->tv_sec = ntp->tv_sec;
159 	ltp64->tv_nsec = ntp->tv_nsec;
160 
161 	return (0);
162 }
163 
164 int
165 linux_to_native_timespec64(struct timespec *ntp, struct l_timespec64 *ltp64)
166 {
167 
168 	if (ltp64->tv_sec < 0 || ltp64->tv_nsec < 0 || ltp64->tv_nsec > 999999999)
169 		return (EINVAL);
170 	ntp->tv_sec = ltp64->tv_sec;
171 	ntp->tv_nsec = ltp64->tv_nsec;
172 
173 	return (0);
174 }
175 #endif
176 
177 int
178 native_to_linux_itimerspec(struct l_itimerspec *ltp, struct itimerspec *ntp)
179 {
180 	int error;
181 
182 	error = native_to_linux_timespec(&ltp->it_interval, &ntp->it_interval);
183 	if (error == 0)
184 		error = native_to_linux_timespec(&ltp->it_value, &ntp->it_value);
185 	return (error);
186 }
187 
188 int
189 linux_to_native_itimerspec(struct itimerspec *ntp, struct l_itimerspec *ltp)
190 {
191 	int error;
192 
193 	error = linux_to_native_timespec(&ntp->it_interval, &ltp->it_interval);
194 	if (error == 0)
195 		error = linux_to_native_timespec(&ntp->it_value, &ltp->it_value);
196 	return (error);
197 }
198 
199 int
200 linux_to_native_clockid(clockid_t *n, clockid_t l)
201 {
202 
203 	if (l < 0) {
204 		/* cpu-clock */
205 		if ((l & LINUX_CLOCKFD_MASK) == LINUX_CLOCKFD)
206 			return (EINVAL);
207 		if (LINUX_CPUCLOCK_WHICH(l) >= LINUX_CPUCLOCK_MAX)
208 			return (EINVAL);
209 
210 		if (LINUX_CPUCLOCK_PERTHREAD(l))
211 			*n = CLOCK_THREAD_CPUTIME_ID;
212 		else
213 			*n = CLOCK_PROCESS_CPUTIME_ID;
214 		return (0);
215 	}
216 
217 	switch (l) {
218 	case LINUX_CLOCK_REALTIME:
219 		*n = CLOCK_REALTIME;
220 		break;
221 	case LINUX_CLOCK_MONOTONIC:
222 		*n = CLOCK_MONOTONIC;
223 		break;
224 	case LINUX_CLOCK_PROCESS_CPUTIME_ID:
225 		*n = CLOCK_PROCESS_CPUTIME_ID;
226 		break;
227 	case LINUX_CLOCK_THREAD_CPUTIME_ID:
228 		*n = CLOCK_THREAD_CPUTIME_ID;
229 		break;
230 	case LINUX_CLOCK_REALTIME_COARSE:
231 		*n = CLOCK_REALTIME_FAST;
232 		break;
233 	case LINUX_CLOCK_MONOTONIC_COARSE:
234 	case LINUX_CLOCK_MONOTONIC_RAW:
235 		*n = CLOCK_MONOTONIC_FAST;
236 		break;
237 	case LINUX_CLOCK_BOOTTIME:
238 		*n = CLOCK_UPTIME;
239 		break;
240 	case LINUX_CLOCK_REALTIME_ALARM:
241 	case LINUX_CLOCK_BOOTTIME_ALARM:
242 	case LINUX_CLOCK_SGI_CYCLE:
243 	case LINUX_CLOCK_TAI:
244 		LIN_SDT_PROBE1(time, linux_to_native_clockid,
245 		    unsupported_clockid, l);
246 		return (EINVAL);
247 	default:
248 		LIN_SDT_PROBE1(time, linux_to_native_clockid,
249 		    unknown_clockid, l);
250 		return (EINVAL);
251 	}
252 
253 	return (0);
254 }
255 
256 int
257 linux_to_native_timerflags(int *nflags, int flags)
258 {
259 
260 	if (flags & ~LINUX_TIMER_ABSTIME)
261 		return (EINVAL);
262 	*nflags = 0;
263 	if (flags & LINUX_TIMER_ABSTIME)
264 		*nflags |= TIMER_ABSTIME;
265 	return (0);
266 }
267 
268 static int
269 linux_common_clock_gettime(struct thread *td, clockid_t which,
270     struct timespec *tp)
271 {
272 	struct rusage ru;
273 	struct thread *targettd;
274 	struct proc *p;
275 	int error, clockwhich;
276 	clockid_t nwhich;
277 	pid_t pid;
278 	lwpid_t tid;
279 
280 	error = linux_to_native_clockid(&nwhich, which);
281 	if (error != 0) {
282 		linux_msg(curthread,
283 		    "unsupported clock_gettime clockid %d", which);
284 		LIN_SDT_PROBE1(time, linux_common_clock_gettime,
285 		    conversion_error, error);
286 		return (error);
287 	}
288 
289 	switch (nwhich) {
290 	case CLOCK_PROCESS_CPUTIME_ID:
291 		if (which < 0) {
292 			clockwhich = LINUX_CPUCLOCK_WHICH(which);
293 			pid = LINUX_CPUCLOCK_ID(which);
294 		} else {
295 			clockwhich = LINUX_CPUCLOCK_SCHED;
296 			pid = 0;
297 		}
298 		if (pid == 0) {
299 			p = td->td_proc;
300 			PROC_LOCK(p);
301 		} else {
302 			error = pget(pid, PGET_CANSEE, &p);
303 			if (error != 0)
304 				return (EINVAL);
305 		}
306 		switch (clockwhich) {
307 		case LINUX_CPUCLOCK_PROF:
308 			PROC_STATLOCK(p);
309 			calcru(p, &ru.ru_utime, &ru.ru_stime);
310 			PROC_STATUNLOCK(p);
311 			PROC_UNLOCK(p);
312 			timevaladd(&ru.ru_utime, &ru.ru_stime);
313 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp);
314 			break;
315 		case LINUX_CPUCLOCK_VIRT:
316 			PROC_STATLOCK(p);
317 			calcru(p, &ru.ru_utime, &ru.ru_stime);
318 			PROC_STATUNLOCK(p);
319 			PROC_UNLOCK(p);
320 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp);
321 			break;
322 		case LINUX_CPUCLOCK_SCHED:
323 			kern_process_cputime(p, tp);
324 			PROC_UNLOCK(p);
325 			break;
326 		default:
327 			PROC_UNLOCK(p);
328 			return (EINVAL);
329 		}
330 
331 		break;
332 
333 	case CLOCK_THREAD_CPUTIME_ID:
334 		if (which < 0) {
335 			clockwhich = LINUX_CPUCLOCK_WHICH(which);
336 			tid = LINUX_CPUCLOCK_ID(which);
337 		} else {
338 			clockwhich = LINUX_CPUCLOCK_SCHED;
339 			tid = 0;
340 		}
341 		p = td->td_proc;
342 		if (tid == 0) {
343 			targettd = td;
344 			PROC_LOCK(p);
345 		} else {
346 			targettd = linux_tdfind(td, tid, p->p_pid);
347 			if (targettd == NULL)
348 				return (EINVAL);
349 		}
350 		switch (clockwhich) {
351 		case LINUX_CPUCLOCK_PROF:
352 			PROC_STATLOCK(p);
353 			thread_lock(targettd);
354 			rufetchtd(targettd, &ru);
355 			thread_unlock(targettd);
356 			PROC_STATUNLOCK(p);
357 			PROC_UNLOCK(p);
358 			timevaladd(&ru.ru_utime, &ru.ru_stime);
359 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp);
360 			break;
361 		case LINUX_CPUCLOCK_VIRT:
362 			PROC_STATLOCK(p);
363 			thread_lock(targettd);
364 			rufetchtd(targettd, &ru);
365 			thread_unlock(targettd);
366 			PROC_STATUNLOCK(p);
367 			PROC_UNLOCK(p);
368 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp);
369 			break;
370 		case LINUX_CPUCLOCK_SCHED:
371 			if (td == targettd)
372 				targettd = NULL;
373 			kern_thread_cputime(targettd, tp);
374 			PROC_UNLOCK(p);
375 			break;
376 		default:
377 			PROC_UNLOCK(p);
378 			return (EINVAL);
379 		}
380 		break;
381 
382 	default:
383 		error = kern_clock_gettime(td, nwhich, tp);
384 		break;
385 	}
386 
387 	return (error);
388 }
389 
390 int
391 linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args)
392 {
393 	struct l_timespec lts;
394 	struct timespec tp;
395 	int error;
396 
397 	error = linux_common_clock_gettime(td, args->which, &tp);
398 	if (error != 0) {
399 		LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error);
400 		return (error);
401 	}
402 	error = native_to_linux_timespec(&lts, &tp);
403 	if (error != 0)
404 		return (error);
405 	error = copyout(&lts, args->tp, sizeof(lts));
406 	if (error != 0)
407 		LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error);
408 
409 	return (error);
410 }
411 
412 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
413 int
414 linux_clock_gettime64(struct thread *td, struct linux_clock_gettime64_args *args)
415 {
416 	struct l_timespec64 lts;
417 	struct timespec tp;
418 	int error;
419 
420 	error = linux_common_clock_gettime(td, args->which, &tp);
421 	if (error != 0) {
422 		LIN_SDT_PROBE1(time, linux_clock_gettime64, gettime_error, error);
423 		return (error);
424 	}
425 	error = native_to_linux_timespec64(&lts, &tp);
426 	if (error != 0)
427 		return (error);
428 	error = copyout(&lts, args->tp, sizeof(lts));
429 	if (error != 0)
430 		LIN_SDT_PROBE1(time, linux_clock_gettime64, copyout_error, error);
431 
432 	return (error);
433 }
434 #endif
435 
436 static int
437 linux_common_clock_settime(struct thread *td, clockid_t which,
438     struct timespec *ts)
439 {
440 	int error;
441 	clockid_t nwhich;
442 
443 	error = linux_to_native_clockid(&nwhich, which);
444 	if (error != 0) {
445 		linux_msg(curthread,
446 		    "unsupported clock_settime clockid %d", which);
447 		LIN_SDT_PROBE1(time, linux_common_clock_settime, conversion_error,
448 		    error);
449 		return (error);
450 	}
451 
452 	error = kern_clock_settime(td, nwhich, ts);
453 	if (error != 0)
454 		LIN_SDT_PROBE1(time, linux_common_clock_settime,
455 		    settime_error, error);
456 
457 	return (error);
458 }
459 
460 int
461 linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args)
462 {
463 	struct timespec ts;
464 	struct l_timespec lts;
465 	int error;
466 
467 	error = copyin(args->tp, &lts, sizeof(lts));
468 	if (error != 0) {
469 		LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error);
470 		return (error);
471 	}
472 	error = linux_to_native_timespec(&ts, &lts);
473 	if (error != 0)
474 		LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
475 		    error);
476 
477 	return (linux_common_clock_settime(td, args->which, &ts));
478 }
479 
480 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
481 int
482 linux_clock_settime64(struct thread *td, struct linux_clock_settime64_args *args)
483 {
484 	struct timespec ts;
485 	struct l_timespec64 lts;
486 	int error;
487 
488 	error = copyin(args->tp, &lts, sizeof(lts));
489 	if (error != 0) {
490 		LIN_SDT_PROBE1(time, linux_clock_settime64, copyin_error, error);
491 		return (error);
492 	}
493 	error = linux_to_native_timespec64(&ts, &lts);
494 	if (error != 0)
495 		LIN_SDT_PROBE1(time, linux_clock_settime64, conversion_error,
496 		    error);
497 	return (linux_common_clock_settime(td, args->which, &ts));
498 }
499 #endif
500 
501 static int
502 linux_common_clock_getres(struct thread *td, clockid_t which,
503     struct timespec *ts)
504 {
505 	struct proc *p;
506 	int error, clockwhich;
507 	clockid_t nwhich;
508 	pid_t pid;
509 	lwpid_t tid;
510 
511 	error = linux_to_native_clockid(&nwhich, which);
512 	if (error != 0) {
513 		linux_msg(curthread,
514 		    "unsupported clock_getres clockid %d", which);
515 		LIN_SDT_PROBE1(time, linux_common_clock_getres,
516 		    conversion_error, error);
517 		return (error);
518 	}
519 
520 	/*
521 	 * Check user supplied clock id in case of per-process
522 	 * or thread-specific cpu-time clock.
523 	 */
524 	if (which < 0) {
525 		switch (nwhich) {
526 		case CLOCK_THREAD_CPUTIME_ID:
527 			tid = LINUX_CPUCLOCK_ID(which);
528 			if (tid != 0) {
529 				p = td->td_proc;
530 				if (linux_tdfind(td, tid, p->p_pid) == NULL)
531 					return (EINVAL);
532 				PROC_UNLOCK(p);
533 			}
534 			break;
535 		case CLOCK_PROCESS_CPUTIME_ID:
536 			pid = LINUX_CPUCLOCK_ID(which);
537 			if (pid != 0) {
538 				error = pget(pid, PGET_CANSEE, &p);
539 				if (error != 0)
540 					return (EINVAL);
541 				PROC_UNLOCK(p);
542 			}
543 			break;
544 		}
545 	}
546 
547 	if (ts == NULL) {
548 		LIN_SDT_PROBE0(time, linux_common_clock_getres, nullcall);
549 		return (0);
550 	}
551 
552 	switch (nwhich) {
553 	case CLOCK_THREAD_CPUTIME_ID:
554 	case CLOCK_PROCESS_CPUTIME_ID:
555 		clockwhich = LINUX_CPUCLOCK_WHICH(which);
556 		/*
557 		 * In both cases (when the clock id obtained by a call to
558 		 * clock_getcpuclockid() or using the clock
559 		 * ID CLOCK_PROCESS_CPUTIME_ID Linux hardcodes precision
560 		 * of clock. The same for the CLOCK_THREAD_CPUTIME_ID clock.
561 		 *
562 		 * See Linux posix_cpu_clock_getres() implementation.
563 		 */
564 		if (which > 0 || clockwhich == LINUX_CPUCLOCK_SCHED) {
565 			ts->tv_sec = 0;
566 			ts->tv_nsec = 1;
567 			goto out;
568 		}
569 
570 		switch (clockwhich) {
571 		case LINUX_CPUCLOCK_PROF:
572 			nwhich = CLOCK_PROF;
573 			break;
574 		case LINUX_CPUCLOCK_VIRT:
575 			nwhich = CLOCK_VIRTUAL;
576 			break;
577 		default:
578 			return (EINVAL);
579 		}
580 		break;
581 
582 	default:
583 		break;
584 	}
585 	error = kern_clock_getres(td, nwhich, ts);
586 	if (error != 0) {
587 		LIN_SDT_PROBE1(time, linux_common_clock_getres,
588 		    getres_error, error);
589 		return (error);
590 	}
591 
592 out:
593 	return (error);
594 }
595 
596 int
597 linux_clock_getres(struct thread *td,
598     struct linux_clock_getres_args *args)
599 {
600 	struct timespec ts;
601 	struct l_timespec lts;
602 	int error;
603 
604 	error = linux_common_clock_getres(td, args->which, &ts);
605 	if (error != 0 || args->tp == NULL)
606 		return (error);
607 
608 	error = native_to_linux_timespec(&lts, &ts);
609 	if (error != 0)
610 		return (error);
611 	error = copyout(&lts, args->tp, sizeof(lts));
612 	if (error != 0)
613 		LIN_SDT_PROBE1(time, linux_clock_getres,
614 		    copyout_error, error);
615 	return (error);
616 }
617 
618 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
619 int
620 linux_clock_getres_time64(struct thread *td,
621     struct linux_clock_getres_time64_args *args)
622 {
623 	struct timespec ts;
624 	struct l_timespec64 lts;
625 	int error;
626 
627 	error = linux_common_clock_getres(td, args->which, &ts);
628 	if (error != 0 || args->tp == NULL)
629 		return (error);
630 
631 	error = native_to_linux_timespec64(&lts, &ts);
632 	if (error != 0)
633 		return (error);
634 	error = copyout(&lts, args->tp, sizeof(lts));
635 	if (error != 0)
636 		LIN_SDT_PROBE1(time, linux_clock_getres_time64,
637 		    copyout_error, error);
638 	return (error);
639 }
640 #endif
641 
642 int
643 linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args)
644 {
645 	struct timespec *rmtp;
646 	struct l_timespec lrqts, lrmts;
647 	struct timespec rqts, rmts;
648 	int error, error2;
649 
650 	error = copyin(args->rqtp, &lrqts, sizeof lrqts);
651 	if (error != 0) {
652 		LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error);
653 		return (error);
654 	}
655 
656 	if (args->rmtp != NULL)
657 		rmtp = &rmts;
658 	else
659 		rmtp = NULL;
660 
661 	error = linux_to_native_timespec(&rqts, &lrqts);
662 	if (error != 0) {
663 		LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error);
664 		return (error);
665 	}
666 	error = kern_nanosleep(td, &rqts, rmtp);
667 	if (error == EINTR && args->rmtp != NULL) {
668 		error2 = native_to_linux_timespec(&lrmts, rmtp);
669 		if (error2 != 0)
670 			return (error2);
671 		error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
672 		if (error2 != 0) {
673 			LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error,
674 			    error2);
675 			return (error2);
676 		}
677 	}
678 
679 	return (error);
680 }
681 
682 static int
683 linux_common_clock_nanosleep(struct thread *td, clockid_t which,
684     l_int lflags, struct timespec *rqtp, struct timespec *rmtp)
685 {
686 	int error, flags;
687 	clockid_t clockid;
688 
689 	error = linux_to_native_timerflags(&flags, lflags);
690 	if (error != 0) {
691 		LIN_SDT_PROBE1(time, linux_common_clock_nanosleep,
692 		    unsupported_flags, lflags);
693 		return (error);
694 	}
695 
696 	error = linux_to_native_clockid(&clockid, which);
697 	if (error != 0) {
698 		linux_msg(curthread,
699 		    "unsupported clock_nanosleep clockid %d", which);
700 		LIN_SDT_PROBE1(time, linux_common_clock_nanosleep,
701 		    unsupported_clockid, which);
702 		return (error);
703 	}
704 	if (clockid == CLOCK_THREAD_CPUTIME_ID)
705 		return (ENOTSUP);
706 
707 	return (kern_clock_nanosleep(td, clockid, flags, rqtp, rmtp));
708 }
709 
710 int
711 linux_clock_nanosleep(struct thread *td,
712     struct linux_clock_nanosleep_args *args)
713 {
714 	struct timespec *rmtp;
715 	struct l_timespec lrqts, lrmts;
716 	struct timespec rqts, rmts;
717 	int error, error2;
718 
719 	error = copyin(args->rqtp, &lrqts, sizeof(lrqts));
720 	if (error != 0) {
721 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error,
722 		    error);
723 		return (error);
724 	}
725 
726 	error = linux_to_native_timespec(&rqts, &lrqts);
727 	if (error != 0) {
728 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error,
729 		    error);
730 		return (error);
731 	}
732 
733 	if (args->rmtp != NULL)
734 		rmtp = &rmts;
735 	else
736 		rmtp = NULL;
737 
738 	error = linux_common_clock_nanosleep(td, args->which, args->flags,
739 	    &rqts, rmtp);
740 	if (error == EINTR && (args->flags & LINUX_TIMER_ABSTIME) == 0 &&
741 	    args->rmtp != NULL) {
742 		error2 = native_to_linux_timespec(&lrmts, rmtp);
743 		if (error2 != 0)
744 			return (error2);
745 		error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
746 		if (error2 != 0) {
747 			LIN_SDT_PROBE1(time, linux_clock_nanosleep,
748 			    copyout_error, error2);
749 			return (error2);
750 		}
751 	}
752 	return (error);
753 }
754 
755 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
756 int
757 linux_clock_nanosleep_time64(struct thread *td,
758     struct linux_clock_nanosleep_time64_args *args)
759 {
760 	struct timespec *rmtp;
761 	struct l_timespec64 lrqts, lrmts;
762 	struct timespec rqts, rmts;
763 	int error, error2;
764 
765 	error = copyin(args->rqtp, &lrqts, sizeof(lrqts));
766 	if (error != 0) {
767 		LIN_SDT_PROBE1(time, linux_clock_nanosleep_time64,
768 		    copyin_error, error);
769 		return (error);
770 	}
771 
772 	error = linux_to_native_timespec64(&rqts, &lrqts);
773 	if (error != 0) {
774 		LIN_SDT_PROBE1(time, linux_clock_nanosleep_time64,
775 		    conversion_error, error);
776 		return (error);
777 	}
778 
779 	if (args->rmtp != NULL)
780 		rmtp = &rmts;
781 	else
782 		rmtp = NULL;
783 
784 	error = linux_common_clock_nanosleep(td, args->which, args->flags,
785 	    &rqts, rmtp);
786 	if (error == EINTR && (args->flags & LINUX_TIMER_ABSTIME) == 0 &&
787 	    args->rmtp != NULL) {
788 		error2 = native_to_linux_timespec64(&lrmts, rmtp);
789 		if (error2 != 0)
790 			return (error2);
791 		error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
792 		if (error2 != 0) {
793 			LIN_SDT_PROBE1(time, linux_clock_nanosleep_time64,
794 			    copyout_error, error2);
795 			return (error2);
796 		}
797 	}
798 	return (error);
799 }
800 #endif
801