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