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 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(<p->it_interval, &ntp->it_interval); 164 if (error == 0) 165 error = native_to_linux_timespec(<p->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, <p->it_interval); 175 if (error == 0) 176 error = linux_to_native_timespec(&ntp->it_value, <p->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 case LINUX_CLOCK_MONOTONIC_RAW: 218 *n = CLOCK_MONOTONIC_FAST; 219 break; 220 case LINUX_CLOCK_BOOTTIME: 221 *n = CLOCK_UPTIME; 222 break; 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 linux_msg(curthread, 272 "unsupported clock_gettime clockid %d", args->which); 273 LIN_SDT_PROBE1(time, linux_clock_gettime, conversion_error, 274 error); 275 LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); 276 return (error); 277 } 278 279 switch (nwhich) { 280 case CLOCK_PROCESS_CPUTIME_ID: 281 if (args->which < 0) { 282 clockwhich = LINUX_CPUCLOCK_WHICH(args->which); 283 pid = LINUX_CPUCLOCK_ID(args->which); 284 } else { 285 clockwhich = LINUX_CPUCLOCK_SCHED; 286 pid = 0; 287 } 288 if (pid == 0) { 289 p = td->td_proc; 290 PROC_LOCK(p); 291 } else { 292 error = pget(pid, PGET_CANSEE, &p); 293 if (error != 0) 294 return (EINVAL); 295 } 296 switch (clockwhich) { 297 case LINUX_CPUCLOCK_PROF: 298 PROC_STATLOCK(p); 299 calcru(p, &ru.ru_utime, &ru.ru_stime); 300 PROC_STATUNLOCK(p); 301 PROC_UNLOCK(p); 302 timevaladd(&ru.ru_utime, &ru.ru_stime); 303 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp); 304 break; 305 case LINUX_CPUCLOCK_VIRT: 306 PROC_STATLOCK(p); 307 calcru(p, &ru.ru_utime, &ru.ru_stime); 308 PROC_STATUNLOCK(p); 309 PROC_UNLOCK(p); 310 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp); 311 break; 312 case LINUX_CPUCLOCK_SCHED: 313 kern_process_cputime(p, &tp); 314 PROC_UNLOCK(p); 315 break; 316 default: 317 PROC_UNLOCK(p); 318 return (EINVAL); 319 } 320 321 break; 322 323 case CLOCK_THREAD_CPUTIME_ID: 324 if (args->which < 0) { 325 clockwhich = LINUX_CPUCLOCK_WHICH(args->which); 326 tid = LINUX_CPUCLOCK_ID(args->which); 327 } else { 328 clockwhich = LINUX_CPUCLOCK_SCHED; 329 tid = 0; 330 } 331 p = td->td_proc; 332 if (tid == 0) { 333 targettd = td; 334 PROC_LOCK(p); 335 } else { 336 targettd = linux_tdfind(td, tid, p->p_pid); 337 if (targettd == NULL) 338 return (EINVAL); 339 } 340 switch (clockwhich) { 341 case LINUX_CPUCLOCK_PROF: 342 PROC_STATLOCK(p); 343 thread_lock(targettd); 344 rufetchtd(targettd, &ru); 345 thread_unlock(targettd); 346 PROC_STATUNLOCK(p); 347 PROC_UNLOCK(p); 348 timevaladd(&ru.ru_utime, &ru.ru_stime); 349 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp); 350 break; 351 case LINUX_CPUCLOCK_VIRT: 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 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp); 359 break; 360 case LINUX_CPUCLOCK_SCHED: 361 if (td == targettd) 362 targettd = NULL; 363 kern_thread_cputime(targettd, &tp); 364 PROC_UNLOCK(p); 365 break; 366 default: 367 PROC_UNLOCK(p); 368 return (EINVAL); 369 } 370 break; 371 372 default: 373 error = kern_clock_gettime(td, nwhich, &tp); 374 break; 375 } 376 if (error != 0) { 377 LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error); 378 LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); 379 return (error); 380 } 381 error = native_to_linux_timespec(<s, &tp); 382 if (error != 0) 383 return (error); 384 error = copyout(<s, args->tp, sizeof lts); 385 if (error != 0) 386 LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error); 387 388 LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); 389 return (error); 390 } 391 392 int 393 linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args) 394 { 395 struct timespec ts; 396 struct l_timespec lts; 397 int error; 398 clockid_t nwhich; 399 400 LIN_SDT_PROBE2(time, linux_clock_settime, entry, args->which, args->tp); 401 402 error = linux_to_native_clockid(&nwhich, args->which); 403 if (error != 0) { 404 linux_msg(curthread, 405 "unsupported clock_settime clockid %d", args->which); 406 LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error, 407 error); 408 LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 409 return (error); 410 } 411 error = copyin(args->tp, <s, sizeof lts); 412 if (error != 0) { 413 LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error); 414 LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 415 return (error); 416 } 417 error = linux_to_native_timespec(&ts, <s); 418 if (error != 0) { 419 LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error, 420 error); 421 LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 422 return (error); 423 } 424 425 error = kern_clock_settime(td, nwhich, &ts); 426 if (error != 0) 427 LIN_SDT_PROBE1(time, linux_clock_settime, settime_error, error); 428 429 LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 430 return (error); 431 } 432 433 int 434 linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args) 435 { 436 struct proc *p; 437 struct timespec ts; 438 struct l_timespec lts; 439 int error, clockwhich; 440 clockid_t nwhich; 441 pid_t pid; 442 lwpid_t tid; 443 444 LIN_SDT_PROBE2(time, linux_clock_getres, entry, args->which, args->tp); 445 446 error = linux_to_native_clockid(&nwhich, args->which); 447 if (error != 0) { 448 linux_msg(curthread, 449 "unsupported clock_getres clockid %d", args->which); 450 LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error, 451 error); 452 LIN_SDT_PROBE1(time, linux_clock_getres, return, error); 453 return (error); 454 } 455 456 /* 457 * Check user supplied clock id in case of per-process 458 * or thread-specific cpu-time clock. 459 */ 460 if (args->which < 0) { 461 switch (nwhich) { 462 case CLOCK_THREAD_CPUTIME_ID: 463 tid = LINUX_CPUCLOCK_ID(args->which); 464 if (tid != 0) { 465 p = td->td_proc; 466 if (linux_tdfind(td, tid, p->p_pid) == NULL) 467 return (EINVAL); 468 PROC_UNLOCK(p); 469 } 470 break; 471 case CLOCK_PROCESS_CPUTIME_ID: 472 pid = LINUX_CPUCLOCK_ID(args->which); 473 if (pid != 0) { 474 error = pget(pid, PGET_CANSEE, &p); 475 if (error != 0) 476 return (EINVAL); 477 PROC_UNLOCK(p); 478 } 479 break; 480 } 481 } 482 483 if (args->tp == NULL) { 484 LIN_SDT_PROBE0(time, linux_clock_getres, nullcall); 485 LIN_SDT_PROBE1(time, linux_clock_getres, return, 0); 486 return (0); 487 } 488 489 switch (nwhich) { 490 case CLOCK_THREAD_CPUTIME_ID: 491 case CLOCK_PROCESS_CPUTIME_ID: 492 clockwhich = LINUX_CPUCLOCK_WHICH(args->which); 493 /* 494 * In both cases (when the clock id obtained by a call to 495 * clock_getcpuclockid() or using the clock 496 * ID CLOCK_PROCESS_CPUTIME_ID Linux hardcodes precision 497 * of clock. The same for the CLOCK_THREAD_CPUTIME_ID clock. 498 * 499 * See Linux posix_cpu_clock_getres() implementation. 500 */ 501 if (args->which > 0 || clockwhich == LINUX_CPUCLOCK_SCHED) { 502 ts.tv_sec = 0; 503 ts.tv_nsec = 1; 504 goto out; 505 } 506 507 switch (clockwhich) { 508 case LINUX_CPUCLOCK_PROF: 509 nwhich = CLOCK_PROF; 510 break; 511 case LINUX_CPUCLOCK_VIRT: 512 nwhich = CLOCK_VIRTUAL; 513 break; 514 default: 515 return (EINVAL); 516 } 517 break; 518 519 default: 520 break; 521 } 522 error = kern_clock_getres(td, nwhich, &ts); 523 if (error != 0) { 524 LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error); 525 LIN_SDT_PROBE1(time, linux_clock_getres, return, error); 526 return (error); 527 } 528 529 out: 530 error = native_to_linux_timespec(<s, &ts); 531 if (error != 0) 532 return (error); 533 error = copyout(<s, args->tp, sizeof lts); 534 if (error != 0) 535 LIN_SDT_PROBE1(time, linux_clock_getres, copyout_error, error); 536 537 LIN_SDT_PROBE1(time, linux_clock_getres, return, error); 538 return (error); 539 } 540 541 int 542 linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args) 543 { 544 struct timespec *rmtp; 545 struct l_timespec lrqts, lrmts; 546 struct timespec rqts, rmts; 547 int error, error2; 548 549 LIN_SDT_PROBE2(time, linux_nanosleep, entry, args->rqtp, args->rmtp); 550 551 error = copyin(args->rqtp, &lrqts, sizeof lrqts); 552 if (error != 0) { 553 LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error); 554 LIN_SDT_PROBE1(time, linux_nanosleep, return, error); 555 return (error); 556 } 557 558 if (args->rmtp != NULL) 559 rmtp = &rmts; 560 else 561 rmtp = NULL; 562 563 error = linux_to_native_timespec(&rqts, &lrqts); 564 if (error != 0) { 565 LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error); 566 LIN_SDT_PROBE1(time, linux_nanosleep, return, error); 567 return (error); 568 } 569 error = kern_nanosleep(td, &rqts, rmtp); 570 if (error == EINTR && args->rmtp != NULL) { 571 error2 = native_to_linux_timespec(&lrmts, rmtp); 572 if (error2 != 0) 573 return (error2); 574 error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts)); 575 if (error2 != 0) { 576 LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error, 577 error2); 578 LIN_SDT_PROBE1(time, linux_nanosleep, return, error2); 579 return (error2); 580 } 581 } 582 583 LIN_SDT_PROBE1(time, linux_nanosleep, return, error); 584 return (error); 585 } 586 587 int 588 linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args) 589 { 590 struct timespec *rmtp; 591 struct l_timespec lrqts, lrmts; 592 struct timespec rqts, rmts; 593 int error, error2, flags; 594 clockid_t clockid; 595 596 LIN_SDT_PROBE4(time, linux_clock_nanosleep, entry, args->which, 597 args->flags, args->rqtp, args->rmtp); 598 599 error = linux_to_native_timerflags(&flags, args->flags); 600 if (error != 0) { 601 LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_flags, 602 args->flags); 603 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); 604 return (error); 605 } 606 607 error = linux_to_native_clockid(&clockid, args->which); 608 if (error != 0) { 609 linux_msg(curthread, 610 "unsupported clock_nanosleep clockid %d", args->which); 611 LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_clockid, 612 args->which); 613 LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 614 return (error); 615 } 616 617 error = copyin(args->rqtp, &lrqts, sizeof(lrqts)); 618 if (error != 0) { 619 LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error, 620 error); 621 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); 622 return (error); 623 } 624 625 if (args->rmtp != NULL) 626 rmtp = &rmts; 627 else 628 rmtp = NULL; 629 630 error = linux_to_native_timespec(&rqts, &lrqts); 631 if (error != 0) { 632 LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error, 633 error); 634 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); 635 return (error); 636 } 637 error = kern_clock_nanosleep(td, clockid, flags, &rqts, rmtp); 638 if (error == EINTR && (flags & TIMER_ABSTIME) == 0 && 639 args->rmtp != NULL) { 640 error2 = native_to_linux_timespec(&lrmts, rmtp); 641 if (error2 != 0) 642 return (error2); 643 error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts)); 644 if (error2 != 0) { 645 LIN_SDT_PROBE1(time, linux_clock_nanosleep, 646 copyout_error, error2); 647 LIN_SDT_PROBE1(time, linux_clock_nanosleep, 648 return, error2); 649 return (error2); 650 } 651 } 652 653 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); 654 return (error); 655 } 656