Home | History | Annotate | Download | only in disp
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     27 /*	  All Rights Reserved  	*/
     28 
     29 
     30 #pragma ident	"@(#)priocntl.c	1.63	06/12/11 SMI"
     31 
     32 #include <sys/types.h>
     33 #include <sys/param.h>
     34 #include <sys/sysmacros.h>
     35 #include <sys/signal.h>
     36 #include <sys/pcb.h>
     37 #include <sys/user.h>
     38 #include <sys/systm.h>
     39 #include <sys/sysinfo.h>
     40 #include <sys/var.h>
     41 #include <sys/errno.h>
     42 #include <sys/cred.h>
     43 #include <sys/proc.h>
     44 #include <sys/procset.h>
     45 #include <sys/debug.h>
     46 #include <sys/inline.h>
     47 #include <sys/priocntl.h>
     48 #include <sys/disp.h>
     49 #include <sys/class.h>
     50 #include <sys/modctl.h>
     51 #include <sys/t_lock.h>
     52 #include <sys/uadmin.h>
     53 #include <sys/cmn_err.h>
     54 #include <sys/policy.h>
     55 
     56 /*
     57  * Structure used to pass arguments to the proccmp() function.
     58  * The arguments must be passed in a structure because proccmp()
     59  * is called indirectly through the dotoprocs() function which
     60  * will only pass through a single one word argument.
     61  */
     62 struct pcmpargs {
     63 	id_t	*pcmp_cidp;
     64 	int	*pcmp_cntp;
     65 	kthread_id_t	*pcmp_retthreadp;
     66 };
     67 
     68 /*
     69  * Structure used to pass arguments to the setparms() function
     70  * which is called indirectly through dotoprocs().
     71  */
     72 struct stprmargs {
     73 	struct pcparms	*stp_parmsp;	/* pointer to parameters */
     74 	int		stp_error;	/* some errors returned here */
     75 };
     76 
     77 #if defined(_SYSCALL32_IMPL) && _LONG_LONG_ALIGNMENT_32 == 4
     78 /*
     79  * A vaparm_t is an int followed by a long long -- this packs differently
     80  * between the 64-bit kernel ABI and the 32-bit user ABI.
     81  */
     82 static int
     83 copyin_vaparms32(caddr_t arg, pc_vaparms_t *vap, uio_seg_t seg)
     84 {
     85 	pc_vaparms32_t vaparms32;
     86 	pc_vaparm32_t *src;
     87 	pc_vaparm_t *dst;
     88 	uint_t cnt;
     89 
     90 	ASSERT(get_udatamodel() == DATAMODEL_ILP32);
     91 
     92 	if ((seg == UIO_USERSPACE ? copyin : kcopy)(arg, &vaparms32,
     93 	    sizeof (vaparms32)))
     94 		return (EFAULT);
     95 
     96 	vap->pc_vaparmscnt = vaparms32.pc_vaparmscnt;
     97 	if ((cnt = vaparms32.pc_vaparmscnt) > PC_VAPARMCNT)
     98 		cnt = PC_VAPARMCNT;
     99 	for (src = vaparms32.pc_parms, dst = vap->pc_parms;
    100 	    cnt--; src++, dst++) {
    101 		dst->pc_key = src->pc_key;
    102 		dst->pc_parm = src->pc_parm;
    103 	}
    104 	return (0);
    105 }
    106 
    107 #define	COPYIN_VAPARMS(arg, vap, size, seg)	\
    108 	(get_udatamodel() == DATAMODEL_NATIVE ?	\
    109 	(*copyinfn)(arg, vap, size) : copyin_vaparms32(arg, vap, seg))
    110 
    111 #else
    112 
    113 #define	COPYIN_VAPARMS(arg, vap, size, seg)	(*copyinfn)(arg, vap, size)
    114 
    115 #endif
    116 
    117 static int donice(procset_t *, pcnice_t *);
    118 static int proccmp(proc_t *, struct pcmpargs *);
    119 static int setparms(proc_t *, struct stprmargs *);
    120 extern int threadcmp(struct pcmpargs *, kthread_id_t);
    121 
    122 /*
    123  * The priocntl system call.
    124  */
    125 long
    126 priocntl_common(int pc_version, procset_t *psp, int cmd, caddr_t arg,
    127     caddr_t arg2, uio_seg_t seg)
    128 {
    129 	pcinfo_t		pcinfo;
    130 	pcparms_t		pcparms;
    131 	pcnice_t		pcnice;
    132 	pcadmin_t		pcadmin;
    133 	pcpri_t			pcpri;
    134 	procset_t		procset;
    135 	struct stprmargs	stprmargs;
    136 	struct pcmpargs		pcmpargs;
    137 	pc_vaparms_t		vaparms;
    138 	char			clname[PC_CLNMSZ];
    139 	char			*outstr;
    140 	int			count;
    141 	kthread_id_t		retthreadp;
    142 	proc_t			*initpp;
    143 	int			clnullflag;
    144 	int			error = 0;
    145 	int			error1 = 0;
    146 	int			rv = 0;
    147 	pid_t			saved_pid;
    148 	id_t			classid;
    149 	int			size;
    150 	int (*copyinfn)(const void *, void *, size_t);
    151 	int (*copyoutfn)(const void *, void *, size_t);
    152 
    153 	/*
    154 	 * First just check the version number. Right now there is only
    155 	 * one version we know about and support.  If we get some other
    156 	 * version number from the application it may be that the
    157 	 * application was built with some future version and is trying
    158 	 * to run on an old release of the system (that's us).  In any
    159 	 * case if we don't recognize the version number all we can do is
    160 	 * return error.
    161 	 */
    162 	if (pc_version != PC_VERSION)
    163 		return (set_errno(EINVAL));
    164 
    165 	if (seg == UIO_USERSPACE) {
    166 		copyinfn = copyin;
    167 		copyoutfn = copyout;
    168 	} else {
    169 		copyinfn = kcopy;
    170 		copyoutfn = kcopy;
    171 	}
    172 
    173 	switch (cmd) {
    174 	case PC_GETCID:
    175 		/*
    176 		 * If the arg pointer is NULL, the user just wants to
    177 		 * know the number of classes. If non-NULL, the pointer
    178 		 * should point to a valid user pcinfo buffer.  In the
    179 		 * dynamic world we need to return the number of loaded
    180 		 * classes, not the max number of available classes that
    181 		 * can be loaded.
    182 		 */
    183 		if (arg == NULL) {
    184 			rv = loaded_classes;
    185 			break;
    186 		} else {
    187 			if ((*copyinfn)(arg, &pcinfo, sizeof (pcinfo)))
    188 				return (set_errno(EFAULT));
    189 		}
    190 
    191 		pcinfo.pc_clname[PC_CLNMSZ-1] = '\0';
    192 
    193 		/*
    194 		 * Get the class ID corresponding to user supplied name.
    195 		 */
    196 		error = getcid(pcinfo.pc_clname, &pcinfo.pc_cid);
    197 		if (error)
    198 			return (set_errno(error));
    199 
    200 		/*
    201 		 * Can't get info about the sys class.
    202 		 */
    203 		if (pcinfo.pc_cid == 0)
    204 			return (set_errno(EINVAL));
    205 
    206 		/*
    207 		 * Get the class specific information.
    208 		 * we MUST make sure that the class has not already
    209 		 * been unloaded before we try the CL_GETCLINFO.
    210 		 * If it has then we need to load it.
    211 		 */
    212 		error =
    213 		    scheduler_load(pcinfo.pc_clname, &sclass[pcinfo.pc_cid]);
    214 		if (error)
    215 			return (set_errno(error));
    216 		error = CL_GETCLINFO(&sclass[pcinfo.pc_cid], pcinfo.pc_clinfo);
    217 		if (error)
    218 			return (set_errno(error));
    219 
    220 		if ((*copyoutfn)(&pcinfo, arg, sizeof (pcinfo)))
    221 			return (set_errno(EFAULT));
    222 
    223 		rv = loaded_classes;
    224 
    225 		break;
    226 
    227 	case PC_GETCLINFO:
    228 		/*
    229 		 * If the arg pointer is NULL, the user just wants to know
    230 		 * the number of classes. If non-NULL, the pointer should
    231 		 * point to a valid user pcinfo buffer.
    232 		 */
    233 		if (arg == NULL) {
    234 			rv = loaded_classes;
    235 			break;
    236 		} else {
    237 			if ((*copyinfn)(arg, &pcinfo, sizeof (pcinfo)))
    238 				return (set_errno(EFAULT));
    239 		}
    240 
    241 		if (pcinfo.pc_cid >= loaded_classes || pcinfo.pc_cid < 1)
    242 			return (set_errno(EINVAL));
    243 
    244 		(void) strncpy(pcinfo.pc_clname, sclass[pcinfo.pc_cid].cl_name,
    245 		    PC_CLNMSZ);
    246 
    247 		/*
    248 		 * Get the class specific information.  we MUST make sure
    249 		 * that the class has not already been unloaded before we
    250 		 * try the CL_GETCLINFO.  If it has then we need to load
    251 		 * it.
    252 		 */
    253 		error =
    254 		    scheduler_load(pcinfo.pc_clname, &sclass[pcinfo.pc_cid]);
    255 		if (error)
    256 			return (set_errno(error));
    257 		error = CL_GETCLINFO(&sclass[pcinfo.pc_cid], pcinfo.pc_clinfo);
    258 		if (error)
    259 			return (set_errno(error));
    260 
    261 		if ((*copyoutfn)(&pcinfo, arg, sizeof (pcinfo)))
    262 			return (set_errno(EFAULT));
    263 
    264 		rv = loaded_classes;
    265 		break;
    266 
    267 	case PC_SETPARMS:
    268 	case PC_SETXPARMS:
    269 		/*
    270 		 * First check the validity of the parameters we got from
    271 		 * the user.  We don't do any permissions checking here
    272 		 * because it's done on a per thread basis by parmsset().
    273 		 */
    274 		if (cmd == PC_SETPARMS) {
    275 			if ((*copyinfn)(arg, &pcparms, sizeof (pcparms)))
    276 				return (set_errno(EFAULT));
    277 
    278 			error = parmsin(&pcparms, NULL);
    279 		} else {
    280 			if ((*copyinfn)(arg, clname, PC_CLNMSZ) ||
    281 			    COPYIN_VAPARMS(arg2, &vaparms, sizeof (vaparms),
    282 			    seg))
    283 				return (set_errno(EFAULT));
    284 			clname[PC_CLNMSZ-1] = '\0';
    285 
    286 			if (getcid(clname, &pcparms.pc_cid))
    287 				return (set_errno(EINVAL));
    288 
    289 			error = parmsin(&pcparms, &vaparms);
    290 		}
    291 
    292 		if (error)
    293 			return (set_errno(error));
    294 
    295 		/*
    296 		 * Get the procset from the user.
    297 		 */
    298 		if ((*copyinfn)(psp, &procset, sizeof (procset)))
    299 			return (set_errno(EFAULT));
    300 
    301 		/*
    302 		 * For performance we do a quick check here to catch
    303 		 * common cases where the current thread is the only one
    304 		 * in the set.  In such cases we can call parmsset()
    305 		 * directly, avoiding the relatively lengthy path through
    306 		 * dotoprocs().  The underlying classes expect pidlock to
    307 		 * be held.
    308 		 */
    309 		if (cur_inset_only(&procset) == B_TRUE) {
    310 			/* do a single LWP */
    311 			if ((procset.p_lidtype == P_LWPID) ||
    312 			    (procset.p_ridtype == P_LWPID)) {
    313 				mutex_enter(&pidlock);
    314 				mutex_enter(&curproc->p_lock);
    315 				error = parmsset(&pcparms, curthread);
    316 				mutex_exit(&curproc->p_lock);
    317 				mutex_exit(&pidlock);
    318 			} else {
    319 				/* do the entire process otherwise */
    320 				stprmargs.stp_parmsp = &pcparms;
    321 				stprmargs.stp_error = 0;
    322 				mutex_enter(&pidlock);
    323 				error = setparms(curproc, &stprmargs);
    324 				mutex_exit(&pidlock);
    325 				if (error == 0 && stprmargs.stp_error != 0)
    326 					error = stprmargs.stp_error;
    327 			}
    328 			if (error)
    329 				return (set_errno(error));
    330 		} else {
    331 			stprmargs.stp_parmsp = &pcparms;
    332 			stprmargs.stp_error = 0;
    333 
    334 			error1 = error = ESRCH;
    335 
    336 			/*
    337 			 * The dotoprocs() call below will cause
    338 			 * setparms() to be called for each thread in the
    339 			 * specified procset. setparms() will in turn
    340 			 * call parmsset() (which does the real work).
    341 			 */
    342 			if ((procset.p_lidtype != P_LWPID) ||
    343 				(procset.p_ridtype != P_LWPID)) {
    344 				error1 = dotoprocs(&procset, setparms,
    345 				    (char *)&stprmargs);
    346 			}
    347 
    348 			/*
    349 			 * take care of the case when any of the
    350 			 * operands happen to be LWP's
    351 			 */
    352 
    353 			if ((procset.p_lidtype == P_LWPID) ||
    354 			    (procset.p_ridtype == P_LWPID)) {
    355 				error = dotolwp(&procset, parmsset,
    356 				    (char *)&pcparms);
    357 				/*
    358 				 * Dotolwp() returns with p_lock held.
    359 				 * This is required for the GETPARMS case
    360 				 * below. So, here we just release the
    361 				 * p_lock.
    362 				 */
    363 				if (MUTEX_HELD(&curproc->p_lock))
    364 					mutex_exit(&curproc->p_lock);
    365 			}
    366 
    367 			/*
    368 			 * If setparms() encounters a permissions error
    369 			 * for one or more of the threads it returns
    370 			 * EPERM in stp_error so dotoprocs() will
    371 			 * continue through the thread set.  If
    372 			 * dotoprocs() returned an error above, it was
    373 			 * more serious than permissions and dotoprocs
    374 			 * quit when the error was encountered.  We
    375 			 * return the more serious error if there was
    376 			 * one, otherwise we return EPERM if we got that
    377 			 * back.
    378 			 */
    379 			if (error1 != ESRCH)
    380 				error = error1;
    381 			if (error == 0 && stprmargs.stp_error != 0)
    382 				error = stprmargs.stp_error;
    383 		}
    384 		break;
    385 
    386 	case PC_GETPARMS:
    387 	case PC_GETXPARMS:
    388 		if (cmd == PC_GETPARMS) {
    389 			if ((*copyinfn)(arg, &pcparms, sizeof (pcparms)))
    390 				return (set_errno(EFAULT));
    391 		} else {
    392 			if (arg != NULL) {
    393 				if ((*copyinfn)(arg, clname, PC_CLNMSZ))
    394 					return (set_errno(EFAULT));
    395 
    396 				clname[PC_CLNMSZ-1] = '\0';
    397 
    398 				if (getcid(clname, &pcparms.pc_cid))
    399 					return (set_errno(EINVAL));
    400 			} else
    401 				pcparms.pc_cid = PC_CLNULL;
    402 
    403 			if (COPYIN_VAPARMS(arg2, &vaparms, sizeof (vaparms),
    404 			    seg))
    405 				return (set_errno(EFAULT));
    406 		}
    407 
    408 		if (pcparms.pc_cid >= loaded_classes ||
    409 		    (pcparms.pc_cid < 1 && pcparms.pc_cid != PC_CLNULL))
    410 			return (set_errno(EINVAL));
    411 
    412 		if ((*copyinfn)(psp, &procset, sizeof (procset)))
    413 			return (set_errno(EFAULT));
    414 
    415 		/*
    416 		 * Check to see if the current thread is the only one
    417 		 * in the set. If not we must go through the whole set
    418 		 * to select a thread.
    419 		 */
    420 		if (cur_inset_only(&procset) == B_TRUE) {
    421 			/* do a single LWP */
    422 			if ((procset.p_lidtype == P_LWPID) ||
    423 			    (procset.p_ridtype == P_LWPID)) {
    424 				if (pcparms.pc_cid != PC_CLNULL &&
    425 				    pcparms.pc_cid != curthread->t_cid) {
    426 					/*
    427 					 * Specified thread not in
    428 					 * specified class.
    429 					 */
    430 					return (set_errno(ESRCH));
    431 				} else {
    432 					mutex_enter(&curproc->p_lock);
    433 					retthreadp = curthread;
    434 				}
    435 			} else {
    436 				count = 0;
    437 				retthreadp = NULL;
    438 				pcmpargs.pcmp_cidp = &pcparms.pc_cid;
    439 				pcmpargs.pcmp_cntp = &count;
    440 				pcmpargs.pcmp_retthreadp = &retthreadp;
    441 				/*
    442 				 * Specified thread not in specified class.
    443 				 */
    444 				if (pcparms.pc_cid != PC_CLNULL &&
    445 				    pcparms.pc_cid != curthread->t_cid)
    446 					return (set_errno(ESRCH));
    447 				error = proccmp(curproc, &pcmpargs);
    448 				if (error) {
    449 					if (retthreadp != NULL)
    450 						mutex_exit(&(curproc->p_lock));
    451 					return (set_errno(error));
    452 				}
    453 			}
    454 		} else {
    455 			/*
    456 			 * get initpp early to avoid lock ordering problems
    457 			 * (we cannot get pidlock while holding any p_lock).
    458 			 */
    459 			mutex_enter(&pidlock);
    460 			initpp = prfind(P_INITPID);
    461 			mutex_exit(&pidlock);
    462 
    463 			/*
    464 			 * Select the thread (from the set) whose
    465 			 * parameters we are going to return.  First we
    466 			 * set up some locations for return values, then
    467 			 * we call proccmp() indirectly through
    468 			 * dotoprocs().  proccmp() will call a class
    469 			 * specific routine which actually does the
    470 			 * selection.  To understand how this works take
    471 			 * a careful look at the code below, the
    472 			 * dotoprocs() function, the proccmp() function,
    473 			 * and the class specific cl_proccmp() functions.
    474 			 */
    475 			if (pcparms.pc_cid == PC_CLNULL)
    476 				clnullflag = 1;
    477 			else
    478 				clnullflag = 0;
    479 			count = 0;
    480 			retthreadp = NULL;
    481 			pcmpargs.pcmp_cidp = &pcparms.pc_cid;
    482 			pcmpargs.pcmp_cntp = &count;
    483 			pcmpargs.pcmp_retthreadp = &retthreadp;
    484 			error1 = error = ESRCH;
    485 
    486 			if ((procset.p_lidtype != P_LWPID) ||
    487 			    (procset.p_ridtype != P_LWPID)) {
    488 				error1 = dotoprocs(&procset, proccmp,
    489 				    (char *)&pcmpargs);
    490 			}
    491 
    492 			/*
    493 			 * take care of combination of LWP and process
    494 			 * set case in a procset
    495 			 */
    496 			if ((procset.p_lidtype == P_LWPID) ||
    497 			    (procset.p_ridtype == P_LWPID)) {
    498 				error = dotolwp(&procset, threadcmp,
    499 				    (char *)&pcmpargs);
    500 			}
    501 
    502 			/*
    503 			 * Both proccmp() and threadcmp() return with the
    504 			 * p_lock held for the ttoproc(retthreadp). This
    505 			 * is required to make sure that the process we
    506 			 * chose as the winner doesn't go away
    507 			 * i.e. retthreadp has to be a valid pointer.
    508 			 *
    509 			 * The case below can only happen if the thread
    510 			 * with the highest priority was not in your
    511 			 * process.  In that case, dotolwp will return
    512 			 * holding p_lock for both your process as well
    513 			 * as the process in which retthreadp is a
    514 			 * thread.
    515 			 */
    516 			if ((retthreadp != NULL) &&
    517 			    (ttoproc(retthreadp) != curproc) &&
    518 			    MUTEX_HELD(&(curproc)->p_lock))
    519 				mutex_exit(&(curproc)->p_lock);
    520 
    521 			ASSERT(retthreadp == NULL ||
    522 			    MUTEX_HELD(&(ttoproc(retthreadp)->p_lock)));
    523 			if (error1 != ESRCH)
    524 				error = error1;
    525 			if (error) {
    526 				if (retthreadp != NULL)
    527 				    mutex_exit(&(ttoproc(retthreadp)->p_lock));
    528 				ASSERT(MUTEX_NOT_HELD(&(curproc)->p_lock));
    529 				return (set_errno(error));
    530 			}
    531 			/*
    532 			 * dotoprocs() ignores the init process if it is
    533 			 * in the set, unless it was the only process found.
    534 			 * Since we are getting parameters here rather than
    535 			 * setting them, we want to make sure init is not
    536 			 * excluded if it is in the set.
    537 			 */
    538 			if (initpp != NULL &&
    539 			    procinset(initpp, &procset) &&
    540 			    (retthreadp != NULL) &&
    541 			    ttoproc(retthreadp) != initpp)
    542 				(void) proccmp(initpp, &pcmpargs);
    543 
    544 			/*
    545 			 * If dotoprocs returned success it found at least
    546 			 * one thread in the set.  If proccmp() failed to
    547 			 * select a thread it is because the user specified
    548 			 * a class and none of the threads in the set
    549 			 * belonged to that class, or because the process
    550 			 * specified was in the middle of exiting and had
    551 			 * cleared its thread list.
    552 			 */
    553 			if (retthreadp == NULL) {
    554 				/*
    555 				 * Might be here and still holding p_lock
    556 				 * if we did a dotolwp on an lwp that
    557 				 * existed but was in the wrong class.
    558 				 */
    559 				if (MUTEX_HELD(&(curproc)->p_lock))
    560 					mutex_exit(&(curproc)->p_lock);
    561 				return (set_errno(ESRCH));
    562 			}
    563 
    564 			/*
    565 			 * User can only use PC_CLNULL with one thread in set.
    566 			 */
    567 			if (clnullflag && count > 1) {
    568 				if (retthreadp != NULL)
    569 					mutex_exit(
    570 					    &(ttoproc(retthreadp)->p_lock));
    571 				ASSERT(MUTEX_NOT_HELD(&(curproc)->p_lock));
    572 				return (set_errno(EINVAL));
    573 			}
    574 		}
    575 
    576 		ASSERT(retthreadp == NULL ||
    577 		    MUTEX_HELD(&(ttoproc(retthreadp)->p_lock)));
    578 		/*
    579 		 * It is possible to have retthreadp == NULL. Proccmp()
    580 		 * in the rare case (p_tlist == NULL) could return without
    581 		 * setting a value for retthreadp.
    582 		 */
    583 		if (retthreadp == NULL) {
    584 			ASSERT(MUTEX_NOT_HELD(&(curproc)->p_lock));
    585 			return (set_errno(ESRCH));
    586 		}
    587 		/*
    588 		 * We've selected a thread so now get the parameters.
    589 		 */
    590 		parmsget(retthreadp, &pcparms);
    591 
    592 		/*
    593 		 * Prepare to return parameters to the user
    594 		 */
    595 		error = parmsout(&pcparms,
    596 		    (cmd == PC_GETPARMS ? NULL : &vaparms));
    597 
    598 		/*
    599 		 * Save pid of selected thread before dropping p_lock.
    600 		 */
    601 		saved_pid = ttoproc(retthreadp)->p_pid;
    602 		mutex_exit(&(ttoproc(retthreadp)->p_lock));
    603 		ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
    604 
    605 		if (error)
    606 			return (set_errno(error));
    607 
    608 		if (cmd == PC_GETPARMS) {
    609 			if ((*copyoutfn)(&pcparms, arg, sizeof (pcparms)))
    610 				return (set_errno(EFAULT));
    611 		} else if ((error = vaparmsout(arg, &pcparms, &vaparms,
    612 		    seg)) != 0)
    613 			return (set_errno(error));
    614 
    615 		/*
    616 		 * And finally, return the pid of the selected thread.
    617 		 */
    618 		rv = saved_pid;
    619 		break;
    620 
    621 	case PC_ADMIN:
    622 		if (get_udatamodel() == DATAMODEL_NATIVE) {
    623 			if ((*copyinfn)(arg, &pcadmin, sizeof (pcadmin_t)))
    624 				return (set_errno(EFAULT));
    625 #ifdef _SYSCALL32_IMPL
    626 		} else {
    627 			/* pcadmin struct from ILP32 callers */
    628 			pcadmin32_t pcadmin32;
    629 
    630 			if ((*copyinfn)(arg, &pcadmin32, sizeof (pcadmin32_t)))
    631 				return (set_errno(EFAULT));
    632 			pcadmin.pc_cid = pcadmin32.pc_cid;
    633 			pcadmin.pc_cladmin = (caddr_t)(uintptr_t)
    634 			    pcadmin32.pc_cladmin;
    635 #endif /* _SYSCALL32_IMPL */
    636 		}
    637 
    638 		if (pcadmin.pc_cid >= loaded_classes ||
    639 		    pcadmin.pc_cid < 1)
    640 			return (set_errno(EINVAL));
    641 
    642 		/*
    643 		 * Have the class do whatever the user is requesting.
    644 		 */
    645 		mutex_enter(&ualock);
    646 		error = CL_ADMIN(&sclass[pcadmin.pc_cid], pcadmin.pc_cladmin,
    647 				CRED());
    648 		mutex_exit(&ualock);
    649 		break;
    650 
    651 	case PC_GETPRIRANGE:
    652 		if ((*copyinfn)(arg, &pcpri, sizeof (pcpri_t)))
    653 			return (set_errno(EFAULT));
    654 
    655 		if (pcpri.pc_cid >= loaded_classes || pcpri.pc_cid < 0)
    656 			return (set_errno(EINVAL));
    657 
    658 		error = CL_GETCLPRI(&sclass[pcpri.pc_cid], &pcpri);
    659 		if (!error) {
    660 			if ((*copyoutfn)(&pcpri, arg, sizeof (pcpri)))
    661 				return (set_errno(EFAULT));
    662 		}
    663 		break;
    664 
    665 	case PC_DONICE:
    666 		/*
    667 		 * Get pcnice and procset structures from the user.
    668 		 */
    669 		if ((*copyinfn)(arg, &pcnice, sizeof (pcnice)) ||
    670 		    (*copyinfn)(psp, &procset, sizeof (procset)))
    671 			return (set_errno(EFAULT));
    672 
    673 		error = donice(&procset, &pcnice);
    674 
    675 		if (!error && (pcnice.pc_op == PC_GETNICE)) {
    676 			if ((*copyoutfn)(&pcnice, arg, sizeof (pcnice)))
    677 				return (set_errno(EFAULT));
    678 		}
    679 		break;
    680 
    681 	case PC_SETDFLCL:
    682 		if (secpolicy_dispadm(CRED()) != 0)
    683 			return (set_errno(EPERM));
    684 
    685 		if (copyin(arg, (caddr_t)clname, PC_CLNMSZ) != 0)
    686 			return (set_errno(EFAULT));
    687 		clname[PC_CLNMSZ-1] = '\0';
    688 
    689 		if (getcid(clname, &classid) != 0)
    690 			return (set_errno(EINVAL));
    691 		if (classid == syscid)
    692 			return (set_errno(EINVAL));
    693 		defaultcid = classid;
    694 		ASSERT(defaultcid > 0 && defaultcid < loaded_classes);
    695 		break;
    696 
    697 	case PC_GETDFLCL:
    698 		mutex_enter(&class_lock);
    699 
    700 		if (defaultcid >= loaded_classes)
    701 			outstr = "";
    702 		else
    703 			outstr = sclass[defaultcid].cl_name;
    704 		size = strlen(outstr) + 1;
    705 		if (arg != NULL)
    706 			if ((*copyoutfn)(outstr, arg, size) != 0)
    707 				error = EFAULT;
    708 
    709 		mutex_exit(&class_lock);
    710 		break;
    711 
    712 	default:
    713 		error = EINVAL;
    714 		break;
    715 	}
    716 	return (error ? (set_errno(error)) : rv);
    717 }
    718 
    719 long
    720 priocntlsys(int pc_version, procset_t *psp, int cmd, caddr_t arg, caddr_t arg2)
    721 {
    722 	return (priocntl_common(pc_version, psp, cmd, arg, arg2,
    723 	    UIO_USERSPACE));
    724 }
    725 
    726 /*
    727  * The proccmp() function is part of the implementation of the
    728  * PC_GETPARMS command of the priocntl system call.  This function works
    729  * with the system call code and with the class specific cl_globpri()
    730  * function to select one thread from a specified procset based on class
    731  * specific criteria. proccmp() is called indirectly from the priocntl
    732  * code through the dotoprocs function.  Basic strategy is dotoprocs()
    733  * calls us once for each thread in the set.  We in turn call the class
    734  * specific function to compare the current thread from dotoprocs to the
    735  * "best" (according to the class criteria) found so far.  We keep the
    736  * "best" thread in *pcmp_retthreadp.
    737  */
    738 static int
    739 proccmp(proc_t *pp, struct pcmpargs *argp)
    740 {
    741 	kthread_id_t	tx, ty;
    742 	int		last_pri = -1;
    743 	int		tx_pri;
    744 	int		found = 0;
    745 
    746 	mutex_enter(&pp->p_lock);
    747 
    748 	if (pp->p_tlist == NULL) {
    749 		mutex_exit(&pp->p_lock);
    750 		return (0);
    751 	}
    752 	(*argp->pcmp_cntp)++;	/* Increment count of procs in the set */
    753 
    754 	if (*argp->pcmp_cidp == PC_CLNULL) {
    755 		/*
    756 		 * If no cid is specified, then lets just pick the first one.
    757 		 * It doesn't matter because if the number of processes in the
    758 		 * set are more than 1, then we return EINVAL in priocntlsys.
    759 		 */
    760 		*argp->pcmp_cidp = pp->p_tlist->t_cid;
    761 	}
    762 	ty = tx = pp->p_tlist;
    763 	do {
    764 		if (tx->t_cid == *argp->pcmp_cidp) {
    765 			/*
    766 			 * We found one which matches the required cid.
    767 			 */
    768 			found = 1;
    769 			if ((tx_pri = CL_GLOBPRI(tx)) > last_pri) {
    770 				last_pri = tx_pri;
    771 				ty = tx;
    772 			}
    773 		}
    774 	} while ((tx = tx->t_forw) != pp->p_tlist);
    775 	if (found) {
    776 		if (*argp->pcmp_retthreadp == NULL) {
    777 			/*
    778 			 * First time through for this set.
    779 			 * keep the mutex held. He might be the one!
    780 			 */
    781 			*argp->pcmp_retthreadp = ty;
    782 		} else {
    783 			tx = *argp->pcmp_retthreadp;
    784 			if (CL_GLOBPRI(ty) <= CL_GLOBPRI(tx)) {
    785 				mutex_exit(&pp->p_lock);
    786 			} else {
    787 				mutex_exit(&(ttoproc(tx)->p_lock));
    788 				*argp->pcmp_retthreadp = ty;
    789 			}
    790 		}
    791 	} else {
    792 		/*
    793 		 * We actually didn't find anything of the same cid in
    794 		 * this process.
    795 		 */
    796 		mutex_exit(&pp->p_lock);
    797 	}
    798 	return (0);
    799 }
    800 
    801 
    802 int
    803 threadcmp(struct pcmpargs *argp, kthread_id_t tp)
    804 {
    805 	kthread_id_t	tx;
    806 	proc_t		*pp;
    807 
    808 	ASSERT(MUTEX_HELD(&(ttoproc(tp))->p_lock));
    809 
    810 	(*argp->pcmp_cntp)++;   /* Increment count of procs in the set */
    811 	if (*argp->pcmp_cidp == PC_CLNULL) {
    812 		/*
    813 		 * If no cid is specified, then lets just pick the first one.
    814 		 * It doesn't matter because if the number of threads in the
    815 		 * set are more than 1, then we return EINVAL in priocntlsys.
    816 		 */
    817 		*argp->pcmp_cidp = tp->t_cid;
    818 	}
    819 	if (tp->t_cid == *argp->pcmp_cidp) {
    820 		if (*argp->pcmp_retthreadp == NULL) {
    821 			/*
    822 			 * First time through for this set.
    823 			 */
    824 			*argp->pcmp_retthreadp = tp;
    825 		} else {
    826 			tx = *argp->pcmp_retthreadp;
    827 			if (CL_GLOBPRI(tp) > CL_GLOBPRI(tx)) {
    828 				/*
    829 				 * Unlike proccmp(), we don't release the
    830 				 * p_lock of the ttoproc(tp) if tp's global
    831 				 * priority is less than tx's. We need to go
    832 				 * through the entire list before we can do
    833 				 * that. The p_lock is released by the caller
    834 				 * of dotolwp().
    835 				 */
    836 				pp = ttoproc(tx);
    837 				ASSERT(MUTEX_HELD(&pp->p_lock));
    838 				if (pp != curproc) {
    839 					mutex_exit(&pp->p_lock);
    840 				}
    841 				*argp->pcmp_retthreadp = tp;
    842 			}
    843 		}
    844 	}
    845 	return (0);
    846 }
    847 
    848 
    849 /*
    850  * The setparms() function is called indirectly by priocntlsys()
    851  * through the dotoprocs() function.  setparms() acts as an
    852  * intermediary between dotoprocs() and the parmsset() function,
    853  * calling parmsset() for each thread in the set and handling
    854  * the error returns on their way back up to dotoprocs().
    855  */
    856 static int
    857 setparms(proc_t *targpp, struct stprmargs *stprmp)
    858 {
    859 	int error = 0;
    860 	kthread_id_t t;
    861 	int err;
    862 
    863 	mutex_enter(&targpp->p_lock);
    864 	if ((t = targpp->p_tlist) == NULL) {
    865 		mutex_exit(&targpp->p_lock);
    866 		return (0);
    867 	}
    868 	do {
    869 		err = parmsset(stprmp->stp_parmsp, t);
    870 		if (error == 0)
    871 			error = err;
    872 	} while ((t = t->t_forw) != targpp->p_tlist);
    873 	mutex_exit(&targpp->p_lock);
    874 	if (error) {
    875 		if (error == EPERM) {
    876 			stprmp->stp_error = EPERM;
    877 			return (0);
    878 		} else {
    879 			return (error);
    880 		}
    881 	} else
    882 		return (0);
    883 }
    884 
    885 int
    886 setthreadnice(pcnice_t *pcnice, kthread_t *tp)
    887 {
    888 	int error = 0;
    889 	int nice;
    890 	int inc;
    891 	id_t rtcid;
    892 
    893 	ASSERT(MUTEX_HELD(&pidlock));
    894 	ASSERT(MUTEX_HELD(&(ttoproc(tp)->p_lock)));
    895 
    896 	/*
    897 	 * The XPG5 standard requires that any realtime process or thread
    898 	 * must be unaffected by a call to setpriority().
    899 	 */
    900 	error = getcidbyname("RT", &rtcid);
    901 	if ((error == 0) && (tp->t_cid == rtcid)) {
    902 		if (pcnice->pc_op == PC_SETNICE)
    903 			return (error);
    904 	}
    905 
    906 	if ((error = CL_DONICE(tp, CRED(), 0, &nice)) != 0)
    907 		return (error);
    908 
    909 	if (pcnice->pc_op == PC_GETNICE) {
    910 		/*
    911 		 * If there is no change to priority, we should return the
    912 		 * highest priority (lowest numerical value) pertaining to
    913 		 * any of the specified threads.
    914 		 */
    915 		if (nice < pcnice->pc_val)
    916 			pcnice->pc_val = nice;
    917 	} else {
    918 		ASSERT(pcnice->pc_op == PC_SETNICE);
    919 		/*
    920 		 * Try to change the nice value of the thread.
    921 		 */
    922 		inc = pcnice->pc_val - nice;
    923 
    924 		error = CL_DONICE(tp, CRED(), inc, &inc);
    925 	}
    926 
    927 	return (error);
    928 }
    929 
    930 int
    931 setprocnice(proc_t *pp, pcnice_t *pcnice)
    932 {
    933 	kthread_t *tp;
    934 	int retval = 0;
    935 	int error = 0;
    936 
    937 	ASSERT(MUTEX_HELD(&pidlock));
    938 	mutex_enter(&pp->p_lock);
    939 
    940 	if ((tp = pp->p_tlist) == NULL) {
    941 		mutex_exit(&pp->p_lock);
    942 		return (ESRCH);
    943 	}
    944 
    945 	/*
    946 	 * Check permissions before changing the nice value.
    947 	 */
    948 	if (pcnice->pc_op == PC_SETNICE) {
    949 		if (!prochasprocperm(pp, curproc, CRED())) {
    950 			mutex_exit(&pp->p_lock);
    951 			return (EPERM);
    952 		}
    953 	}
    954 
    955 	do {
    956 		error = setthreadnice(pcnice, tp);
    957 		if (error)
    958 			retval = error;
    959 	} while ((tp = tp->t_forw) != pp->p_tlist);
    960 
    961 	mutex_exit(&pp->p_lock);
    962 	return (retval);
    963 }
    964 
    965 /*
    966  * Update the nice value of the specified LWP or set of processes.
    967  */
    968 static int
    969 donice(procset_t *procset, pcnice_t *pcnice)
    970 {
    971 	int err_proc = 0;
    972 	int err_thread = 0;
    973 	int err = 0;
    974 
    975 	/*
    976 	 * Sanity check.
    977 	 */
    978 	if (pcnice->pc_op != PC_GETNICE && pcnice->pc_op != PC_SETNICE)
    979 		return (EINVAL);
    980 
    981 	/*
    982 	 * If it is PC_GETNICE operation then set pc_val to the largest
    983 	 * possible nice value to help us find the lowest nice value
    984 	 * pertaining to any of the specified processes.
    985 	 */
    986 	if (pcnice->pc_op == PC_GETNICE)
    987 		pcnice->pc_val = NZERO;
    988 
    989 	if (procset->p_lidtype != P_LWPID ||
    990 	    procset->p_ridtype != P_LWPID)
    991 		err_proc = dotoprocs(procset, setprocnice, (char *)pcnice);
    992 
    993 	if (procset->p_lidtype == P_LWPID || procset->p_ridtype == P_LWPID) {
    994 		err_thread = dotolwp(procset, setthreadnice, (char *)pcnice);
    995 		/*
    996 		 * dotolwp() can return with p_lock held.  This is required
    997 		 * for the priocntl GETPARMS case.  So, here we just release
    998 		 * the p_lock.
    999 		 */
   1000 		if (MUTEX_HELD(&curproc->p_lock))
   1001 			mutex_exit(&curproc->p_lock);
   1002 
   1003 		/*
   1004 		 * If we were called for a single LWP, then ignore ESRCH
   1005 		 * returned by the previous dotoprocs() call.
   1006 		 */
   1007 		if (err_proc == ESRCH)
   1008 			err_proc = 0;
   1009 	}
   1010 
   1011 	/*
   1012 	 * dotoprocs() ignores the init process if it is in the set, unless
   1013 	 * it was the only process found. We want to make sure init is not
   1014 	 * excluded if we're going PC_GETNICE operation.
   1015 	 */
   1016 	if (pcnice->pc_op == PC_GETNICE) {
   1017 		proc_t *initpp;
   1018 
   1019 		mutex_enter(&pidlock);
   1020 		initpp = prfind(P_INITPID);
   1021 		if (initpp != NULL && procinset(initpp, procset))
   1022 			err = setprocnice(initpp, pcnice);
   1023 		mutex_exit(&pidlock);
   1024 	}
   1025 
   1026 	/*
   1027 	 * We're returning the latest error here that we've got back from
   1028 	 * the setthreadnice() or setprocnice(). That is, err_thread and/or
   1029 	 * err_proc can be replaced by err.
   1030 	 */
   1031 	if (!err)
   1032 		err = err_thread ? err_thread : err_proc;
   1033 
   1034 	return (err);
   1035 }
   1036