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