1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 2308 fr157268 * Common Development and Distribution License (the "License"). 6 2308 fr157268 * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 9150 Gangadhar * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #include <sys/types.h> 27 0 stevel #include <sys/systm.h> 28 0 stevel #include <sys/cmn_err.h> 29 0 stevel #include <sys/cpuvar.h> 30 0 stevel #include <sys/thread.h> 31 0 stevel #include <sys/disp.h> 32 0 stevel #include <sys/kmem.h> 33 0 stevel #include <sys/debug.h> 34 0 stevel #include <sys/sysmacros.h> 35 0 stevel #include <sys/cpupart.h> 36 0 stevel #include <sys/pset.h> 37 0 stevel #include <sys/modctl.h> 38 0 stevel #include <sys/syscall.h> 39 0 stevel #include <sys/task.h> 40 0 stevel #include <sys/loadavg.h> 41 0 stevel #include <sys/fss.h> 42 0 stevel #include <sys/pool.h> 43 0 stevel #include <sys/pool_pset.h> 44 0 stevel #include <sys/policy.h> 45 0 stevel #include <sys/zone.h> 46 0 stevel #include <sys/contract/process_impl.h> 47 0 stevel 48 0 stevel static int pset(int, long, long, long, long); 49 0 stevel 50 0 stevel static struct sysent pset_sysent = { 51 0 stevel 5, 52 0 stevel SE_ARGC | SE_NOUNLOAD, 53 0 stevel (int (*)())pset, 54 0 stevel }; 55 0 stevel 56 0 stevel static struct modlsys modlsys = { 57 0 stevel &mod_syscallops, "processor sets", &pset_sysent 58 0 stevel }; 59 0 stevel 60 0 stevel #ifdef _SYSCALL32_IMPL 61 0 stevel static struct modlsys modlsys32 = { 62 0 stevel &mod_syscallops32, "32-bit pset(2) syscall", &pset_sysent 63 0 stevel }; 64 0 stevel #endif 65 0 stevel 66 0 stevel static struct modlinkage modlinkage = { 67 0 stevel MODREV_1, 68 0 stevel &modlsys, 69 0 stevel #ifdef _SYSCALL32_IMPL 70 0 stevel &modlsys32, 71 0 stevel #endif 72 0 stevel NULL 73 0 stevel }; 74 0 stevel 75 0 stevel #define PSET_BADATTR(attr) ((~PSET_NOESCAPE) & (attr)) 76 0 stevel 77 0 stevel int 78 0 stevel _init(void) 79 0 stevel { 80 0 stevel return (mod_install(&modlinkage)); 81 0 stevel } 82 0 stevel 83 0 stevel int 84 0 stevel _info(struct modinfo *modinfop) 85 0 stevel { 86 0 stevel return (mod_info(&modlinkage, modinfop)); 87 0 stevel } 88 0 stevel 89 0 stevel static int 90 0 stevel pset_create(psetid_t *psetp) 91 0 stevel { 92 0 stevel psetid_t newpset; 93 0 stevel int error; 94 0 stevel 95 0 stevel if (secpolicy_pset(CRED()) != 0) 96 0 stevel return (set_errno(EPERM)); 97 0 stevel 98 0 stevel pool_lock(); 99 0 stevel if (pool_state == POOL_ENABLED) { 100 0 stevel pool_unlock(); 101 0 stevel return (set_errno(ENOTSUP)); 102 0 stevel } 103 0 stevel error = cpupart_create(&newpset); 104 0 stevel if (error) { 105 0 stevel pool_unlock(); 106 0 stevel return (set_errno(error)); 107 0 stevel } 108 0 stevel if (copyout(&newpset, psetp, sizeof (psetid_t)) != 0) { 109 0 stevel (void) cpupart_destroy(newpset); 110 0 stevel pool_unlock(); 111 0 stevel return (set_errno(EFAULT)); 112 0 stevel } 113 0 stevel pool_unlock(); 114 0 stevel return (error); 115 0 stevel } 116 0 stevel 117 0 stevel static int 118 0 stevel pset_destroy(psetid_t pset) 119 0 stevel { 120 0 stevel int error; 121 0 stevel 122 0 stevel if (secpolicy_pset(CRED()) != 0) 123 0 stevel return (set_errno(EPERM)); 124 0 stevel 125 0 stevel pool_lock(); 126 0 stevel if (pool_state == POOL_ENABLED) { 127 0 stevel pool_unlock(); 128 0 stevel return (set_errno(ENOTSUP)); 129 0 stevel } 130 0 stevel error = cpupart_destroy(pset); 131 0 stevel pool_unlock(); 132 0 stevel if (error) 133 0 stevel return (set_errno(error)); 134 0 stevel else 135 0 stevel return (0); 136 0 stevel } 137 0 stevel 138 0 stevel static int 139 0 stevel pset_assign(psetid_t pset, processorid_t cpuid, psetid_t *opset, int forced) 140 0 stevel { 141 0 stevel psetid_t oldpset; 142 0 stevel int error = 0; 143 0 stevel cpu_t *cp; 144 0 stevel 145 0 stevel if (pset != PS_QUERY && secpolicy_pset(CRED()) != 0) 146 0 stevel return (set_errno(EPERM)); 147 0 stevel 148 0 stevel pool_lock(); 149 0 stevel if (pset != PS_QUERY && pool_state == POOL_ENABLED) { 150 0 stevel pool_unlock(); 151 0 stevel return (set_errno(ENOTSUP)); 152 0 stevel } 153 0 stevel 154 0 stevel mutex_enter(&cpu_lock); 155 0 stevel if ((cp = cpu_get(cpuid)) == NULL) { 156 0 stevel mutex_exit(&cpu_lock); 157 0 stevel pool_unlock(); 158 0 stevel return (set_errno(EINVAL)); 159 0 stevel } 160 0 stevel 161 0 stevel oldpset = cpupart_query_cpu(cp); 162 0 stevel 163 0 stevel if (pset != PS_QUERY) 164 0 stevel error = cpupart_attach_cpu(pset, cp, forced); 165 0 stevel mutex_exit(&cpu_lock); 166 0 stevel pool_unlock(); 167 0 stevel 168 0 stevel if (error) 169 0 stevel return (set_errno(error)); 170 0 stevel 171 0 stevel if (opset != NULL) 172 0 stevel if (copyout(&oldpset, opset, sizeof (psetid_t)) != 0) 173 0 stevel return (set_errno(EFAULT)); 174 0 stevel 175 0 stevel return (0); 176 0 stevel } 177 0 stevel 178 0 stevel static int 179 0 stevel pset_info(psetid_t pset, int *typep, uint_t *numcpusp, 180 0 stevel processorid_t *cpulistp) 181 0 stevel { 182 0 stevel int pset_type; 183 0 stevel uint_t user_ncpus = 0, real_ncpus, copy_ncpus; 184 0 stevel processorid_t *pset_cpus = NULL; 185 0 stevel int error = 0; 186 0 stevel 187 0 stevel if (numcpusp != NULL) { 188 0 stevel if (copyin(numcpusp, &user_ncpus, sizeof (uint_t)) != 0) 189 0 stevel return (set_errno(EFAULT)); 190 0 stevel } 191 0 stevel 192 0 stevel if (user_ncpus > max_ncpus) /* sanity check */ 193 0 stevel user_ncpus = max_ncpus; 194 0 stevel if (user_ncpus != 0 && cpulistp != NULL) 195 0 stevel pset_cpus = kmem_alloc(sizeof (processorid_t) * user_ncpus, 196 0 stevel KM_SLEEP); 197 0 stevel 198 0 stevel real_ncpus = user_ncpus; 199 0 stevel if ((error = cpupart_get_cpus(&pset, pset_cpus, &real_ncpus)) != 0) 200 0 stevel goto out; 201 0 stevel 202 0 stevel /* 203 0 stevel * Now copyout the information about this processor set. 204 0 stevel */ 205 0 stevel 206 0 stevel /* 207 0 stevel * Get number of cpus to copy back. If the user didn't pass in 208 0 stevel * a big enough buffer, only copy back as many cpus as fits in 209 0 stevel * the buffer but copy back the real number of cpus. 210 0 stevel */ 211 0 stevel 212 0 stevel if (user_ncpus != 0 && cpulistp != NULL) { 213 0 stevel copy_ncpus = MIN(real_ncpus, user_ncpus); 214 0 stevel if (copyout(pset_cpus, cpulistp, 215 0 stevel sizeof (processorid_t) * copy_ncpus) != 0) { 216 0 stevel error = EFAULT; 217 0 stevel goto out; 218 0 stevel } 219 0 stevel } 220 0 stevel if (pset_cpus != NULL) 221 0 stevel kmem_free(pset_cpus, sizeof (processorid_t) * user_ncpus); 222 0 stevel if (typep != NULL) { 223 0 stevel if (pset == PS_NONE) 224 0 stevel pset_type = PS_NONE; 225 0 stevel else 226 0 stevel pset_type = PS_PRIVATE; 227 0 stevel if (copyout(&pset_type, typep, sizeof (int)) != 0) 228 0 stevel return (set_errno(EFAULT)); 229 0 stevel } 230 0 stevel if (numcpusp != NULL) 231 0 stevel if (copyout(&real_ncpus, numcpusp, sizeof (uint_t)) != 0) 232 0 stevel return (set_errno(EFAULT)); 233 0 stevel return (0); 234 0 stevel 235 0 stevel out: 236 0 stevel if (pset_cpus != NULL) 237 0 stevel kmem_free(pset_cpus, sizeof (processorid_t) * user_ncpus); 238 0 stevel return (set_errno(error)); 239 0 stevel } 240 0 stevel 241 0 stevel static int 242 0 stevel pset_bind_thread(kthread_t *tp, psetid_t pset, psetid_t *oldpset, void *projbuf, 243 0 stevel void *zonebuf) 244 0 stevel { 245 0 stevel int error = 0; 246 0 stevel 247 0 stevel ASSERT(pool_lock_held()); 248 0 stevel ASSERT(MUTEX_HELD(&cpu_lock)); 249 0 stevel ASSERT(MUTEX_HELD(&ttoproc(tp)->p_lock)); 250 0 stevel 251 0 stevel *oldpset = tp->t_bind_pset; 252 6298 akolb 253 6298 akolb switch (pset) { 254 6298 akolb case PS_SOFT: 255 6298 akolb TB_PSET_SOFT_SET(tp); 256 6298 akolb break; 257 6298 akolb 258 6298 akolb case PS_HARD: 259 6298 akolb TB_PSET_HARD_SET(tp); 260 6298 akolb break; 261 6298 akolb 262 6298 akolb case PS_QUERY: 263 6298 akolb break; 264 6298 akolb 265 6298 akolb case PS_QUERY_TYPE: 266 6298 akolb *oldpset = TB_PSET_IS_SOFT(tp) ? PS_SOFT : PS_HARD; 267 6298 akolb break; 268 6298 akolb 269 6298 akolb default: 270 0 stevel /* 271 0 stevel * Must have the same UID as the target process or 272 0 stevel * have PRIV_PROC_OWNER privilege. 273 0 stevel */ 274 0 stevel if (!hasprocperm(tp->t_cred, CRED())) 275 0 stevel return (EPERM); 276 0 stevel /* 277 0 stevel * Unbinding of an unbound thread should always succeed. 278 0 stevel */ 279 0 stevel if (*oldpset == PS_NONE && pset == PS_NONE) 280 0 stevel return (0); 281 0 stevel /* 282 0 stevel * Only privileged processes can move threads from psets with 283 0 stevel * PSET_NOESCAPE attribute. 284 0 stevel */ 285 0 stevel if ((tp->t_cpupart->cp_attr & PSET_NOESCAPE) && 286 0 stevel secpolicy_pset(CRED()) != 0) 287 0 stevel return (EPERM); 288 0 stevel if ((error = cpupart_bind_thread(tp, pset, 0, 289 0 stevel projbuf, zonebuf)) == 0) 290 0 stevel tp->t_bind_pset = pset; 291 6298 akolb 292 6298 akolb break; 293 0 stevel } 294 6298 akolb 295 0 stevel return (error); 296 0 stevel } 297 0 stevel 298 0 stevel static int 299 0 stevel pset_bind_process(proc_t *pp, psetid_t pset, psetid_t *oldpset, void *projbuf, 300 0 stevel void *zonebuf) 301 0 stevel { 302 0 stevel int error = 0; 303 0 stevel kthread_t *tp; 304 0 stevel 305 0 stevel /* skip kernel processes */ 306 6298 akolb if ((pset != PS_QUERY) && pp->p_flag & SSYS) { 307 0 stevel *oldpset = PS_NONE; 308 9150 Gangadhar return (ENOTSUP); 309 0 stevel } 310 0 stevel 311 0 stevel mutex_enter(&pp->p_lock); 312 0 stevel tp = pp->p_tlist; 313 0 stevel if (tp != NULL) { 314 0 stevel do { 315 0 stevel int rval; 316 0 stevel 317 0 stevel rval = pset_bind_thread(tp, pset, oldpset, projbuf, 318 0 stevel zonebuf); 319 0 stevel if (error == 0) 320 0 stevel error = rval; 321 0 stevel } while ((tp = tp->t_forw) != pp->p_tlist); 322 0 stevel } else 323 0 stevel error = ESRCH; 324 0 stevel mutex_exit(&pp->p_lock); 325 0 stevel 326 0 stevel return (error); 327 0 stevel } 328 0 stevel 329 0 stevel static int 330 0 stevel pset_bind_task(task_t *tk, psetid_t pset, psetid_t *oldpset, void *projbuf, 331 0 stevel void *zonebuf) 332 0 stevel { 333 0 stevel int error = 0; 334 0 stevel proc_t *pp; 335 0 stevel 336 0 stevel ASSERT(MUTEX_HELD(&pidlock)); 337 0 stevel 338 0 stevel if ((pp = tk->tk_memb_list) == NULL) { 339 0 stevel return (ESRCH); 340 0 stevel } 341 0 stevel 342 0 stevel do { 343 0 stevel int rval; 344 0 stevel 345 9150 Gangadhar if (!(pp->p_flag & SSYS)) { 346 9150 Gangadhar rval = pset_bind_process(pp, pset, oldpset, projbuf, 347 9150 Gangadhar zonebuf); 348 9150 Gangadhar if (error == 0) 349 9150 Gangadhar error = rval; 350 9150 Gangadhar } 351 0 stevel } while ((pp = pp->p_tasknext) != tk->tk_memb_list); 352 0 stevel 353 0 stevel return (error); 354 0 stevel } 355 0 stevel 356 0 stevel static int 357 0 stevel pset_bind_project(kproject_t *kpj, psetid_t pset, psetid_t *oldpset, 358 0 stevel void *projbuf, void *zonebuf) 359 0 stevel { 360 0 stevel int error = 0; 361 0 stevel proc_t *pp; 362 0 stevel 363 0 stevel ASSERT(MUTEX_HELD(&pidlock)); 364 0 stevel 365 0 stevel for (pp = practive; pp != NULL; pp = pp->p_next) { 366 0 stevel if (pp->p_tlist == NULL) 367 0 stevel continue; 368 9150 Gangadhar if (pp->p_task->tk_proj == kpj && !(pp->p_flag & SSYS)) { 369 0 stevel int rval; 370 0 stevel 371 0 stevel rval = pset_bind_process(pp, pset, oldpset, projbuf, 372 0 stevel zonebuf); 373 0 stevel if (error == 0) 374 0 stevel error = rval; 375 0 stevel } 376 0 stevel } 377 0 stevel 378 0 stevel return (error); 379 0 stevel } 380 0 stevel 381 0 stevel static int 382 0 stevel pset_bind_zone(zone_t *zptr, psetid_t pset, psetid_t *oldpset, void *projbuf, 383 0 stevel void *zonebuf) 384 0 stevel { 385 0 stevel int error = 0; 386 0 stevel proc_t *pp; 387 0 stevel 388 0 stevel ASSERT(MUTEX_HELD(&pidlock)); 389 0 stevel 390 0 stevel for (pp = practive; pp != NULL; pp = pp->p_next) { 391 9150 Gangadhar if (pp->p_zone == zptr && !(pp->p_flag & SSYS)) { 392 0 stevel int rval; 393 0 stevel 394 0 stevel rval = pset_bind_process(pp, pset, oldpset, projbuf, 395 0 stevel zonebuf); 396 0 stevel if (error == 0) 397 0 stevel error = rval; 398 0 stevel } 399 0 stevel } 400 0 stevel 401 0 stevel return (error); 402 0 stevel } 403 0 stevel 404 0 stevel /* 405 0 stevel * Unbind all threads from the specified processor set, or from all 406 0 stevel * processor sets. 407 0 stevel */ 408 0 stevel static int 409 0 stevel pset_unbind(psetid_t pset, void *projbuf, void *zonebuf, idtype_t idtype) 410 0 stevel { 411 0 stevel psetid_t olbind; 412 0 stevel kthread_t *tp; 413 0 stevel int error = 0; 414 0 stevel int rval; 415 0 stevel proc_t *pp; 416 0 stevel 417 0 stevel ASSERT(MUTEX_HELD(&cpu_lock)); 418 0 stevel 419 0 stevel if (idtype == P_PSETID && cpupart_find(pset) == NULL) 420 0 stevel return (EINVAL); 421 0 stevel 422 0 stevel mutex_enter(&pidlock); 423 0 stevel for (pp = practive; pp != NULL; pp = pp->p_next) { 424 0 stevel mutex_enter(&pp->p_lock); 425 0 stevel tp = pp->p_tlist; 426 0 stevel /* 427 0 stevel * Skip zombies and kernel processes, and processes in 428 0 stevel * other zones, if called from a non-global zone. 429 0 stevel */ 430 0 stevel if (tp == NULL || (pp->p_flag & SSYS) || 431 0 stevel !HASZONEACCESS(curproc, pp->p_zone->zone_id)) { 432 0 stevel mutex_exit(&pp->p_lock); 433 0 stevel continue; 434 0 stevel } 435 0 stevel do { 436 0 stevel if ((idtype == P_PSETID && tp->t_bind_pset != pset) || 437 0 stevel (idtype == P_ALL && tp->t_bind_pset == PS_NONE)) 438 0 stevel continue; 439 0 stevel rval = pset_bind_thread(tp, PS_NONE, &olbind, 440 0 stevel projbuf, zonebuf); 441 0 stevel if (error == 0) 442 0 stevel error = rval; 443 0 stevel } while ((tp = tp->t_forw) != pp->p_tlist); 444 0 stevel mutex_exit(&pp->p_lock); 445 0 stevel } 446 0 stevel mutex_exit(&pidlock); 447 0 stevel return (error); 448 0 stevel } 449 0 stevel 450 0 stevel static int 451 0 stevel pset_bind_contract(cont_process_t *ctp, psetid_t pset, psetid_t *oldpset, 452 0 stevel void *projbuf, void *zonebuf) 453 0 stevel { 454 0 stevel int error = 0; 455 0 stevel proc_t *pp; 456 0 stevel 457 0 stevel ASSERT(MUTEX_HELD(&pidlock)); 458 0 stevel 459 0 stevel for (pp = practive; pp != NULL; pp = pp->p_next) { 460 0 stevel if (pp->p_ct_process == ctp) { 461 0 stevel int rval; 462 0 stevel 463 0 stevel rval = pset_bind_process(pp, pset, oldpset, projbuf, 464 0 stevel zonebuf); 465 0 stevel if (error == 0) 466 0 stevel error = rval; 467 0 stevel } 468 0 stevel } 469 0 stevel 470 0 stevel return (error); 471 0 stevel } 472 0 stevel 473 10089 Surya /* 474 10089 Surya * Bind the lwp:id of process:pid to processor set: pset 475 10089 Surya */ 476 10089 Surya static int 477 10089 Surya pset_bind_lwp(psetid_t pset, id_t id, pid_t pid, psetid_t *opset) 478 10089 Surya { 479 10089 Surya kthread_t *tp; 480 10089 Surya proc_t *pp; 481 10089 Surya psetid_t oldpset; 482 10089 Surya void *projbuf, *zonebuf; 483 10089 Surya int error = 0; 484 10089 Surya 485 10089 Surya pool_lock(); 486 10089 Surya mutex_enter(&cpu_lock); 487 10089 Surya projbuf = fss_allocbuf(FSS_NPROJ_BUF, FSS_ALLOC_PROJ); 488 10089 Surya zonebuf = fss_allocbuf(FSS_NPROJ_BUF, FSS_ALLOC_ZONE); 489 10089 Surya 490 10089 Surya mutex_enter(&pidlock); 491 10089 Surya if ((pid == P_MYID && id == P_MYID) || 492 10089 Surya (pid == curproc->p_pid && id == P_MYID)) { 493 10089 Surya pp = curproc; 494 10089 Surya tp = curthread; 495 10089 Surya mutex_enter(&pp->p_lock); 496 10089 Surya } else { 497 10089 Surya if (pid == P_MYID) { 498 10089 Surya pp = curproc; 499 10089 Surya } else if ((pp = prfind(pid)) == NULL) { 500 10089 Surya error = ESRCH; 501 10089 Surya goto err; 502 10089 Surya } 503 10089 Surya if (pp != curproc && id == P_MYID) { 504 10089 Surya error = EINVAL; 505 10089 Surya goto err; 506 10089 Surya } 507 10089 Surya mutex_enter(&pp->p_lock); 508 10089 Surya if ((tp = idtot(pp, id)) == NULL) { 509 10089 Surya mutex_exit(&pp->p_lock); 510 10089 Surya error = ESRCH; 511 10089 Surya goto err; 512 10089 Surya } 513 10089 Surya } 514 10089 Surya 515 10089 Surya error = pset_bind_thread(tp, pset, &oldpset, projbuf, zonebuf); 516 10089 Surya mutex_exit(&pp->p_lock); 517 10089 Surya err: 518 10089 Surya mutex_exit(&pidlock); 519 10089 Surya 520 10089 Surya fss_freebuf(projbuf, FSS_ALLOC_PROJ); 521 10089 Surya fss_freebuf(zonebuf, FSS_ALLOC_ZONE); 522 10089 Surya mutex_exit(&cpu_lock); 523 10089 Surya pool_unlock(); 524 10089 Surya if (opset != NULL) { 525 10089 Surya if (copyout(&oldpset, opset, sizeof (psetid_t)) != 0) 526 10089 Surya return (set_errno(EFAULT)); 527 10089 Surya } 528 10089 Surya if (error != 0) 529 10089 Surya return (set_errno(error)); 530 10089 Surya return (0); 531 10089 Surya } 532 10089 Surya 533 0 stevel static int 534 0 stevel pset_bind(psetid_t pset, idtype_t idtype, id_t id, psetid_t *opset) 535 0 stevel { 536 0 stevel kthread_t *tp; 537 0 stevel proc_t *pp; 538 0 stevel task_t *tk; 539 0 stevel kproject_t *kpj; 540 0 stevel contract_t *ct; 541 0 stevel zone_t *zptr; 542 0 stevel psetid_t oldpset; 543 0 stevel int error = 0; 544 0 stevel void *projbuf, *zonebuf; 545 0 stevel 546 0 stevel pool_lock(); 547 6298 akolb if ((pset != PS_QUERY) && (pset != PS_SOFT) && 548 6298 akolb (pset != PS_HARD) && (pset != PS_QUERY_TYPE)) { 549 0 stevel /* 550 0 stevel * Check if the set actually exists before checking 551 0 stevel * permissions. This is the historical error 552 0 stevel * precedence. Note that if pset was PS_MYID, the 553 0 stevel * cpupart_get_cpus call will change it to the 554 0 stevel * processor set id of the caller (or PS_NONE if the 555 0 stevel * caller is not bound to a processor set). 556 0 stevel */ 557 0 stevel if (pool_state == POOL_ENABLED) { 558 0 stevel pool_unlock(); 559 0 stevel return (set_errno(ENOTSUP)); 560 0 stevel } 561 0 stevel if (cpupart_get_cpus(&pset, NULL, NULL) != 0) { 562 0 stevel pool_unlock(); 563 0 stevel return (set_errno(EINVAL)); 564 0 stevel } else if (pset != PS_NONE && secpolicy_pset(CRED()) != 0) { 565 0 stevel pool_unlock(); 566 0 stevel return (set_errno(EPERM)); 567 0 stevel } 568 0 stevel } 569 0 stevel 570 0 stevel /* 571 0 stevel * Pre-allocate enough buffers for FSS for all active projects 572 0 stevel * and for all active zones on the system. Unused buffers will 573 0 stevel * be freed later by fss_freebuf(). 574 0 stevel */ 575 0 stevel mutex_enter(&cpu_lock); 576 0 stevel projbuf = fss_allocbuf(FSS_NPROJ_BUF, FSS_ALLOC_PROJ); 577 0 stevel zonebuf = fss_allocbuf(FSS_NPROJ_BUF, FSS_ALLOC_ZONE); 578 0 stevel 579 0 stevel switch (idtype) { 580 0 stevel case P_LWPID: 581 0 stevel pp = curproc; 582 0 stevel mutex_enter(&pidlock); 583 0 stevel mutex_enter(&pp->p_lock); 584 0 stevel if (id == P_MYID) { 585 0 stevel tp = curthread; 586 0 stevel } else { 587 0 stevel if ((tp = idtot(pp, id)) == NULL) { 588 0 stevel mutex_exit(&pp->p_lock); 589 0 stevel mutex_exit(&pidlock); 590 0 stevel error = ESRCH; 591 0 stevel break; 592 0 stevel } 593 0 stevel } 594 0 stevel error = pset_bind_thread(tp, pset, &oldpset, projbuf, zonebuf); 595 0 stevel mutex_exit(&pp->p_lock); 596 0 stevel mutex_exit(&pidlock); 597 0 stevel break; 598 0 stevel 599 0 stevel case P_PID: 600 0 stevel mutex_enter(&pidlock); 601 0 stevel if (id == P_MYID) { 602 0 stevel pp = curproc; 603 0 stevel } else if ((pp = prfind(id)) == NULL) { 604 0 stevel mutex_exit(&pidlock); 605 0 stevel error = ESRCH; 606 0 stevel break; 607 0 stevel } 608 0 stevel error = pset_bind_process(pp, pset, &oldpset, projbuf, zonebuf); 609 0 stevel mutex_exit(&pidlock); 610 0 stevel break; 611 0 stevel 612 0 stevel case P_TASKID: 613 0 stevel mutex_enter(&pidlock); 614 0 stevel if (id == P_MYID) 615 0 stevel id = curproc->p_task->tk_tkid; 616 0 stevel if ((tk = task_hold_by_id(id)) == NULL) { 617 0 stevel mutex_exit(&pidlock); 618 0 stevel error = ESRCH; 619 0 stevel break; 620 0 stevel } 621 0 stevel error = pset_bind_task(tk, pset, &oldpset, projbuf, zonebuf); 622 0 stevel mutex_exit(&pidlock); 623 0 stevel task_rele(tk); 624 0 stevel break; 625 0 stevel 626 0 stevel case P_PROJID: 627 3247 gjelinek pp = curproc; 628 0 stevel if (id == P_MYID) 629 0 stevel id = curprojid(); 630 3247 gjelinek if ((kpj = project_hold_by_id(id, pp->p_zone, 631 0 stevel PROJECT_HOLD_FIND)) == NULL) { 632 0 stevel error = ESRCH; 633 0 stevel break; 634 0 stevel } 635 0 stevel mutex_enter(&pidlock); 636 0 stevel error = pset_bind_project(kpj, pset, &oldpset, projbuf, 637 0 stevel zonebuf); 638 0 stevel mutex_exit(&pidlock); 639 0 stevel project_rele(kpj); 640 0 stevel break; 641 0 stevel 642 0 stevel case P_ZONEID: 643 0 stevel if (id == P_MYID) 644 0 stevel id = getzoneid(); 645 0 stevel if ((zptr = zone_find_by_id(id)) == NULL) { 646 0 stevel error = ESRCH; 647 0 stevel break; 648 0 stevel } 649 0 stevel mutex_enter(&pidlock); 650 0 stevel error = pset_bind_zone(zptr, pset, &oldpset, projbuf, zonebuf); 651 0 stevel mutex_exit(&pidlock); 652 0 stevel zone_rele(zptr); 653 0 stevel break; 654 0 stevel 655 0 stevel case P_CTID: 656 0 stevel if (id == P_MYID) 657 0 stevel id = PRCTID(curproc); 658 0 stevel if ((ct = contract_type_ptr(process_type, id, 659 0 stevel curproc->p_zone->zone_uniqid)) == NULL) { 660 0 stevel error = ESRCH; 661 0 stevel break; 662 0 stevel } 663 0 stevel mutex_enter(&pidlock); 664 0 stevel error = pset_bind_contract(ct->ct_data, pset, &oldpset, projbuf, 665 0 stevel zonebuf); 666 0 stevel mutex_exit(&pidlock); 667 0 stevel contract_rele(ct); 668 0 stevel break; 669 0 stevel 670 0 stevel case P_PSETID: 671 0 stevel if (id == P_MYID || pset != PS_NONE || !INGLOBALZONE(curproc)) { 672 0 stevel error = EINVAL; 673 0 stevel break; 674 0 stevel } 675 0 stevel error = pset_unbind(id, projbuf, zonebuf, idtype); 676 0 stevel break; 677 0 stevel 678 0 stevel case P_ALL: 679 0 stevel if (id == P_MYID || pset != PS_NONE || !INGLOBALZONE(curproc)) { 680 0 stevel error = EINVAL; 681 0 stevel break; 682 0 stevel } 683 0 stevel error = pset_unbind(PS_NONE, projbuf, zonebuf, idtype); 684 0 stevel break; 685 0 stevel 686 0 stevel default: 687 0 stevel error = EINVAL; 688 0 stevel break; 689 0 stevel } 690 0 stevel 691 0 stevel fss_freebuf(projbuf, FSS_ALLOC_PROJ); 692 0 stevel fss_freebuf(zonebuf, FSS_ALLOC_ZONE); 693 0 stevel mutex_exit(&cpu_lock); 694 0 stevel pool_unlock(); 695 0 stevel 696 0 stevel if (error != 0) 697 0 stevel return (set_errno(error)); 698 0 stevel if (opset != NULL) { 699 0 stevel if (copyout(&oldpset, opset, sizeof (psetid_t)) != 0) 700 0 stevel return (set_errno(EFAULT)); 701 0 stevel } 702 0 stevel return (0); 703 0 stevel } 704 0 stevel 705 0 stevel /* 706 0 stevel * Report load average statistics for the specified processor set. 707 0 stevel */ 708 0 stevel static int 709 0 stevel pset_getloadavg(psetid_t pset, int *buf, int nelem) 710 0 stevel { 711 2308 fr157268 int loadbuf[LOADAVG_NSTATS]; 712 0 stevel int error = 0; 713 0 stevel 714 0 stevel if (nelem < 0) 715 0 stevel return (set_errno(EINVAL)); 716 0 stevel 717 0 stevel /* 718 0 stevel * We keep the same number of load average statistics for processor 719 0 stevel * sets as we do for the system as a whole. 720 0 stevel */ 721 0 stevel if (nelem > LOADAVG_NSTATS) 722 0 stevel nelem = LOADAVG_NSTATS; 723 0 stevel 724 0 stevel mutex_enter(&cpu_lock); 725 0 stevel error = cpupart_get_loadavg(pset, loadbuf, nelem); 726 0 stevel mutex_exit(&cpu_lock); 727 0 stevel if (!error && nelem && copyout(loadbuf, buf, nelem * sizeof (int)) != 0) 728 0 stevel error = EFAULT; 729 0 stevel 730 0 stevel if (error) 731 0 stevel return (set_errno(error)); 732 0 stevel else 733 0 stevel return (0); 734 0 stevel } 735 0 stevel 736 0 stevel 737 0 stevel /* 738 0 stevel * Return list of active processor sets, up to a maximum indicated by 739 0 stevel * numpsets. The total number of processor sets is stored in the 740 0 stevel * location pointed to by numpsets. 741 0 stevel */ 742 0 stevel static int 743 0 stevel pset_list(psetid_t *psetlist, uint_t *numpsets) 744 0 stevel { 745 0 stevel uint_t user_npsets = 0; 746 0 stevel uint_t real_npsets; 747 0 stevel psetid_t *psets = NULL; 748 0 stevel int error = 0; 749 0 stevel 750 0 stevel if (numpsets != NULL) { 751 0 stevel if (copyin(numpsets, &user_npsets, sizeof (uint_t)) != 0) 752 0 stevel return (set_errno(EFAULT)); 753 0 stevel } 754 0 stevel 755 0 stevel /* 756 0 stevel * Get the list of all processor sets. First we need to find 757 0 stevel * out how many there are, so we can allocate a large enough 758 0 stevel * buffer. 759 0 stevel */ 760 0 stevel mutex_enter(&cpu_lock); 761 0 stevel if (!INGLOBALZONE(curproc) && pool_pset_enabled()) { 762 0 stevel psetid_t psetid = zone_pset_get(curproc->p_zone); 763 0 stevel 764 0 stevel if (psetid == PS_NONE) { 765 0 stevel real_npsets = 0; 766 0 stevel } else { 767 0 stevel real_npsets = 1; 768 0 stevel psets = kmem_alloc(real_npsets * sizeof (psetid_t), 769 0 stevel KM_SLEEP); 770 0 stevel psets[0] = psetid; 771 0 stevel } 772 0 stevel } else { 773 0 stevel real_npsets = cpupart_list(0, NULL, CP_ALL); 774 0 stevel if (real_npsets) { 775 0 stevel psets = kmem_alloc(real_npsets * sizeof (psetid_t), 776 0 stevel KM_SLEEP); 777 0 stevel (void) cpupart_list(psets, real_npsets, CP_ALL); 778 0 stevel } 779 0 stevel } 780 0 stevel mutex_exit(&cpu_lock); 781 0 stevel 782 0 stevel if (user_npsets > real_npsets) 783 0 stevel user_npsets = real_npsets; 784 0 stevel 785 0 stevel if (numpsets != NULL) { 786 0 stevel if (copyout(&real_npsets, numpsets, sizeof (uint_t)) != 0) 787 0 stevel error = EFAULT; 788 0 stevel else if (psetlist != NULL && user_npsets != 0) { 789 0 stevel if (copyout(psets, psetlist, 790 0 stevel user_npsets * sizeof (psetid_t)) != 0) 791 0 stevel error = EFAULT; 792 0 stevel } 793 0 stevel } 794 0 stevel 795 0 stevel if (real_npsets) 796 0 stevel kmem_free(psets, real_npsets * sizeof (psetid_t)); 797 0 stevel 798 0 stevel if (error) 799 0 stevel return (set_errno(error)); 800 0 stevel else 801 0 stevel return (0); 802 0 stevel } 803 0 stevel 804 0 stevel static int 805 0 stevel pset_setattr(psetid_t pset, uint_t attr) 806 0 stevel { 807 0 stevel int error; 808 0 stevel 809 0 stevel if (secpolicy_pset(CRED()) != 0) 810 0 stevel return (set_errno(EPERM)); 811 0 stevel pool_lock(); 812 0 stevel if (pool_state == POOL_ENABLED) { 813 0 stevel pool_unlock(); 814 0 stevel return (set_errno(ENOTSUP)); 815 0 stevel } 816 0 stevel if (pset == PS_QUERY || PSET_BADATTR(attr)) { 817 0 stevel pool_unlock(); 818 0 stevel return (set_errno(EINVAL)); 819 0 stevel } 820 0 stevel if ((error = cpupart_setattr(pset, attr)) != 0) { 821 0 stevel pool_unlock(); 822 0 stevel return (set_errno(error)); 823 0 stevel } 824 0 stevel pool_unlock(); 825 0 stevel return (0); 826 0 stevel } 827 0 stevel 828 0 stevel static int 829 0 stevel pset_getattr(psetid_t pset, uint_t *attrp) 830 0 stevel { 831 0 stevel int error = 0; 832 0 stevel uint_t attr; 833 0 stevel 834 0 stevel if (pset == PS_QUERY) 835 0 stevel return (set_errno(EINVAL)); 836 0 stevel if ((error = cpupart_getattr(pset, &attr)) != 0) 837 0 stevel return (set_errno(error)); 838 0 stevel if (copyout(&attr, attrp, sizeof (uint_t)) != 0) 839 0 stevel return (set_errno(EFAULT)); 840 0 stevel return (0); 841 0 stevel } 842 0 stevel 843 0 stevel static int 844 0 stevel pset(int subcode, long arg1, long arg2, long arg3, long arg4) 845 0 stevel { 846 0 stevel switch (subcode) { 847 0 stevel case PSET_CREATE: 848 0 stevel return (pset_create((psetid_t *)arg1)); 849 0 stevel case PSET_DESTROY: 850 0 stevel return (pset_destroy((psetid_t)arg1)); 851 0 stevel case PSET_ASSIGN: 852 0 stevel return (pset_assign((psetid_t)arg1, 853 0 stevel (processorid_t)arg2, (psetid_t *)arg3, 0)); 854 0 stevel case PSET_INFO: 855 0 stevel return (pset_info((psetid_t)arg1, (int *)arg2, 856 0 stevel (uint_t *)arg3, (processorid_t *)arg4)); 857 0 stevel case PSET_BIND: 858 0 stevel return (pset_bind((psetid_t)arg1, (idtype_t)arg2, 859 0 stevel (id_t)arg3, (psetid_t *)arg4)); 860 10089 Surya case PSET_BIND_LWP: 861 10089 Surya return (pset_bind_lwp((psetid_t)arg1, (id_t)arg2, 862 10089 Surya (pid_t)arg3, (psetid_t *)arg4)); 863 0 stevel case PSET_GETLOADAVG: 864 0 stevel return (pset_getloadavg((psetid_t)arg1, (int *)arg2, 865 0 stevel (int)arg3)); 866 0 stevel case PSET_LIST: 867 0 stevel return (pset_list((psetid_t *)arg1, (uint_t *)arg2)); 868 0 stevel case PSET_SETATTR: 869 0 stevel return (pset_setattr((psetid_t)arg1, (uint_t)arg2)); 870 0 stevel case PSET_GETATTR: 871 0 stevel return (pset_getattr((psetid_t)arg1, (uint_t *)arg2)); 872 0 stevel case PSET_ASSIGN_FORCED: 873 0 stevel return (pset_assign((psetid_t)arg1, 874 0 stevel (processorid_t)arg2, (psetid_t *)arg3, 1)); 875 0 stevel default: 876 0 stevel return (set_errno(EINVAL)); 877 0 stevel } 878 0 stevel } 879