Home | History | Annotate | Line # | Download | only in common
linux_sched.c revision 1.18
      1 /*	$NetBSD: linux_sched.c,v 1.18 2004/09/10 22:22:20 wiz 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.18 2004/09/10 22:22:20 wiz 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/sa.h>
     52 #include <sys/syscallargs.h>
     53 #include <sys/wait.h>
     54 
     55 #include <machine/cpu.h>
     56 
     57 #include <compat/linux/common/linux_types.h>
     58 #include <compat/linux/common/linux_signal.h>
     59 
     60 #include <compat/linux/linux_syscallargs.h>
     61 
     62 #include <compat/linux/common/linux_sched.h>
     63 
     64 int
     65 linux_sys_clone(l, v, retval)
     66 	struct lwp *l;
     67 	void *v;
     68 	register_t *retval;
     69 {
     70 	struct linux_sys_clone_args /* {
     71 		syscallarg(int) flags;
     72 		syscallarg(void *) stack;
     73 	} */ *uap = v;
     74 	int flags, sig;
     75 
     76 	/*
     77 	 * We don't support the Linux CLONE_PID or CLONE_PTRACE flags.
     78 	 */
     79 	if (SCARG(uap, flags) & (LINUX_CLONE_PID|LINUX_CLONE_PTRACE))
     80 		return (EINVAL);
     81 
     82 	/*
     83 	 * Thread group implies shared signals. Shared signals
     84 	 * imply shared VM. This matches what Linux kernel does.
     85 	 */
     86 	if (SCARG(uap, flags) & LINUX_CLONE_THREAD
     87 	    && (SCARG(uap, flags) & LINUX_CLONE_SIGHAND) == 0)
     88 		return (EINVAL);
     89 	if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND
     90 	    && (SCARG(uap, flags) & LINUX_CLONE_VM) == 0)
     91 		return (EINVAL);
     92 
     93 	flags = 0;
     94 
     95 	if (SCARG(uap, flags) & LINUX_CLONE_VM)
     96 		flags |= FORK_SHAREVM;
     97 	if (SCARG(uap, flags) & LINUX_CLONE_FS)
     98 		flags |= FORK_SHARECWD;
     99 	if (SCARG(uap, flags) & LINUX_CLONE_FILES)
    100 		flags |= FORK_SHAREFILES;
    101 	if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND)
    102 		flags |= FORK_SHARESIGS;
    103 	if (SCARG(uap, flags) & LINUX_CLONE_VFORK)
    104 		flags |= FORK_PPWAIT;
    105 
    106 	sig = SCARG(uap, flags) & LINUX_CLONE_CSIGNAL;
    107 	if (sig < 0 || sig >= LINUX__NSIG)
    108 		return (EINVAL);
    109 	sig = linux_to_native_signo[sig];
    110 
    111 	/*
    112 	 * Note that Linux does not provide a portable way of specifying
    113 	 * the stack area; the caller must know if the stack grows up
    114 	 * or down.  So, we pass a stack size of 0, so that the code
    115 	 * that makes this adjustment is a noop.
    116 	 */
    117 	return (fork1(l, flags, sig, SCARG(uap, stack), 0,
    118 	    NULL, NULL, retval, NULL));
    119 }
    120 
    121 int
    122 linux_sys_sched_setparam(cl, v, retval)
    123 	struct lwp *cl;
    124 	void *v;
    125 	register_t *retval;
    126 {
    127 	struct linux_sys_sched_setparam_args /* {
    128 		syscallarg(linux_pid_t) pid;
    129 		syscallarg(const struct linux_sched_param *) sp;
    130 	} */ *uap = v;
    131 	struct proc *cp = cl->l_proc;
    132 	int error;
    133 	struct linux_sched_param lp;
    134 	struct proc *p;
    135 
    136 /*
    137  * We only check for valid parameters and return afterwards.
    138  */
    139 
    140 	if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
    141 		return EINVAL;
    142 
    143 	error = copyin(SCARG(uap, sp), &lp, sizeof(lp));
    144 	if (error)
    145 		return error;
    146 
    147 	if (SCARG(uap, pid) != 0) {
    148 		struct pcred *pc = cp->p_cred;
    149 
    150 		if ((p = pfind(SCARG(uap, pid))) == NULL)
    151 			return ESRCH;
    152 		if (!(cp == p ||
    153 		      pc->pc_ucred->cr_uid == 0 ||
    154 		      pc->p_ruid == p->p_cred->p_ruid ||
    155 		      pc->pc_ucred->cr_uid == p->p_cred->p_ruid ||
    156 		      pc->p_ruid == p->p_ucred->cr_uid ||
    157 		      pc->pc_ucred->cr_uid == p->p_ucred->cr_uid))
    158 			return EPERM;
    159 	}
    160 
    161 	return 0;
    162 }
    163 
    164 int
    165 linux_sys_sched_getparam(cl, v, retval)
    166 	struct lwp *cl;
    167 	void *v;
    168 	register_t *retval;
    169 {
    170 	struct linux_sys_sched_getparam_args /* {
    171 		syscallarg(linux_pid_t) pid;
    172 		syscallarg(struct linux_sched_param *) sp;
    173 	} */ *uap = v;
    174 	struct proc *cp = cl->l_proc;
    175 	struct proc *p;
    176 	struct linux_sched_param lp;
    177 
    178 /*
    179  * We only check for valid parameters and return a dummy priority afterwards.
    180  */
    181 	if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
    182 		return EINVAL;
    183 
    184 	if (SCARG(uap, pid) != 0) {
    185 		struct pcred *pc = cp->p_cred;
    186 
    187 		if ((p = pfind(SCARG(uap, pid))) == NULL)
    188 			return ESRCH;
    189 		if (!(cp == p ||
    190 		      pc->pc_ucred->cr_uid == 0 ||
    191 		      pc->p_ruid == p->p_cred->p_ruid ||
    192 		      pc->pc_ucred->cr_uid == p->p_cred->p_ruid ||
    193 		      pc->p_ruid == p->p_ucred->cr_uid ||
    194 		      pc->pc_ucred->cr_uid == p->p_ucred->cr_uid))
    195 			return EPERM;
    196 	}
    197 
    198 	lp.sched_priority = 0;
    199 	return copyout(&lp, SCARG(uap, sp), sizeof(lp));
    200 }
    201 
    202 int
    203 linux_sys_sched_setscheduler(cl, v, retval)
    204 	struct lwp *cl;
    205 	void *v;
    206 	register_t *retval;
    207 {
    208 	struct linux_sys_sched_setscheduler_args /* {
    209 		syscallarg(linux_pid_t) pid;
    210 		syscallarg(int) policy;
    211 		syscallarg(cont struct linux_sched_scheduler *) sp;
    212 	} */ *uap = v;
    213 	struct proc *cp = cl->l_proc;
    214 	int error;
    215 	struct linux_sched_param lp;
    216 	struct proc *p;
    217 
    218 /*
    219  * We only check for valid parameters and return afterwards.
    220  */
    221 
    222 	if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
    223 		return EINVAL;
    224 
    225 	error = copyin(SCARG(uap, sp), &lp, sizeof(lp));
    226 	if (error)
    227 		return error;
    228 
    229 	if (SCARG(uap, pid) != 0) {
    230 		struct pcred *pc = cp->p_cred;
    231 
    232 		if ((p = pfind(SCARG(uap, pid))) == NULL)
    233 			return ESRCH;
    234 		if (!(cp == p ||
    235 		      pc->pc_ucred->cr_uid == 0 ||
    236 		      pc->p_ruid == p->p_cred->p_ruid ||
    237 		      pc->pc_ucred->cr_uid == p->p_cred->p_ruid ||
    238 		      pc->p_ruid == p->p_ucred->cr_uid ||
    239 		      pc->pc_ucred->cr_uid == p->p_ucred->cr_uid))
    240 			return EPERM;
    241 	}
    242 
    243 /*
    244  * We can't emulate anything put the default scheduling policy.
    245  */
    246 	if (SCARG(uap, policy) != LINUX_SCHED_OTHER || lp.sched_priority != 0)
    247 		return EINVAL;
    248 
    249 	return 0;
    250 }
    251 
    252 int
    253 linux_sys_sched_getscheduler(cl, v, retval)
    254 	struct lwp *cl;
    255 	void *v;
    256 	register_t *retval;
    257 {
    258 	struct linux_sys_sched_getscheduler_args /* {
    259 		syscallarg(linux_pid_t) pid;
    260 	} */ *uap = v;
    261 	struct proc *cp = cl->l_proc;
    262 	struct proc *p;
    263 
    264 	*retval = -1;
    265 /*
    266  * We only check for valid parameters and return afterwards.
    267  */
    268 
    269 	if (SCARG(uap, pid) != 0) {
    270 		struct pcred *pc = cp->p_cred;
    271 
    272 		if ((p = pfind(SCARG(uap, pid))) == NULL)
    273 			return ESRCH;
    274 		if (!(cp == p ||
    275 		      pc->pc_ucred->cr_uid == 0 ||
    276 		      pc->p_ruid == p->p_cred->p_ruid ||
    277 		      pc->pc_ucred->cr_uid == p->p_cred->p_ruid ||
    278 		      pc->p_ruid == p->p_ucred->cr_uid ||
    279 		      pc->pc_ucred->cr_uid == p->p_ucred->cr_uid))
    280 			return EPERM;
    281 	}
    282 
    283 /*
    284  * We can't emulate anything put the default scheduling policy.
    285  */
    286 	*retval = LINUX_SCHED_OTHER;
    287 	return 0;
    288 }
    289 
    290 int
    291 linux_sys_sched_yield(cl, v, retval)
    292 	struct lwp *cl;
    293 	void *v;
    294 	register_t *retval;
    295 {
    296 
    297 	yield();
    298 	return 0;
    299 }
    300 
    301 int
    302 linux_sys_sched_get_priority_max(cl, v, retval)
    303 	struct lwp *cl;
    304 	void *v;
    305 	register_t *retval;
    306 {
    307 	struct linux_sys_sched_get_priority_max_args /* {
    308 		syscallarg(int) policy;
    309 	} */ *uap = v;
    310 
    311 /*
    312  * We can't emulate anything put the default scheduling policy.
    313  */
    314 	if (SCARG(uap, policy) != LINUX_SCHED_OTHER) {
    315 		*retval = -1;
    316 		return EINVAL;
    317 	}
    318 
    319 	*retval = 0;
    320 	return 0;
    321 }
    322 
    323 int
    324 linux_sys_sched_get_priority_min(cl, v, retval)
    325 	struct lwp *cl;
    326 	void *v;
    327 	register_t *retval;
    328 {
    329 	struct linux_sys_sched_get_priority_min_args /* {
    330 		syscallarg(int) policy;
    331 	} */ *uap = v;
    332 
    333 /*
    334  * We can't emulate anything put the default scheduling policy.
    335  */
    336 	if (SCARG(uap, policy) != LINUX_SCHED_OTHER) {
    337 		*retval = -1;
    338 		return EINVAL;
    339 	}
    340 
    341 	*retval = 0;
    342 	return 0;
    343 }
    344 
    345 #ifndef __m68k__
    346 /* Present on everything but m68k */
    347 int
    348 linux_sys_exit_group(l, v, retval)
    349 	struct lwp *l;
    350 	void *v;
    351 	register_t *retval;
    352 {
    353 	struct linux_sys_exit_group_args /* {
    354 		syscallarg(int) error_code;
    355 	} */ *uap = v;
    356 
    357 	/*
    358 	 * XXX The calling thread is supposed to kill all threads
    359 	 * in the same thread group (i.e. all threads created
    360 	 * via clone(2) with CLONE_THREAD flag set). This appears
    361 	 * to not be used yet, so the thread group handling
    362 	 * is currently not implemented.
    363 	 */
    364 
    365 	exit1(l, W_EXITCODE(SCARG(uap, error_code), 0));
    366 	/* NOTREACHED */
    367 	return 0;
    368 }
    369 #endif /* !__m68k__ */
    370