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(<p->it_interval, &ntp->it_interval); 183 if (error == 0) 184 error = native_to_linux_timespec(<p->it_value, &ntp->it_interval); 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, <p->it_interval); 194 if (error == 0) 195 error = linux_to_native_timespec(&ntp->it_value, <p->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(<s, &tp); 403 if (error != 0) 404 return (error); 405 error = copyout(<s, 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(<s, &tp); 426 if (error != 0) 427 return (error); 428 error = copyout(<s, 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, <s, 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, <s); 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, <s, 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, <s); 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(<s, &ts); 609 if (error != 0) 610 return (error); 611 error = copyout(<s, 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(<s, &ts); 632 if (error != 0) 633 return (error); 634 error = copyout(<s, 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