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 && 543 procinset(initpp, &procset) && 544 (retthreadp != NULL) && 545 ttoproc(retthreadp) != initpp) 546 (void) proccmp(initpp, &pcmpargs); 547 548 /* 549 * If dotoprocs returned success it found at least 550 * one thread in the set. If proccmp() failed to 551 * select a thread it is because the user specified 552 * a class and none of the threads in the set 553 * belonged to that class, or because the process 554 * specified was in the middle of exiting and had 555 * cleared its thread list. 556 */ 557 if (retthreadp == NULL) { 558 /* 559 * Might be here and still holding p_lock 560 * if we did a dotolwp on an lwp that 561 * existed but was in the wrong class. 562 */ 563 if (MUTEX_HELD(&(curproc)->p_lock)) 564 mutex_exit(&(curproc)->p_lock); 565 return (set_errno(ESRCH)); 566 } 567 568 /* 569 * User can only use PC_CLNULL with one thread in set. 570 */ 571 if (clnullflag && count > 1) { 572 if (retthreadp != NULL) 573 mutex_exit( 574 &(ttoproc(retthreadp)->p_lock)); 575 ASSERT(MUTEX_NOT_HELD(&(curproc)->p_lock)); 576 return (set_errno(EINVAL)); 577 } 578 } 579 580 ASSERT(retthreadp == NULL || 581 MUTEX_HELD(&(ttoproc(retthreadp)->p_lock))); 582 /* 583 * It is possible to have retthreadp == NULL. Proccmp() 584 * in the rare case (p_tlist == NULL) could return without 585 * setting a value for retthreadp. 586 */ 587 if (retthreadp == NULL) { 588 ASSERT(MUTEX_NOT_HELD(&(curproc)->p_lock)); 589 return (set_errno(ESRCH)); 590 } 591 /* 592 * We've selected a thread so now get the parameters. 593 */ 594 parmsget(retthreadp, &pcparms); 595 596 /* 597 * Prepare to return parameters to the user 598 */ 599 error = parmsout(&pcparms, 600 (cmd == PC_GETPARMS ? NULL : &vaparms)); 601 602 /* 603 * Save pid of selected thread before dropping p_lock. 604 */ 605 saved_pid = ttoproc(retthreadp)->p_pid; 606 mutex_exit(&(ttoproc(retthreadp)->p_lock)); 607 ASSERT(MUTEX_NOT_HELD(&curproc->p_lock)); 608 609 if (error) 610 return (set_errno(error)); 611 612 if (cmd == PC_GETPARMS) { 613 if ((*copyoutfn)(&pcparms, arg, sizeof (pcparms))) 614 return (set_errno(EFAULT)); 615 } else if ((error = vaparmsout(arg, &pcparms, &vaparms, 616 seg)) != 0) 617 return (set_errno(error)); 618 619 /* 620 * And finally, return the pid of the selected thread. 621 */ 622 rv = saved_pid; 623 break; 624 625 case PC_ADMIN: 626 if (get_udatamodel() == DATAMODEL_NATIVE) { 627 if ((*copyinfn)(arg, &pcadmin, sizeof (pcadmin_t))) 628 return (set_errno(EFAULT)); 629 #ifdef _SYSCALL32_IMPL 630 } else { 631 /* pcadmin struct from ILP32 callers */ 632 pcadmin32_t pcadmin32; 633 634 if ((*copyinfn)(arg, &pcadmin32, sizeof (pcadmin32_t))) 635 return (set_errno(EFAULT)); 636 pcadmin.pc_cid = pcadmin32.pc_cid; 637 pcadmin.pc_cladmin = (caddr_t)(uintptr_t) 638 pcadmin32.pc_cladmin; 639 #endif /* _SYSCALL32_IMPL */ 640 } 641 642 if (pcadmin.pc_cid >= loaded_classes || 643 pcadmin.pc_cid < 1) 644 return (set_errno(EINVAL)); 645 646 /* 647 * Have the class do whatever the user is requesting. 648 */ 649 mutex_enter(&ualock); 650 error = CL_ADMIN(&sclass[pcadmin.pc_cid], pcadmin.pc_cladmin, 651 CRED()); 652 mutex_exit(&ualock); 653 break; 654 655 case PC_GETPRIRANGE: 656 if ((*copyinfn)(arg, &pcpri, sizeof (pcpri_t))) 657 return (set_errno(EFAULT)); 658 659 if (pcpri.pc_cid >= loaded_classes || pcpri.pc_cid < 0) 660 return (set_errno(EINVAL)); 661 662 error = CL_GETCLPRI(&sclass[pcpri.pc_cid], &pcpri); 663 if (!error) { 664 if ((*copyoutfn)(&pcpri, arg, sizeof (pcpri))) 665 return (set_errno(EFAULT)); 666 } 667 break; 668 669 case PC_DONICE: 670 /* 671 * Get pcnice and procset structures from the user. 672 */ 673 if ((*copyinfn)(arg, &pcnice, sizeof (pcnice)) || 674 (*copyinfn)(psp, &procset, sizeof (procset))) 675 return (set_errno(EFAULT)); 676 677 error = donice(&procset, &pcnice); 678 679 if (!error && (pcnice.pc_op == PC_GETNICE)) { 680 if ((*copyoutfn)(&pcnice, arg, sizeof (pcnice))) 681 return (set_errno(EFAULT)); 682 } 683 break; 684 685 case PC_DOPRIO: 686 /* 687 * Get pcprio and procset structures from the user. 688 */ 689 if ((*copyinfn)(arg, &pcprio, sizeof (pcprio)) || 690 (*copyinfn)(psp, &procset, sizeof (procset))) 691 return (set_errno(EFAULT)); 692 693 error = doprio(&procset, &pcprio); 694 695 if (!error && (pcprio.pc_op == PC_GETPRIO)) { 696 if ((*copyoutfn)(&pcprio, arg, sizeof (pcprio))) 697 return (set_errno(EFAULT)); 698 } 699 break; 700 701 case PC_SETDFLCL: 702 if (secpolicy_dispadm(CRED()) != 0) 703 return (set_errno(EPERM)); 704 705 if (copyin(arg, (caddr_t)clname, PC_CLNMSZ) != 0) 706 return (set_errno(EFAULT)); 707 clname[PC_CLNMSZ-1] = '\0'; 708 709 if (getcid(clname, &classid) != 0) 710 return (set_errno(EINVAL)); 711 if (classid == syscid) 712 return (set_errno(EINVAL)); 713 defaultcid = classid; 714 ASSERT(defaultcid > 0 && defaultcid < loaded_classes); 715 break; 716 717 case PC_GETDFLCL: 718 mutex_enter(&class_lock); 719 720 if (defaultcid >= loaded_classes) 721 outstr = ""; 722 else 723 outstr = sclass[defaultcid].cl_name; 724 size = strlen(outstr) + 1; 725 if (arg != NULL) 726 if ((*copyoutfn)(outstr, arg, size) != 0) 727 error = EFAULT; 728 729 mutex_exit(&class_lock); 730 break; 731 732 default: 733 error = EINVAL; 734 break; 735 } 736 return (error ? (set_errno(error)) : rv); 737 } 738 739 long 740 priocntlsys(int pc_version, procset_t *psp, int cmd, caddr_t arg, caddr_t arg2) 741 { 742 return (priocntl_common(pc_version, psp, cmd, arg, arg2, 743 UIO_USERSPACE)); 744 } 745 746 /* 747 * The proccmp() function is part of the implementation of the 748 * PC_GETPARMS command of the priocntl system call. This function works 749 * with the system call code and with the class specific cl_globpri() 750 * function to select one thread from a specified procset based on class 751 * specific criteria. proccmp() is called indirectly from the priocntl 752 * code through the dotoprocs function. Basic strategy is dotoprocs() 753 * calls us once for each thread in the set. We in turn call the class 754 * specific function to compare the current thread from dotoprocs to the 755 * "best" (according to the class criteria) found so far. We keep the 756 * "best" thread in *pcmp_retthreadp. 757 */ 758 static int 759 proccmp(proc_t *pp, struct pcmpargs *argp) 760 { 761 kthread_t *tx; 762 kthread_t *ty; 763 int last_pri = -1; 764 int tx_pri; 765 int found = 0; 766 767 mutex_enter(&pp->p_lock); 768 769 if (pp->p_tlist == NULL) { 770 mutex_exit(&pp->p_lock); 771 return (0); 772 } 773 (*argp->pcmp_cntp)++; /* Increment count of procs in the set */ 774 775 if (*argp->pcmp_cidp == PC_CLNULL) { 776 /* 777 * If no cid is specified, then lets just pick the first one. 778 * It doesn't matter because if the number of processes in the 779 * set are more than 1, then we return EINVAL in priocntlsys. 780 */ 781 *argp->pcmp_cidp = pp->p_tlist->t_cid; 782 } 783 ty = tx = pp->p_tlist; 784 do { 785 if (tx->t_cid == *argp->pcmp_cidp) { 786 /* 787 * We found one which matches the required cid. 788 */ 789 found = 1; 790 if ((tx_pri = CL_GLOBPRI(tx)) > last_pri) { 791 last_pri = tx_pri; 792 ty = tx; 793 } 794 } 795 } while ((tx = tx->t_forw) != pp->p_tlist); 796 if (found) { 797 if (*argp->pcmp_retthreadp == NULL) { 798 /* 799 * First time through for this set. 800 * keep the mutex held. He might be the one! 801 */ 802 *argp->pcmp_retthreadp = ty; 803 } else { 804 tx = *argp->pcmp_retthreadp; 805 if (CL_GLOBPRI(ty) <= CL_GLOBPRI(tx)) { 806 mutex_exit(&pp->p_lock); 807 } else { 808 mutex_exit(&(ttoproc(tx)->p_lock)); 809 *argp->pcmp_retthreadp = ty; 810 } 811 } 812 } else { 813 /* 814 * We actually didn't find anything of the same cid in 815 * this process. 816 */ 817 mutex_exit(&pp->p_lock); 818 } 819 return (0); 820 } 821 822 823 int 824 threadcmp(struct pcmpargs *argp, kthread_t *tp) 825 { 826 kthread_t *tx; 827 proc_t *pp; 828 829 ASSERT(MUTEX_HELD(&(ttoproc(tp))->p_lock)); 830 831 (*argp->pcmp_cntp)++; /* Increment count of procs in the set */ 832 if (*argp->pcmp_cidp == PC_CLNULL) { 833 /* 834 * If no cid is specified, then lets just pick the first one. 835 * It doesn't matter because if the number of threads in the 836 * set are more than 1, then we return EINVAL in priocntlsys. 837 */ 838 *argp->pcmp_cidp = tp->t_cid; 839 } 840 if (tp->t_cid == *argp->pcmp_cidp) { 841 if (*argp->pcmp_retthreadp == NULL) { 842 /* 843 * First time through for this set. 844 */ 845 *argp->pcmp_retthreadp = tp; 846 } else { 847 tx = *argp->pcmp_retthreadp; 848 if (CL_GLOBPRI(tp) > CL_GLOBPRI(tx)) { 849 /* 850 * Unlike proccmp(), we don't release the 851 * p_lock of the ttoproc(tp) if tp's global 852 * priority is less than tx's. We need to go 853 * through the entire list before we can do 854 * that. The p_lock is released by the caller 855 * of dotolwp(). 856 */ 857 pp = ttoproc(tx); 858 ASSERT(MUTEX_HELD(&pp->p_lock)); 859 if (pp != curproc) { 860 mutex_exit(&pp->p_lock); 861 } 862 *argp->pcmp_retthreadp = tp; 863 } 864 } 865 } 866 return (0); 867 } 868 869 870 /* 871 * The setparms() function is called indirectly by priocntlsys() 872 * through the dotoprocs() function. setparms() acts as an 873 * intermediary between dotoprocs() and the parmsset() function, 874 * calling parmsset() for each thread in the set and handling 875 * the error returns on their way back up to dotoprocs(). 876 */ 877 static int 878 setparms(proc_t *targpp, struct stprmargs *stprmp) 879 { 880 int error = 0; 881 kthread_t *t; 882 int err; 883 884 mutex_enter(&targpp->p_lock); 885 if ((t = targpp->p_tlist) == NULL) { 886 mutex_exit(&targpp->p_lock); 887 return (0); 888 } 889 do { 890 err = parmsset(stprmp->stp_parmsp, t); 891 if (error == 0) 892 error = err; 893 } while ((t = t->t_forw) != targpp->p_tlist); 894 mutex_exit(&targpp->p_lock); 895 if (error) { 896 if (error == EPERM) { 897 stprmp->stp_error = EPERM; 898 return (0); 899 } else { 900 return (error); 901 } 902 } else 903 return (0); 904 } 905 906 int 907 setthreadnice(pcnice_t *pcnice, kthread_t *tp) 908 { 909 int error; 910 int nice; 911 int inc; 912 id_t rtcid; 913 914 ASSERT(MUTEX_HELD(&pidlock)); 915 ASSERT(MUTEX_HELD(&(ttoproc(tp)->p_lock))); 916 917 /* 918 * The XPG5 standard requires that any realtime process or thread 919 * must be unaffected by a call to setpriority(). 920 */ 921 error = getcidbyname("RT", &rtcid); 922 if (error == 0 && tp->t_cid == rtcid) { 923 if (pcnice->pc_op == PC_SETNICE) 924 return (0); 925 } 926 927 if ((error = CL_DONICE(tp, CRED(), 0, &nice)) != 0) 928 return (error); 929 930 if (pcnice->pc_op == PC_GETNICE) { 931 /* 932 * If there is no change to priority, we should return the 933 * highest priority (lowest numerical value) pertaining to 934 * any of the specified threads. 935 */ 936 if (nice < pcnice->pc_val) 937 pcnice->pc_val = nice; 938 } else { 939 ASSERT(pcnice->pc_op == PC_SETNICE); 940 /* 941 * Try to change the nice value of the thread. 942 */ 943 inc = pcnice->pc_val - nice; 944 945 error = CL_DONICE(tp, CRED(), inc, &inc); 946 schedctl_set_cidpri(tp); 947 } 948 949 return (error); 950 } 951 952 int 953 setprocnice(proc_t *pp, pcnice_t *pcnice) 954 { 955 kthread_t *tp; 956 int retval = 0; 957 int error; 958 959 ASSERT(MUTEX_HELD(&pidlock)); 960 mutex_enter(&pp->p_lock); 961 962 if ((tp = pp->p_tlist) == NULL) { 963 mutex_exit(&pp->p_lock); 964 return (ESRCH); 965 } 966 967 /* 968 * Check permissions before changing the nice value. 969 */ 970 if (pcnice->pc_op == PC_SETNICE) { 971 if (!prochasprocperm(pp, curproc, CRED())) { 972 mutex_exit(&pp->p_lock); 973 return (EPERM); 974 } 975 } 976 977 do { 978 error = setthreadnice(pcnice, tp); 979 if (error) 980 retval = error; 981 } while ((tp = tp->t_forw) != pp->p_tlist); 982 983 mutex_exit(&pp->p_lock); 984 return (retval); 985 } 986 987 /* 988 * Update the nice value of the specified LWP or set of processes. 989 */ 990 static int 991 donice(procset_t *procset, pcnice_t *pcnice) 992 { 993 int err_proc = 0; 994 int err_thread = 0; 995 int err = 0; 996 997 /* 998 * Sanity check. 999 */ 1000 if (pcnice->pc_op != PC_GETNICE && pcnice->pc_op != PC_SETNICE) 1001 return (EINVAL); 1002 1003 /* 1004 * If it is PC_GETNICE operation then set pc_val to the largest 1005 * possible nice value to help us find the lowest nice value 1006 * pertaining to any of the specified processes. 1007 */ 1008 if (pcnice->pc_op == PC_GETNICE) 1009 pcnice->pc_val = NZERO; 1010 1011 if (procset->p_lidtype != P_LWPID || 1012 procset->p_ridtype != P_LWPID) 1013 err_proc = dotoprocs(procset, setprocnice, (char *)pcnice); 1014 1015 if (procset->p_lidtype == P_LWPID || procset->p_ridtype == P_LWPID) { 1016 err_thread = dotolwp(procset, setthreadnice, (char *)pcnice); 1017 /* 1018 * dotolwp() can return with p_lock held. This is required 1019 * for the priocntl GETPARMS case. So, here we just release 1020 * the p_lock. 1021 */ 1022 if (MUTEX_HELD(&curproc->p_lock)) 1023 mutex_exit(&curproc->p_lock); 1024 1025 /* 1026 * If we were called for a single LWP, then ignore ESRCH 1027 * returned by the previous dotoprocs() call. 1028 */ 1029 if (err_proc == ESRCH) 1030 err_proc = 0; 1031 } 1032 1033 /* 1034 * dotoprocs() ignores the init process if it is in the set, unless 1035 * it was the only process found. We want to make sure init is not 1036 * excluded if we're going PC_GETNICE operation. 1037 */ 1038 if (pcnice->pc_op == PC_GETNICE) { 1039 proc_t *initpp; 1040 1041 mutex_enter(&pidlock); 1042 initpp = prfind(P_INITPID); 1043 if (initpp != NULL && procinset(initpp, procset)) 1044 err = setprocnice(initpp, pcnice); 1045 mutex_exit(&pidlock); 1046 } 1047 1048 /* 1049 * We're returning the latest error here that we've got back from 1050 * the setthreadnice() or setprocnice(). That is, err_thread and/or 1051 * err_proc can be replaced by err. 1052 */ 1053 if (!err) 1054 err = err_thread ? err_thread : err_proc; 1055 1056 return (err); 1057 } 1058 1059 int 1060 setthreadprio(pcprio_t *pcprio, kthread_t *tp) 1061 { 1062 int prio = 0; 1063 int incr; 1064 int error; 1065 1066 ASSERT(MUTEX_HELD(&pidlock)); 1067 ASSERT(MUTEX_HELD(&(ttoproc(tp)->p_lock))); 1068 1069 if (pcprio->pc_op == PC_SETPRIO && pcprio->pc_cid != tp->t_cid) { 1070 /* 1071 * Target thread must change to new class. 1072 * See comments in parmsset(), from where this code was copied. 1073 */ 1074 void *bufp = NULL; 1075 caddr_t clprocp = (caddr_t)tp->t_cldata; 1076 id_t oldcid = tp->t_cid; 1077 1078 error = CL_CANEXIT(tp, NULL); 1079 if (error) 1080 return (error); 1081 if (CL_ALLOC(&bufp, pcprio->pc_cid, KM_NOSLEEP) != 0) 1082 return (ENOMEM); 1083 error = CL_ENTERCLASS(tp, pcprio->pc_cid, NULL, CRED(), bufp); 1084 if (error) { 1085 CL_FREE(pcprio->pc_cid, bufp); 1086 return (error); 1087 } 1088 CL_EXITCLASS(oldcid, clprocp); 1089 schedctl_set_cidpri(tp); 1090 } 1091 1092 if ((error = CL_DOPRIO(tp, CRED(), 0, &prio)) != 0) 1093 return (error); 1094 1095 if (pcprio->pc_op == PC_GETPRIO) { 1096 /* 1097 * If we are not setting the priority, we should return the 1098 * highest priority pertaining to any of the specified threads. 1099 */ 1100 if (prio > pcprio->pc_val) { 1101 pcprio->pc_cid = tp->t_cid; 1102 pcprio->pc_val = prio; 1103 } 1104 } else if (prio != pcprio->pc_val) { 1105 /* 1106 * Try to change the priority of the thread. 1107 */ 1108 incr = pcprio->pc_val - prio; 1109 error = CL_DOPRIO(tp, CRED(), incr, &prio); 1110 schedctl_set_cidpri(tp); 1111 } 1112 1113 return (error); 1114 } 1115 1116 int 1117 setprocprio(proc_t *pp, pcprio_t *pcprio) 1118 { 1119 kthread_t *tp; 1120 int retval = 0; 1121 int error; 1122 1123 ASSERT(MUTEX_HELD(&pidlock)); 1124 mutex_enter(&pp->p_lock); 1125 1126 if ((tp = pp->p_tlist) == NULL) { 1127 mutex_exit(&pp->p_lock); 1128 return (ESRCH); 1129 } 1130 1131 /* 1132 * Check permissions before changing the prio value. 1133 */ 1134 if (pcprio->pc_op == PC_SETPRIO) { 1135 if (!prochasprocperm(pp, curproc, CRED())) { 1136 mutex_exit(&pp->p_lock); 1137 return (EPERM); 1138 } 1139 } 1140 1141 do { 1142 error = setthreadprio(pcprio, tp); 1143 if (error) 1144 retval = error; 1145 } while ((tp = tp->t_forw) != pp->p_tlist); 1146 1147 mutex_exit(&pp->p_lock); 1148 return (retval); 1149 } 1150 1151 /* 1152 * Set the class and priority of the specified LWP or set of processes. 1153 */ 1154 static int 1155 doprio(procset_t *procset, pcprio_t *pcprio) 1156 { 1157 int err_proc = 0; 1158 int err_thread = 0; 1159 int err = 0; 1160 1161 /* 1162 * Sanity check. 1163 */ 1164 if (pcprio->pc_op != PC_GETPRIO && pcprio->pc_op != PC_SETPRIO) 1165 return (EINVAL); 1166 if (pcprio->pc_op == PC_SETPRIO && 1167 (pcprio->pc_cid >= loaded_classes || pcprio->pc_cid < 1)) 1168 return (EINVAL); 1169 1170 /* 1171 * If it is a PC_GETPRIO operation then set pc_val to the smallest 1172 * possible prio value to help us find the highest priority 1173 * pertaining to any of the specified processes. 1174 */ 1175 if (pcprio->pc_op == PC_GETPRIO) 1176 pcprio->pc_val = SHRT_MIN; 1177 1178 if (procset->p_lidtype != P_LWPID || 1179 procset->p_ridtype != P_LWPID) 1180 err_proc = dotoprocs(procset, setprocprio, (char *)pcprio); 1181 1182 if (procset->p_lidtype == P_LWPID || procset->p_ridtype == P_LWPID) { 1183 err_thread = dotolwp(procset, setthreadprio, (char *)pcprio); 1184 /* 1185 * dotolwp() can return with p_lock held. This is required 1186 * for the priocntl GETPARMS case. So, here we just release 1187 * the p_lock. 1188 */ 1189 if (MUTEX_HELD(&curproc->p_lock)) 1190 mutex_exit(&curproc->p_lock); 1191 1192 /* 1193 * If we were called for a single LWP, then ignore ESRCH 1194 * returned by the previous dotoprocs() call. 1195 */ 1196 if (err_proc == ESRCH) 1197 err_proc = 0; 1198 } 1199 1200 /* 1201 * dotoprocs() ignores the init process if it is in the set, unless 1202 * it was the only process found. We want to make sure init is not 1203 * excluded if we're going PC_GETPRIO operation. 1204 */ 1205 if (pcprio->pc_op == PC_GETPRIO) { 1206 proc_t *initpp; 1207 1208 mutex_enter(&pidlock); 1209 initpp = prfind(P_INITPID); 1210 if (initpp != NULL && procinset(initpp, procset)) 1211 err = setprocprio(initpp, pcprio); 1212 mutex_exit(&pidlock); 1213 } 1214 1215 /* 1216 * We're returning the latest error here that we've got back from 1217 * the setthreadprio() or setprocprio(). That is, err_thread and/or 1218 * err_proc can be replaced by err. 1219 */ 1220 if (!err) 1221 err = err_thread ? err_thread : err_proc; 1222 1223 return (err); 1224 } 1225