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