Home | History | Annotate | Line # | Download | only in common
linux_sched.c revision 1.29.12.1
      1 /*	$NetBSD: linux_sched.c,v 1.29.12.1 2006/05/24 15:48:27 tron 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.29.12.1 2006/05/24 15:48:27 tron 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/sa.h>
     54 #include <sys/syscallargs.h>
     55 #include <sys/wait.h>
     56 #include <sys/kauth.h>
     57 
     58 #include <machine/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 
     65 #include <compat/linux/linux_syscallargs.h>
     66 
     67 #include <compat/linux/common/linux_sched.h>
     68 
     69 int
     70 linux_sys_clone(l, v, retval)
     71 	struct lwp *l;
     72 	void *v;
     73 	register_t *retval;
     74 {
     75 	struct linux_sys_clone_args /* {
     76 		syscallarg(int) flags;
     77 		syscallarg(void *) stack;
     78 #ifdef LINUX_NPTL
     79 		syscallarg(void *) parent_tidptr;
     80 		syscallarg(void *) child_tidptr;
     81 #endif
     82 	} */ *uap = v;
     83 	int flags, sig;
     84 	int error;
     85 #ifdef LINUX_NPTL
     86 	struct linux_emuldata *led;
     87 #endif
     88 
     89 	/*
     90 	 * We don't support the Linux CLONE_PID or CLONE_PTRACE flags.
     91 	 */
     92 	if (SCARG(uap, flags) & (LINUX_CLONE_PID|LINUX_CLONE_PTRACE))
     93 		return (EINVAL);
     94 
     95 	/*
     96 	 * Thread group implies shared signals. Shared signals
     97 	 * imply shared VM. This matches what Linux kernel does.
     98 	 */
     99 	if (SCARG(uap, flags) & LINUX_CLONE_THREAD
    100 	    && (SCARG(uap, flags) & LINUX_CLONE_SIGHAND) == 0)
    101 		return (EINVAL);
    102 	if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND
    103 	    && (SCARG(uap, flags) & LINUX_CLONE_VM) == 0)
    104 		return (EINVAL);
    105 
    106 	flags = 0;
    107 
    108 	if (SCARG(uap, flags) & LINUX_CLONE_VM)
    109 		flags |= FORK_SHAREVM;
    110 	if (SCARG(uap, flags) & LINUX_CLONE_FS)
    111 		flags |= FORK_SHARECWD;
    112 	if (SCARG(uap, flags) & LINUX_CLONE_FILES)
    113 		flags |= FORK_SHAREFILES;
    114 	if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND)
    115 		flags |= FORK_SHARESIGS;
    116 	if (SCARG(uap, flags) & LINUX_CLONE_VFORK)
    117 		flags |= FORK_PPWAIT;
    118 
    119 	/* Thread should not issue a SIGCHLD on termination */
    120 	if (SCARG(uap, flags) & LINUX_CLONE_THREAD) {
    121 		sig = 0;
    122 	} else {
    123 		sig = SCARG(uap, flags) & LINUX_CLONE_CSIGNAL;
    124 		if (sig < 0 || sig >= LINUX__NSIG)
    125 			return (EINVAL);
    126 		sig = linux_to_native_signo[sig];
    127 	}
    128 
    129 #ifdef LINUX_NPTL
    130 	led = (struct linux_emuldata *)l->l_proc->p_emuldata;
    131 
    132 	if (SCARG(uap, flags) & LINUX_CLONE_PARENT_SETTID) {
    133 		if (SCARG(uap, parent_tidptr) == NULL) {
    134 			printf("linux_sys_clone: NULL parent_tidptr\n");
    135 			return EINVAL;
    136 		}
    137 
    138 		if ((error = copyout(&l->l_proc->p_pid,
    139 		    SCARG(uap, parent_tidptr),
    140 		    sizeof(l->l_proc->p_pid))) != 0)
    141 			return error;
    142 	}
    143 
    144 	/* CLONE_CHILD_CLEARTID: TID clear in the child on exit() */
    145 	if (SCARG(uap, flags) & LINUX_CLONE_CHILD_CLEARTID)
    146 		led->child_clear_tid = SCARG(uap, child_tidptr);
    147 	else
    148 		led->child_clear_tid = NULL;
    149 
    150 	/* CLONE_CHILD_SETTID: TID set in the child on clone() */
    151 	if (SCARG(uap, flags) & LINUX_CLONE_CHILD_SETTID)
    152 		led->child_set_tid = SCARG(uap, child_tidptr);
    153 	else
    154 		led->child_set_tid = NULL;
    155 
    156 	/* CLONE_SETTLS: new Thread Local Storage in the child */
    157 	if (SCARG(uap, flags) & LINUX_CLONE_SETTLS)
    158 		led->set_tls = linux_get_newtls(l);
    159 	else
    160 		led->set_tls = 0;
    161 #endif /* LINUX_NPTL */
    162 	/*
    163 	 * Note that Linux does not provide a portable way of specifying
    164 	 * the stack area; the caller must know if the stack grows up
    165 	 * or down.  So, we pass a stack size of 0, so that the code
    166 	 * that makes this adjustment is a noop.
    167 	 */
    168 	if ((error = fork1(l, flags, sig, SCARG(uap, stack), 0,
    169 	    NULL, NULL, retval, NULL)) != 0)
    170 		return error;
    171 
    172 	return 0;
    173 }
    174 
    175 int
    176 linux_sys_sched_setparam(cl, v, retval)
    177 	struct lwp *cl;
    178 	void *v;
    179 	register_t *retval;
    180 {
    181 	struct linux_sys_sched_setparam_args /* {
    182 		syscallarg(linux_pid_t) pid;
    183 		syscallarg(const struct linux_sched_param *) sp;
    184 	} */ *uap = v;
    185 	struct proc *cp = cl->l_proc;
    186 	int error;
    187 	struct linux_sched_param lp;
    188 	struct proc *p;
    189 
    190 /*
    191  * We only check for valid parameters and return afterwards.
    192  */
    193 
    194 	if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
    195 		return EINVAL;
    196 
    197 	error = copyin(SCARG(uap, sp), &lp, sizeof(lp));
    198 	if (error)
    199 		return error;
    200 
    201 	if (SCARG(uap, pid) != 0) {
    202 		kauth_cred_t pc = cp->p_cred;
    203 
    204 		if ((p = pfind(SCARG(uap, pid))) == NULL)
    205 			return ESRCH;
    206 		if (!(cp == p ||
    207 		      kauth_cred_geteuid(pc) == 0 ||
    208 		      kauth_cred_getuid(pc) == kauth_cred_getuid(p->p_cred) ||
    209 		      kauth_cred_geteuid(pc) == kauth_cred_getuid(p->p_cred) ||
    210 		      kauth_cred_getuid(pc) == kauth_cred_geteuid(p->p_cred) ||
    211 		      kauth_cred_geteuid(pc) == kauth_cred_geteuid(p->p_cred)))
    212 			return EPERM;
    213 	}
    214 
    215 	return 0;
    216 }
    217 
    218 int
    219 linux_sys_sched_getparam(cl, v, retval)
    220 	struct lwp *cl;
    221 	void *v;
    222 	register_t *retval;
    223 {
    224 	struct linux_sys_sched_getparam_args /* {
    225 		syscallarg(linux_pid_t) pid;
    226 		syscallarg(struct linux_sched_param *) sp;
    227 	} */ *uap = v;
    228 	struct proc *cp = cl->l_proc;
    229 	struct proc *p;
    230 	struct linux_sched_param lp;
    231 
    232 /*
    233  * We only check for valid parameters and return a dummy priority afterwards.
    234  */
    235 	if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
    236 		return EINVAL;
    237 
    238 	if (SCARG(uap, pid) != 0) {
    239 		kauth_cred_t pc = cp->p_cred;
    240 
    241 		if ((p = pfind(SCARG(uap, pid))) == NULL)
    242 			return ESRCH;
    243 		if (!(cp == p ||
    244 		      kauth_cred_geteuid(pc) == 0 ||
    245 		      kauth_cred_getuid(pc) == kauth_cred_getuid(p->p_cred) ||
    246 		      kauth_cred_geteuid(pc) == kauth_cred_getuid(p->p_cred) ||
    247 		      kauth_cred_getuid(pc) == kauth_cred_geteuid(p->p_cred) ||
    248 		      kauth_cred_geteuid(pc) == kauth_cred_geteuid(p->p_cred)))
    249 			return EPERM;
    250 	}
    251 
    252 	lp.sched_priority = 0;
    253 	return copyout(&lp, SCARG(uap, sp), sizeof(lp));
    254 }
    255 
    256 int
    257 linux_sys_sched_setscheduler(cl, v, retval)
    258 	struct lwp *cl;
    259 	void *v;
    260 	register_t *retval;
    261 {
    262 	struct linux_sys_sched_setscheduler_args /* {
    263 		syscallarg(linux_pid_t) pid;
    264 		syscallarg(int) policy;
    265 		syscallarg(cont struct linux_sched_scheduler *) sp;
    266 	} */ *uap = v;
    267 	struct proc *cp = cl->l_proc;
    268 	int error;
    269 	struct linux_sched_param lp;
    270 	struct proc *p;
    271 
    272 /*
    273  * We only check for valid parameters and return afterwards.
    274  */
    275 
    276 	if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
    277 		return EINVAL;
    278 
    279 	error = copyin(SCARG(uap, sp), &lp, sizeof(lp));
    280 	if (error)
    281 		return error;
    282 
    283 	if (SCARG(uap, pid) != 0) {
    284 		kauth_cred_t pc = cp->p_cred;
    285 
    286 		if ((p = pfind(SCARG(uap, pid))) == NULL)
    287 			return ESRCH;
    288 		if (!(cp == p ||
    289 		      kauth_cred_geteuid(pc) == 0 ||
    290 		      kauth_cred_getuid(pc) == kauth_cred_getuid(p->p_cred) ||
    291 		      kauth_cred_geteuid(pc) == kauth_cred_getuid(p->p_cred) ||
    292 		      kauth_cred_getuid(pc) == kauth_cred_geteuid(p->p_cred) ||
    293 		      kauth_cred_geteuid(pc) == kauth_cred_geteuid(p->p_cred)))
    294 			return EPERM;
    295 	}
    296 
    297 /*
    298  * We can't emulate anything put the default scheduling policy.
    299  */
    300 	if (SCARG(uap, policy) != LINUX_SCHED_OTHER || lp.sched_priority != 0)
    301 		return EINVAL;
    302 
    303 	return 0;
    304 }
    305 
    306 int
    307 linux_sys_sched_getscheduler(cl, v, retval)
    308 	struct lwp *cl;
    309 	void *v;
    310 	register_t *retval;
    311 {
    312 	struct linux_sys_sched_getscheduler_args /* {
    313 		syscallarg(linux_pid_t) pid;
    314 	} */ *uap = v;
    315 	struct proc *cp = cl->l_proc;
    316 	struct proc *p;
    317 
    318 	*retval = -1;
    319 /*
    320  * We only check for valid parameters and return afterwards.
    321  */
    322 
    323 	if (SCARG(uap, pid) != 0) {
    324 		kauth_cred_t pc = cp->p_cred;
    325 
    326 		if ((p = pfind(SCARG(uap, pid))) == NULL)
    327 			return ESRCH;
    328 		if (!(cp == p ||
    329 		      kauth_cred_geteuid(pc) == 0 ||
    330 		      kauth_cred_getuid(pc) == kauth_cred_getuid(p->p_cred) ||
    331 		      kauth_cred_geteuid(pc) == kauth_cred_getuid(p->p_cred) ||
    332 		      kauth_cred_getuid(pc) == kauth_cred_geteuid(p->p_cred) ||
    333 		      kauth_cred_geteuid(pc) == kauth_cred_geteuid(p->p_cred)))
    334 			return EPERM;
    335 	}
    336 
    337 /*
    338  * We can't emulate anything put the default scheduling policy.
    339  */
    340 	*retval = LINUX_SCHED_OTHER;
    341 	return 0;
    342 }
    343 
    344 int
    345 linux_sys_sched_yield(cl, v, retval)
    346 	struct lwp *cl;
    347 	void *v;
    348 	register_t *retval;
    349 {
    350 
    351 	yield();
    352 	return 0;
    353 }
    354 
    355 int
    356 linux_sys_sched_get_priority_max(cl, v, retval)
    357 	struct lwp *cl;
    358 	void *v;
    359 	register_t *retval;
    360 {
    361 	struct linux_sys_sched_get_priority_max_args /* {
    362 		syscallarg(int) policy;
    363 	} */ *uap = v;
    364 
    365 /*
    366  * We can't emulate anything put the default scheduling policy.
    367  */
    368 	if (SCARG(uap, policy) != LINUX_SCHED_OTHER) {
    369 		*retval = -1;
    370 		return EINVAL;
    371 	}
    372 
    373 	*retval = 0;
    374 	return 0;
    375 }
    376 
    377 int
    378 linux_sys_sched_get_priority_min(cl, v, retval)
    379 	struct lwp *cl;
    380 	void *v;
    381 	register_t *retval;
    382 {
    383 	struct linux_sys_sched_get_priority_min_args /* {
    384 		syscallarg(int) policy;
    385 	} */ *uap = v;
    386 
    387 /*
    388  * We can't emulate anything put the default scheduling policy.
    389  */
    390 	if (SCARG(uap, policy) != LINUX_SCHED_OTHER) {
    391 		*retval = -1;
    392 		return EINVAL;
    393 	}
    394 
    395 	*retval = 0;
    396 	return 0;
    397 }
    398 
    399 #ifndef __m68k__
    400 /* Present on everything but m68k */
    401 int
    402 linux_sys_exit_group(l, v, retval)
    403 	struct lwp *l;
    404 	void *v;
    405 	register_t *retval;
    406 {
    407 	struct linux_sys_exit_group_args /* {
    408 		syscallarg(int) error_code;
    409 	} */ *uap = v;
    410 
    411 	/*
    412 	 * XXX The calling thread is supposed to kill all threads
    413 	 * in the same thread group (i.e. all threads created
    414 	 * via clone(2) with CLONE_THREAD flag set). This appears
    415 	 * to not be used yet, so the thread group handling
    416 	 * is currently not implemented.
    417 	 */
    418 
    419 	exit1(l, W_EXITCODE(SCARG(uap, error_code), 0));
    420 	/* NOTREACHED */
    421 	return 0;
    422 }
    423 #endif /* !__m68k__ */
    424 
    425 #ifdef LINUX_NPTL
    426 int
    427 linux_sys_set_tid_address(l, v, retval)
    428 	struct lwp *l;
    429 	void *v;
    430 	register_t *retval;
    431 {
    432 	struct linux_sys_set_tid_address_args /* {
    433 		syscallarg(int *) tidptr;
    434 	} */ *uap = v;
    435 	struct linux_emuldata *led;
    436 
    437 	led = (struct linux_emuldata *)l->l_proc->p_emuldata;
    438 	led->clear_tid = SCARG(uap, tid);
    439 
    440 	*retval = l->l_proc->p_pid;
    441 
    442 	return 0;
    443 }
    444 
    445 /* ARGUSED1 */
    446 int
    447 linux_sys_gettid(l, v, retval)
    448 	struct lwp *l;
    449 	void *v;
    450 	register_t *retval;
    451 {
    452 	*retval = l->l_proc->p_pid;
    453 	return 0;
    454 }
    455 
    456 int
    457 linux_sys_sched_getaffinity(l, v, retval)
    458 	struct lwp *l;
    459 	void *v;
    460 	register_t *retval;
    461 {
    462 	struct linux_sys_sched_getaffinity_args /* {
    463 		syscallarg(pid_t) pid;
    464 		syscallarg(unsigned int) len;
    465 		syscallarg(unsigned long *) mask;
    466 	} */ *uap = v;
    467 	int error;
    468 	int ret;
    469 	int ncpu;
    470 	int name[2];
    471 	size_t sz;
    472 	char *data;
    473 	int *retp;
    474 
    475 	if (SCARG(uap, mask) == NULL)
    476 		return EINVAL;
    477 
    478 	if (SCARG(uap, len) < sizeof(int))
    479 		return EINVAL;
    480 
    481 	if (pfind(SCARG(uap, pid)) == NULL)
    482 		return ESRCH;
    483 
    484 	/*
    485 	 * return the actual number of CPU, tag all of them as available
    486 	 * The result is a mask, the first CPU being in the least significant
    487 	 * bit.
    488 	 */
    489 	name[0] = CTL_HW;
    490 	name[1] = HW_NCPU;
    491 	sz = sizeof(ncpu);
    492 
    493 	if ((error = old_sysctl(&name[0], 2, &ncpu, &sz, NULL, 0, NULL)) != 0)
    494 		return error;
    495 
    496 	ret = (1 << ncpu) - 1;
    497 
    498 	data = malloc(SCARG(uap, len), M_TEMP, M_WAITOK|M_ZERO);
    499 	retp = (int *)&data[SCARG(uap, len) - sizeof(ret)];
    500 	*retp = ret;
    501 
    502 	if ((error = copyout(data, SCARG(uap, mask), SCARG(uap, len))) != 0)
    503 		return error;
    504 
    505 	free(data, M_TEMP);
    506 
    507 	return 0;
    508 
    509 }
    510 
    511 int
    512 linux_sys_sched_setaffinity(l, v, retval)
    513 	struct lwp *l;
    514 	void *v;
    515 	register_t *retval;
    516 {
    517 	struct linux_sys_sched_setaffinity_args /* {
    518 		syscallarg(pid_t) pid;
    519 		syscallarg(unsigned int) len;
    520 		syscallarg(unsigned long *) mask;
    521 	} */ *uap = v;
    522 
    523 	if (pfind(SCARG(uap, pid)) == NULL)
    524 		return ESRCH;
    525 
    526 	/* Let's ignore it */
    527 #ifdef DEBUG_LINUX
    528 	printf("linux_sys_sched_setaffinity\n");
    529 #endif
    530 	return 0;
    531 };
    532 #endif /* LINUX_NPTL */
    533