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