xref: /titanic_50/usr/src/uts/common/disp/priocntl.c (revision dfb96a4f56fb431b915bc67e5d9d5c8d4f4f6679)
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 	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