1 /* $NetBSD: linux_sched.c,v 1.47 2008/01/23 15:04:39 elad Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center; by Matthias Scheler. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Linux compatibility module. Try to deal with scheduler related syscalls. 42 */ 43 44 #include <sys/cdefs.h> 45 __KERNEL_RCSID(0, "$NetBSD: linux_sched.c,v 1.47 2008/01/23 15:04:39 elad Exp $"); 46 47 #include <sys/param.h> 48 #include <sys/mount.h> 49 #include <sys/proc.h> 50 #include <sys/systm.h> 51 #include <sys/sysctl.h> 52 #include <sys/malloc.h> 53 #include <sys/syscallargs.h> 54 #include <sys/wait.h> 55 #include <sys/kauth.h> 56 #include <sys/ptrace.h> 57 58 #include <sys/cpu.h> 59 60 #include <compat/linux/common/linux_types.h> 61 #include <compat/linux/common/linux_signal.h> 62 #include <compat/linux/common/linux_machdep.h> /* For LINUX_NPTL */ 63 #include <compat/linux/common/linux_emuldata.h> 64 #include <compat/linux/common/linux_ipc.h> 65 #include <compat/linux/common/linux_sem.h> 66 67 #include <compat/linux/linux_syscallargs.h> 68 69 #include <compat/linux/common/linux_sched.h> 70 71 int 72 linux_sys_clone(struct lwp *l, const struct linux_sys_clone_args *uap, register_t *retval) 73 { 74 /* { 75 syscallarg(int) flags; 76 syscallarg(void *) stack; 77 #ifdef LINUX_NPTL 78 syscallarg(void *) parent_tidptr; 79 syscallarg(void *) child_tidptr; 80 #endif 81 } */ 82 int flags, sig; 83 int error; 84 #ifdef LINUX_NPTL 85 struct linux_emuldata *led; 86 #endif 87 88 /* 89 * We don't support the Linux CLONE_PID or CLONE_PTRACE flags. 90 */ 91 if (SCARG(uap, flags) & (LINUX_CLONE_PID|LINUX_CLONE_PTRACE)) 92 return (EINVAL); 93 94 /* 95 * Thread group implies shared signals. Shared signals 96 * imply shared VM. This matches what Linux kernel does. 97 */ 98 if (SCARG(uap, flags) & LINUX_CLONE_THREAD 99 && (SCARG(uap, flags) & LINUX_CLONE_SIGHAND) == 0) 100 return (EINVAL); 101 if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND 102 && (SCARG(uap, flags) & LINUX_CLONE_VM) == 0) 103 return (EINVAL); 104 105 flags = 0; 106 107 if (SCARG(uap, flags) & LINUX_CLONE_VM) 108 flags |= FORK_SHAREVM; 109 if (SCARG(uap, flags) & LINUX_CLONE_FS) 110 flags |= FORK_SHARECWD; 111 if (SCARG(uap, flags) & LINUX_CLONE_FILES) 112 flags |= FORK_SHAREFILES; 113 if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND) 114 flags |= FORK_SHARESIGS; 115 if (SCARG(uap, flags) & LINUX_CLONE_VFORK) 116 flags |= FORK_PPWAIT; 117 118 sig = SCARG(uap, flags) & LINUX_CLONE_CSIGNAL; 119 if (sig < 0 || sig >= LINUX__NSIG) 120 return (EINVAL); 121 sig = linux_to_native_signo[sig]; 122 123 #ifdef LINUX_NPTL 124 led = (struct linux_emuldata *)l->l_proc->p_emuldata; 125 126 led->parent_tidptr = SCARG(uap, parent_tidptr); 127 led->child_tidptr = SCARG(uap, child_tidptr); 128 led->clone_flags = SCARG(uap, flags); 129 #endif /* LINUX_NPTL */ 130 131 /* 132 * Note that Linux does not provide a portable way of specifying 133 * the stack area; the caller must know if the stack grows up 134 * or down. So, we pass a stack size of 0, so that the code 135 * that makes this adjustment is a noop. 136 */ 137 if ((error = fork1(l, flags, sig, SCARG(uap, stack), 0, 138 NULL, NULL, retval, NULL)) != 0) 139 return error; 140 141 return 0; 142 } 143 144 int 145 linux_sys_sched_setparam(struct lwp *l, const struct linux_sys_sched_setparam_args *uap, register_t *retval) 146 { 147 /* { 148 syscallarg(linux_pid_t) pid; 149 syscallarg(const struct linux_sched_param *) sp; 150 } */ 151 int error; 152 struct linux_sched_param lp; 153 struct proc *p; 154 155 /* 156 * We only check for valid parameters and return afterwards. 157 */ 158 159 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL) 160 return EINVAL; 161 162 error = copyin(SCARG(uap, sp), &lp, sizeof(lp)); 163 if (error) 164 return error; 165 166 if (SCARG(uap, pid) != 0) { 167 if ((p = pfind(SCARG(uap, pid))) == NULL) 168 return ESRCH; 169 170 if (l->l_proc != p && 171 kauth_authorize_process(l->l_cred, KAUTH_PROCESS_SCHEDULER, 172 p, KAUTH_ARG(KAUTH_REQ_PROCESS_SCHEDULER_SETPARAM), NULL, 173 &lp) != 0) 174 return EPERM; 175 } 176 177 return 0; 178 } 179 180 int 181 linux_sys_sched_getparam(struct lwp *l, const struct linux_sys_sched_getparam_args *uap, register_t *retval) 182 { 183 /* { 184 syscallarg(linux_pid_t) pid; 185 syscallarg(struct linux_sched_param *) sp; 186 } */ 187 struct proc *p; 188 struct linux_sched_param lp; 189 190 /* 191 * We only check for valid parameters and return a dummy priority afterwards. 192 */ 193 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL) 194 return EINVAL; 195 196 if (SCARG(uap, pid) != 0) { 197 if ((p = pfind(SCARG(uap, pid))) == NULL) 198 return ESRCH; 199 200 if (l->l_proc != p && 201 kauth_authorize_process(l->l_cred, KAUTH_PROCESS_SCHEDULER, 202 p, KAUTH_ARG(KAUTH_REQ_PROCESS_SCHEDULER_GETPARAM), NULL, 203 NULL) != 0) 204 return EPERM; 205 } 206 207 lp.sched_priority = 0; 208 return copyout(&lp, SCARG(uap, sp), sizeof(lp)); 209 } 210 211 int 212 linux_sys_sched_setscheduler(struct lwp *l, const struct linux_sys_sched_setscheduler_args *uap, register_t *retval) 213 { 214 /* { 215 syscallarg(linux_pid_t) pid; 216 syscallarg(int) policy; 217 syscallarg(cont struct linux_sched_scheduler *) sp; 218 } */ 219 int error; 220 struct linux_sched_param lp; 221 struct proc *p; 222 223 /* 224 * We only check for valid parameters and return afterwards. 225 */ 226 227 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL) 228 return EINVAL; 229 230 error = copyin(SCARG(uap, sp), &lp, sizeof(lp)); 231 if (error) 232 return error; 233 234 if (SCARG(uap, pid) != 0) { 235 if ((p = pfind(SCARG(uap, pid))) == NULL) 236 return ESRCH; 237 238 if (l->l_proc != p && 239 kauth_authorize_process(l->l_cred, KAUTH_PROCESS_SCHEDULER, 240 p, KAUTH_ARG(KAUTH_REQ_PROCESS_SCHEDULER_SET), 241 KAUTH_ARG(SCARG(uap, policy)), &lp) != 0) 242 return EPERM; 243 } 244 245 return 0; 246 /* 247 * We can't emulate anything put the default scheduling policy. 248 */ 249 if (SCARG(uap, policy) != LINUX_SCHED_OTHER || lp.sched_priority != 0) 250 return EINVAL; 251 252 return 0; 253 } 254 255 int 256 linux_sys_sched_getscheduler(struct lwp *l, const struct linux_sys_sched_getscheduler_args *uap, register_t *retval) 257 { 258 /* { 259 syscallarg(linux_pid_t) pid; 260 } */ 261 struct proc *p; 262 263 *retval = -1; 264 /* 265 * We only check for valid parameters and return afterwards. 266 */ 267 268 if (SCARG(uap, pid) != 0) { 269 if ((p = pfind(SCARG(uap, pid))) == NULL) 270 return ESRCH; 271 272 if (l->l_proc != p && 273 kauth_authorize_process(l->l_cred, KAUTH_PROCESS_SCHEDULER, 274 p, KAUTH_ARG(KAUTH_REQ_PROCESS_SCHEDULER_GET), NULL, 275 NULL) != 0) 276 return EPERM; 277 } 278 279 /* 280 * We can't emulate anything put the default scheduling policy. 281 */ 282 *retval = LINUX_SCHED_OTHER; 283 return 0; 284 } 285 286 int 287 linux_sys_sched_yield(struct lwp *l, const void *v, register_t *retval) 288 { 289 290 yield(); 291 return 0; 292 } 293 294 int 295 linux_sys_sched_get_priority_max(struct lwp *l, const struct linux_sys_sched_get_priority_max_args *uap, register_t *retval) 296 { 297 /* { 298 syscallarg(int) policy; 299 } */ 300 301 /* 302 * We can't emulate anything put the default scheduling policy. 303 */ 304 if (SCARG(uap, policy) != LINUX_SCHED_OTHER) { 305 *retval = -1; 306 return EINVAL; 307 } 308 309 *retval = 0; 310 return 0; 311 } 312 313 int 314 linux_sys_sched_get_priority_min(struct lwp *l, const struct linux_sys_sched_get_priority_min_args *uap, register_t *retval) 315 { 316 /* { 317 syscallarg(int) policy; 318 } */ 319 320 /* 321 * We can't emulate anything put the default scheduling policy. 322 */ 323 if (SCARG(uap, policy) != LINUX_SCHED_OTHER) { 324 *retval = -1; 325 return EINVAL; 326 } 327 328 *retval = 0; 329 return 0; 330 } 331 332 #ifndef __m68k__ 333 /* Present on everything but m68k */ 334 int 335 linux_sys_exit_group(struct lwp *l, const struct linux_sys_exit_group_args *uap, register_t *retval) 336 { 337 #ifdef LINUX_NPTL 338 /* { 339 syscallarg(int) error_code; 340 } */ 341 struct proc *p = l->l_proc; 342 struct linux_emuldata *led = p->p_emuldata; 343 struct linux_emuldata *e; 344 345 if (led->s->flags & LINUX_LES_USE_NPTL) { 346 347 #ifdef DEBUG_LINUX 348 printf("%s:%d, led->s->refs = %d\n", __func__, __LINE__, 349 led->s->refs); 350 #endif 351 352 /* 353 * The calling thread is supposed to kill all threads 354 * in the same thread group (i.e. all threads created 355 * via clone(2) with CLONE_THREAD flag set). 356 * 357 * If there is only one thread, things are quite simple 358 */ 359 if (led->s->refs == 1) 360 return sys_exit(l, (const void *)uap, retval); 361 362 #ifdef DEBUG_LINUX 363 printf("%s:%d\n", __func__, __LINE__); 364 #endif 365 366 led->s->flags |= LINUX_LES_INEXITGROUP; 367 led->s->xstat = W_EXITCODE(SCARG(uap, error_code), 0); 368 369 /* 370 * Kill all threads in the group. The emulation exit hook takes 371 * care of hiding the zombies and reporting the exit code 372 * properly. 373 */ 374 mutex_enter(&proclist_mutex); 375 LIST_FOREACH(e, &led->s->threads, threads) { 376 if (e->proc == p) 377 continue; 378 379 #ifdef DEBUG_LINUX 380 printf("%s: kill PID %d\n", __func__, e->proc->p_pid); 381 #endif 382 psignal(e->proc, SIGKILL); 383 } 384 385 /* Now, kill ourselves */ 386 psignal(p, SIGKILL); 387 mutex_exit(&proclist_mutex); 388 389 return 0; 390 391 } 392 #endif /* LINUX_NPTL */ 393 394 return sys_exit(l, (const void *)uap, retval); 395 } 396 #endif /* !__m68k__ */ 397 398 #ifdef LINUX_NPTL 399 int 400 linux_sys_set_tid_address(struct lwp *l, const struct linux_sys_set_tid_address_args *uap, register_t *retval) 401 { 402 /* { 403 syscallarg(int *) tidptr; 404 } */ 405 struct linux_emuldata *led; 406 407 led = (struct linux_emuldata *)l->l_proc->p_emuldata; 408 led->clear_tid = SCARG(uap, tid); 409 410 led->s->flags |= LINUX_LES_USE_NPTL; 411 412 *retval = l->l_proc->p_pid; 413 414 return 0; 415 } 416 417 /* ARGUSED1 */ 418 int 419 linux_sys_gettid(struct lwp *l, const void *v, register_t *retval) 420 { 421 /* The Linux kernel does it exactly that way */ 422 *retval = l->l_proc->p_pid; 423 return 0; 424 } 425 426 #ifdef LINUX_NPTL 427 /* ARGUSED1 */ 428 int 429 linux_sys_getpid(struct lwp *l, const void *v, register_t *retval) 430 { 431 struct linux_emuldata *led = l->l_proc->p_emuldata; 432 433 if (led->s->flags & LINUX_LES_USE_NPTL) { 434 /* The Linux kernel does it exactly that way */ 435 *retval = led->s->group_pid; 436 } else { 437 *retval = l->l_proc->p_pid; 438 } 439 440 return 0; 441 } 442 443 /* ARGUSED1 */ 444 int 445 linux_sys_getppid(struct lwp *l, const void *v, register_t *retval) 446 { 447 struct proc *p = l->l_proc; 448 struct linux_emuldata *led = p->p_emuldata; 449 struct proc *glp; 450 struct proc *pp; 451 452 if (led->s->flags & LINUX_LES_USE_NPTL) { 453 454 /* Find the thread group leader's parent */ 455 if ((glp = pfind(led->s->group_pid)) == NULL) { 456 /* Maybe panic... */ 457 printf("linux_sys_getppid: missing group leader PID" 458 " %d\n", led->s->group_pid); 459 return -1; 460 } 461 pp = glp->p_pptr; 462 463 /* If this is a Linux process too, return thread group PID */ 464 if (pp->p_emul == p->p_emul) { 465 struct linux_emuldata *pled; 466 467 pled = pp->p_emuldata; 468 *retval = pled->s->group_pid; 469 } else { 470 *retval = pp->p_pid; 471 } 472 473 } else { 474 *retval = p->p_pptr->p_pid; 475 } 476 477 return 0; 478 } 479 #endif /* LINUX_NPTL */ 480 481 int 482 linux_sys_sched_getaffinity(struct lwp *l, const struct linux_sys_sched_getaffinity_args *uap, register_t *retval) 483 { 484 /* { 485 syscallarg(pid_t) pid; 486 syscallarg(unsigned int) len; 487 syscallarg(unsigned long *) mask; 488 } */ 489 int error; 490 int ret; 491 char *data; 492 int *retp; 493 494 if (SCARG(uap, mask) == NULL) 495 return EINVAL; 496 497 if (SCARG(uap, len) < sizeof(int)) 498 return EINVAL; 499 500 if (pfind(SCARG(uap, pid)) == NULL) 501 return ESRCH; 502 503 /* 504 * return the actual number of CPU, tag all of them as available 505 * The result is a mask, the first CPU being in the least significant 506 * bit. 507 */ 508 ret = (1 << ncpu) - 1; 509 data = malloc(SCARG(uap, len), M_TEMP, M_WAITOK|M_ZERO); 510 retp = (int *)&data[SCARG(uap, len) - sizeof(ret)]; 511 *retp = ret; 512 513 if ((error = copyout(data, SCARG(uap, mask), SCARG(uap, len))) != 0) 514 return error; 515 516 free(data, M_TEMP); 517 518 return 0; 519 520 } 521 522 int 523 linux_sys_sched_setaffinity(struct lwp *l, const struct linux_sys_sched_setaffinity_args *uap, register_t *retval) 524 { 525 /* { 526 syscallarg(pid_t) pid; 527 syscallarg(unsigned int) len; 528 syscallarg(unsigned long *) mask; 529 } */ 530 531 if (pfind(SCARG(uap, pid)) == NULL) 532 return ESRCH; 533 534 /* Let's ignore it */ 535 #ifdef DEBUG_LINUX 536 printf("linux_sys_sched_setaffinity\n"); 537 #endif 538 return 0; 539 }; 540 #endif /* LINUX_NPTL */ 541