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