xref: /freebsd/sys/compat/linux/linux_time.c (revision a3557ef0)
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 
71 /* DTrace init */
72 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
73 
74 /**
75  * DTrace probes in this module.
76  */
77 LIN_SDT_PROBE_DEFINE2(time, native_to_linux_timespec, entry,
78     "struct l_timespec *", "struct timespec *");
79 LIN_SDT_PROBE_DEFINE0(time, native_to_linux_timespec, return);
80 LIN_SDT_PROBE_DEFINE2(time, linux_to_native_timespec, entry,
81     "struct timespec *", "struct l_timespec *");
82 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_timespec, return, "int");
83 LIN_SDT_PROBE_DEFINE2(time, linux_to_native_clockid, entry, "clockid_t *",
84     "clockid_t");
85 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid,
86     "clockid_t");
87 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid,
88     "clockid_t");
89 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, return, "int");
90 LIN_SDT_PROBE_DEFINE2(time, linux_clock_gettime, entry, "clockid_t",
91     "struct l_timespec *");
92 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, conversion_error, "int");
93 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int");
94 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int");
95 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, return, "int");
96 LIN_SDT_PROBE_DEFINE2(time, linux_clock_settime, entry, "clockid_t",
97     "struct l_timespec *");
98 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int");
99 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, settime_error, "int");
100 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int");
101 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, return, "int");
102 LIN_SDT_PROBE_DEFINE2(time, linux_clock_getres, entry, "clockid_t",
103     "struct l_timespec *");
104 LIN_SDT_PROBE_DEFINE0(time, linux_clock_getres, nullcall);
105 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, conversion_error, "int");
106 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, getres_error, "int");
107 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int");
108 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, return, "int");
109 LIN_SDT_PROBE_DEFINE2(time, linux_nanosleep, entry, "const struct l_timespec *",
110     "struct l_timespec *");
111 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, conversion_error, "int");
112 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int");
113 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int");
114 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, return, "int");
115 LIN_SDT_PROBE_DEFINE4(time, linux_clock_nanosleep, entry, "clockid_t", "int",
116     "struct l_timespec *", "struct l_timespec *");
117 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, conversion_error, "int");
118 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int");
119 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int");
120 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_flags, "int");
121 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_clockid, "int");
122 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, return, "int");
123 
124 
125 int
126 native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp)
127 {
128 
129 	LIN_SDT_PROBE2(time, native_to_linux_timespec, entry, ltp, ntp);
130 #ifdef COMPAT_LINUX32
131 	if (ntp->tv_sec > INT_MAX || ntp->tv_sec < INT_MIN)
132 		return (EOVERFLOW);
133 #endif
134 	ltp->tv_sec = ntp->tv_sec;
135 	ltp->tv_nsec = ntp->tv_nsec;
136 
137 	LIN_SDT_PROBE0(time, native_to_linux_timespec, return);
138 	return (0);
139 }
140 
141 int
142 linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp)
143 {
144 
145 	LIN_SDT_PROBE2(time, linux_to_native_timespec, entry, ntp, ltp);
146 
147 	if (ltp->tv_sec < 0 || ltp->tv_nsec < 0 || ltp->tv_nsec > 999999999) {
148 		LIN_SDT_PROBE1(time, linux_to_native_timespec, return, EINVAL);
149 		return (EINVAL);
150 	}
151 	ntp->tv_sec = ltp->tv_sec;
152 	ntp->tv_nsec = ltp->tv_nsec;
153 
154 	LIN_SDT_PROBE1(time, linux_to_native_timespec, return, 0);
155 	return (0);
156 }
157 
158 int
159 native_to_linux_itimerspec(struct l_itimerspec *ltp, struct itimerspec *ntp)
160 {
161 	int error;
162 
163 	error = native_to_linux_timespec(&ltp->it_interval, &ntp->it_interval);
164 	if (error == 0)
165 		error = native_to_linux_timespec(&ltp->it_value, &ntp->it_interval);
166 	return (error);
167 }
168 
169 int
170 linux_to_native_itimerspec(struct itimerspec *ntp, struct l_itimerspec *ltp)
171 {
172 	int error;
173 
174 	error = linux_to_native_timespec(&ntp->it_interval, &ltp->it_interval);
175 	if (error == 0)
176 		error = linux_to_native_timespec(&ntp->it_value, &ltp->it_value);
177 	return (error);
178 }
179 
180 int
181 linux_to_native_clockid(clockid_t *n, clockid_t l)
182 {
183 
184 	LIN_SDT_PROBE2(time, linux_to_native_clockid, entry, n, l);
185 
186 	if (l < 0) {
187 		/* cpu-clock */
188 		if ((l & LINUX_CLOCKFD_MASK) == LINUX_CLOCKFD)
189 			return (EINVAL);
190 		if (LINUX_CPUCLOCK_WHICH(l) >= LINUX_CPUCLOCK_MAX)
191 			return (EINVAL);
192 
193 		if (LINUX_CPUCLOCK_PERTHREAD(l))
194 			*n = CLOCK_THREAD_CPUTIME_ID;
195 		else
196 			*n = CLOCK_PROCESS_CPUTIME_ID;
197 		return (0);
198 	}
199 
200 	switch (l) {
201 	case LINUX_CLOCK_REALTIME:
202 		*n = CLOCK_REALTIME;
203 		break;
204 	case LINUX_CLOCK_MONOTONIC:
205 		*n = CLOCK_MONOTONIC;
206 		break;
207 	case LINUX_CLOCK_PROCESS_CPUTIME_ID:
208 		*n = CLOCK_PROCESS_CPUTIME_ID;
209 		break;
210 	case LINUX_CLOCK_THREAD_CPUTIME_ID:
211 		*n = CLOCK_THREAD_CPUTIME_ID;
212 		break;
213 	case LINUX_CLOCK_REALTIME_COARSE:
214 		*n = CLOCK_REALTIME_FAST;
215 		break;
216 	case LINUX_CLOCK_MONOTONIC_COARSE:
217 		*n = CLOCK_MONOTONIC_FAST;
218 		break;
219 	case LINUX_CLOCK_BOOTTIME:
220 		*n = CLOCK_UPTIME;
221 		break;
222 	case LINUX_CLOCK_MONOTONIC_RAW:
223 	case LINUX_CLOCK_REALTIME_ALARM:
224 	case LINUX_CLOCK_BOOTTIME_ALARM:
225 	case LINUX_CLOCK_SGI_CYCLE:
226 	case LINUX_CLOCK_TAI:
227 		LIN_SDT_PROBE1(time, linux_to_native_clockid,
228 		    unsupported_clockid, l);
229 		LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
230 		return (EINVAL);
231 	default:
232 		LIN_SDT_PROBE1(time, linux_to_native_clockid,
233 		    unknown_clockid, l);
234 		LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
235 		return (EINVAL);
236 	}
237 
238 	LIN_SDT_PROBE1(time, linux_to_native_clockid, return, 0);
239 	return (0);
240 }
241 
242 int
243 linux_to_native_timerflags(int *nflags, int flags)
244 {
245 
246 	if (flags & ~LINUX_TIMER_ABSTIME)
247 		return (EINVAL);
248 	*nflags = 0;
249 	if (flags & LINUX_TIMER_ABSTIME)
250 		*nflags |= TIMER_ABSTIME;
251 	return (0);
252 }
253 
254 int
255 linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args)
256 {
257 	struct l_timespec lts;
258 	struct timespec tp;
259 	struct rusage ru;
260 	struct thread *targettd;
261 	struct proc *p;
262 	int error, clockwhich;
263 	clockid_t nwhich;
264 	pid_t pid;
265 	lwpid_t tid;
266 
267 	LIN_SDT_PROBE2(time, linux_clock_gettime, entry, args->which, args->tp);
268 
269 	error = linux_to_native_clockid(&nwhich, args->which);
270 	if (error != 0) {
271 		LIN_SDT_PROBE1(time, linux_clock_gettime, conversion_error,
272 		    error);
273 		LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
274 		return (error);
275 	}
276 
277 	switch (nwhich) {
278 	case CLOCK_PROCESS_CPUTIME_ID:
279 		if (args->which < 0) {
280 			clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
281 			pid = LINUX_CPUCLOCK_ID(args->which);
282 		} else {
283 			clockwhich = LINUX_CPUCLOCK_SCHED;
284 			pid = 0;
285 		}
286 		if (pid == 0) {
287 			p = td->td_proc;
288 			PROC_LOCK(p);
289 		} else {
290 			error = pget(pid, PGET_CANSEE, &p);
291 			if (error != 0)
292 				return (EINVAL);
293 		}
294 		switch (clockwhich) {
295 		case LINUX_CPUCLOCK_PROF:
296 			PROC_STATLOCK(p);
297 			calcru(p, &ru.ru_utime, &ru.ru_stime);
298 			PROC_STATUNLOCK(p);
299 			PROC_UNLOCK(p);
300 			timevaladd(&ru.ru_utime, &ru.ru_stime);
301 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
302 			break;
303 		case LINUX_CPUCLOCK_VIRT:
304 			PROC_STATLOCK(p);
305 			calcru(p, &ru.ru_utime, &ru.ru_stime);
306 			PROC_STATUNLOCK(p);
307 			PROC_UNLOCK(p);
308 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
309 			break;
310 		case LINUX_CPUCLOCK_SCHED:
311 			kern_process_cputime(p, &tp);
312 			PROC_UNLOCK(p);
313 			break;
314 		default:
315 			PROC_UNLOCK(p);
316 			return (EINVAL);
317 		}
318 
319 		break;
320 
321 	case CLOCK_THREAD_CPUTIME_ID:
322 		if (args->which < 0) {
323 			clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
324 			tid = LINUX_CPUCLOCK_ID(args->which);
325 		} else {
326 			clockwhich = LINUX_CPUCLOCK_SCHED;
327 			tid = 0;
328 		}
329 		p = td->td_proc;
330 		if (tid == 0) {
331 			targettd = td;
332 			PROC_LOCK(p);
333 		} else {
334 			targettd = linux_tdfind(td, tid, p->p_pid);
335 			if (targettd == NULL)
336 				return (EINVAL);
337 		}
338 		switch (clockwhich) {
339 		case LINUX_CPUCLOCK_PROF:
340 			PROC_STATLOCK(p);
341 			thread_lock(targettd);
342 			rufetchtd(targettd, &ru);
343 			thread_unlock(targettd);
344 			PROC_STATUNLOCK(p);
345 			PROC_UNLOCK(p);
346 			timevaladd(&ru.ru_utime, &ru.ru_stime);
347 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
348 			break;
349 		case LINUX_CPUCLOCK_VIRT:
350 			PROC_STATLOCK(p);
351 			thread_lock(targettd);
352 			rufetchtd(targettd, &ru);
353 			thread_unlock(targettd);
354 			PROC_STATUNLOCK(p);
355 			PROC_UNLOCK(p);
356 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
357 			break;
358 		case LINUX_CPUCLOCK_SCHED:
359 			if (td == targettd)
360 				targettd = NULL;
361 			kern_thread_cputime(targettd, &tp);
362 			PROC_UNLOCK(p);
363 			break;
364 		default:
365 			PROC_UNLOCK(p);
366 			return (EINVAL);
367 		}
368 		break;
369 
370 	default:
371 		error = kern_clock_gettime(td, nwhich, &tp);
372 		break;
373 	}
374 	if (error != 0) {
375 		LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error);
376 		LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
377 		return (error);
378 	}
379 	error = native_to_linux_timespec(&lts, &tp);
380 	if (error != 0)
381 		return (error);
382 	error = copyout(&lts, args->tp, sizeof lts);
383 	if (error != 0)
384 		LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error);
385 
386 	LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
387 	return (error);
388 }
389 
390 int
391 linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args)
392 {
393 	struct timespec ts;
394 	struct l_timespec lts;
395 	int error;
396 	clockid_t nwhich;
397 
398 	LIN_SDT_PROBE2(time, linux_clock_settime, entry, args->which, args->tp);
399 
400 	error = linux_to_native_clockid(&nwhich, args->which);
401 	if (error != 0) {
402 		LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
403 		    error);
404 		LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
405 		return (error);
406 	}
407 	error = copyin(args->tp, &lts, sizeof lts);
408 	if (error != 0) {
409 		LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error);
410 		LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
411 		return (error);
412 	}
413 	error = linux_to_native_timespec(&ts, &lts);
414 	if (error != 0) {
415 		LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
416 		    error);
417 		LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
418 		return (error);
419 	}
420 
421 	error = kern_clock_settime(td, nwhich, &ts);
422 	if (error != 0)
423 		LIN_SDT_PROBE1(time, linux_clock_settime, settime_error, error);
424 
425 	LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
426 	return (error);
427 }
428 
429 int
430 linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args)
431 {
432 	struct proc *p;
433 	struct timespec ts;
434 	struct l_timespec lts;
435 	int error, clockwhich;
436 	clockid_t nwhich;
437 	pid_t pid;
438 	lwpid_t tid;
439 
440 	LIN_SDT_PROBE2(time, linux_clock_getres, entry, args->which, args->tp);
441 
442 	error = linux_to_native_clockid(&nwhich, args->which);
443 	if (error != 0) {
444 		LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error,
445 		    error);
446 		LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
447 		return (error);
448 	}
449 
450 	/*
451 	 * Check user supplied clock id in case of per-process
452 	 * or thread-specific cpu-time clock.
453 	 */
454 	if (args->which < 0) {
455 		switch (nwhich) {
456 		case CLOCK_THREAD_CPUTIME_ID:
457 			tid = LINUX_CPUCLOCK_ID(args->which);
458 			if (tid != 0) {
459 				p = td->td_proc;
460 				if (linux_tdfind(td, tid, p->p_pid) == NULL)
461 					return (EINVAL);
462 				PROC_UNLOCK(p);
463 			}
464 			break;
465 		case CLOCK_PROCESS_CPUTIME_ID:
466 			pid = LINUX_CPUCLOCK_ID(args->which);
467 			if (pid != 0) {
468 				error = pget(pid, PGET_CANSEE, &p);
469 				if (error != 0)
470 					return (EINVAL);
471 				PROC_UNLOCK(p);
472 			}
473 			break;
474 		}
475 	}
476 
477 	if (args->tp == NULL) {
478 		LIN_SDT_PROBE0(time, linux_clock_getres, nullcall);
479 		LIN_SDT_PROBE1(time, linux_clock_getres, return, 0);
480 		return (0);
481 	}
482 
483 	switch (nwhich) {
484 	case CLOCK_THREAD_CPUTIME_ID:
485 	case CLOCK_PROCESS_CPUTIME_ID:
486 		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
487 		/*
488 		 * In both cases (when the clock id obtained by a call to
489 		 * clock_getcpuclockid() or using the clock
490 		 * ID CLOCK_PROCESS_CPUTIME_ID Linux hardcodes precision
491 		 * of clock. The same for the CLOCK_THREAD_CPUTIME_ID clock.
492 		 *
493 		 * See Linux posix_cpu_clock_getres() implementation.
494 		 */
495 		if (args->which > 0 || clockwhich == LINUX_CPUCLOCK_SCHED) {
496 			ts.tv_sec = 0;
497 			ts.tv_nsec = 1;
498 			goto out;
499 		}
500 
501 		switch (clockwhich) {
502 		case LINUX_CPUCLOCK_PROF:
503 			nwhich = CLOCK_PROF;
504 			break;
505 		case LINUX_CPUCLOCK_VIRT:
506 			nwhich = CLOCK_VIRTUAL;
507 			break;
508 		default:
509 			return (EINVAL);
510 		}
511 		break;
512 
513 	default:
514 		break;
515 	}
516 	error = kern_clock_getres(td, nwhich, &ts);
517 	if (error != 0) {
518 		LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error);
519 		LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
520 		return (error);
521 	}
522 
523 out:
524 	error = native_to_linux_timespec(&lts, &ts);
525 	if (error != 0)
526 		return (error);
527 	error = copyout(&lts, args->tp, sizeof lts);
528 	if (error != 0)
529 		LIN_SDT_PROBE1(time, linux_clock_getres, copyout_error, error);
530 
531 	LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
532 	return (error);
533 }
534 
535 int
536 linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args)
537 {
538 	struct timespec *rmtp;
539 	struct l_timespec lrqts, lrmts;
540 	struct timespec rqts, rmts;
541 	int error, error2;
542 
543 	LIN_SDT_PROBE2(time, linux_nanosleep, entry, args->rqtp, args->rmtp);
544 
545 	error = copyin(args->rqtp, &lrqts, sizeof lrqts);
546 	if (error != 0) {
547 		LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error);
548 		LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
549 		return (error);
550 	}
551 
552 	if (args->rmtp != NULL)
553 		rmtp = &rmts;
554 	else
555 		rmtp = NULL;
556 
557 	error = linux_to_native_timespec(&rqts, &lrqts);
558 	if (error != 0) {
559 		LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error);
560 		LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
561 		return (error);
562 	}
563 	error = kern_nanosleep(td, &rqts, rmtp);
564 	if (error == EINTR && args->rmtp != NULL) {
565 		error2 = native_to_linux_timespec(&lrmts, rmtp);
566 		if (error2 != 0)
567 			return (error2);
568 		error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
569 		if (error2 != 0) {
570 			LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error,
571 			    error2);
572 			LIN_SDT_PROBE1(time, linux_nanosleep, return, error2);
573 			return (error2);
574 		}
575 	}
576 
577 	LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
578 	return (error);
579 }
580 
581 int
582 linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args)
583 {
584 	struct timespec *rmtp;
585 	struct l_timespec lrqts, lrmts;
586 	struct timespec rqts, rmts;
587 	int error, error2, flags;
588 	clockid_t clockid;
589 
590 	LIN_SDT_PROBE4(time, linux_clock_nanosleep, entry, args->which,
591 	    args->flags, args->rqtp, args->rmtp);
592 
593 	error = linux_to_native_timerflags(&flags, args->flags);
594 	if (error != 0) {
595 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_flags,
596 		    args->flags);
597 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
598 		return (error);
599 	}
600 
601 	error = linux_to_native_clockid(&clockid, args->which);
602 	if (error != 0) {
603 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_clockid,
604 		    args->which);
605 		LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
606 		return (error);
607 	}
608 
609 	error = copyin(args->rqtp, &lrqts, sizeof(lrqts));
610 	if (error != 0) {
611 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error,
612 		    error);
613 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
614 		return (error);
615 	}
616 
617 	if (args->rmtp != NULL)
618 		rmtp = &rmts;
619 	else
620 		rmtp = NULL;
621 
622 	error = linux_to_native_timespec(&rqts, &lrqts);
623 	if (error != 0) {
624 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error,
625 		    error);
626 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
627 		return (error);
628 	}
629 	error = kern_clock_nanosleep(td, clockid, flags, &rqts, rmtp);
630 	if (error == EINTR && (flags & TIMER_ABSTIME) == 0 &&
631 	    args->rmtp != NULL) {
632 		error2 = native_to_linux_timespec(&lrmts, rmtp);
633 		if (error2 != 0)
634 			return (error2);
635 		error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
636 		if (error2 != 0) {
637 			LIN_SDT_PROBE1(time, linux_clock_nanosleep,
638 			    copyout_error, error2);
639 			LIN_SDT_PROBE1(time, linux_clock_nanosleep,
640 			    return, error2);
641 			return (error2);
642 		}
643 	}
644 
645 	LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
646 	return (error);
647 }
648