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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/atomic.h> 30 #include <sys/cmn_err.h> 31 #include <sys/exacct.h> 32 #include <sys/id_space.h> 33 #include <sys/kmem.h> 34 #include <sys/modhash.h> 35 #include <sys/mutex.h> 36 #include <sys/proc.h> 37 #include <sys/project.h> 38 #include <sys/rctl.h> 39 #include <sys/systm.h> 40 #include <sys/task.h> 41 #include <sys/time.h> 42 #include <sys/types.h> 43 #include <sys/zone.h> 44 #include <sys/cpuvar.h> 45 #include <sys/fss.h> 46 #include <sys/class.h> 47 #include <sys/project.h> 48 49 /* 50 * Tasks 51 * 52 * A task is a collection of processes, associated with a common project ID 53 * and related by a common initial parent. The task primarily represents a 54 * natural process sequence with known resource usage, although it can also be 55 * viewed as a convenient grouping of processes for signal delivery, processor 56 * binding, and administrative operations. 57 * 58 * Membership and observership 59 * We can conceive of situations where processes outside of the task may wish 60 * to examine the resource usage of the task. Similarly, a number of the 61 * administrative operations on a task can be performed by processes who are 62 * not members of the task. Accordingly, we must design a locking strategy 63 * where observers of the task, who wish to examine or operate on the task, 64 * and members of task, who can perform the mentioned operations, as well as 65 * leave the task, see a consistent and correct representation of the task at 66 * all times. 67 * 68 * Locking 69 * Because the task membership is a new relation between processes, its 70 * locking becomes an additional responsibility of the pidlock/p_lock locking 71 * sequence; however, tasks closely resemble sessions and the session locking 72 * model is mostly appropriate for the interaction of tasks, processes, and 73 * procfs. 74 * 75 * kmutex_t task_hash_lock 76 * task_hash_lock is a global lock protecting the contents of the task 77 * ID-to-task pointer hash. Holders of task_hash_lock must not attempt to 78 * acquire pidlock or p_lock. 79 * uint_t tk_hold_count 80 * tk_hold_count, the number of members and observers of the current task, 81 * must be manipulated atomically. 82 * proc_t *tk_memb_list 83 * proc_t *p_tasknext 84 * proc_t *p_taskprev 85 * The task's membership list is protected by pidlock, and is therefore 86 * always acquired before any of its members' p_lock mutexes. The p_task 87 * member of the proc structure is protected by pidlock or p_lock for 88 * reading, and by both pidlock and p_lock for modification, as is done for 89 * p_sessp. The key point is that only the process can modify its p_task, 90 * and not any entity on the system. (/proc will use prlock() to prevent 91 * the process from leaving, as opposed to pidlock.) 92 * kmutex_t tk_usage_lock 93 * tk_usage_lock is a per-task lock protecting the contents of the task 94 * usage structure and tk_nlwps counter for the task.max-lwps resource 95 * control. 96 */ 97 98 int task_hash_size = 256; 99 static kmutex_t task_hash_lock; 100 static mod_hash_t *task_hash; 101 102 static id_space_t *taskid_space; /* global taskid space */ 103 static kmem_cache_t *task_cache; /* kmem cache for task structures */ 104 105 rctl_hndl_t rc_task_lwps; 106 rctl_hndl_t rc_task_cpu_time; 107 108 /* 109 * static rctl_qty_t task_usage_lwps(void *taskp) 110 * 111 * Overview 112 * task_usage_lwps() is the usage operation for the resource control 113 * associated with the number of LWPs in a task. 114 * 115 * Return values 116 * The number of LWPs in the given task is returned. 117 * 118 * Caller's context 119 * The p->p_lock must be held across the call. 120 */ 121 /*ARGSUSED*/ 122 static rctl_qty_t 123 task_lwps_usage(rctl_t *r, proc_t *p) 124 { 125 task_t *t; 126 rctl_qty_t nlwps; 127 128 ASSERT(MUTEX_HELD(&p->p_lock)); 129 130 t = p->p_task; 131 mutex_enter(&p->p_zone->zone_nlwps_lock); 132 nlwps = t->tk_nlwps; 133 mutex_exit(&p->p_zone->zone_nlwps_lock); 134 135 return (nlwps); 136 } 137 138 /* 139 * static int task_test_lwps(void *taskp, rctl_val_t *, int64_t incr, 140 * int flags) 141 * 142 * Overview 143 * task_test_lwps() is the test-if-valid-increment for the resource control 144 * for the number of processes in a task. 145 * 146 * Return values 147 * 0 if the threshold limit was not passed, 1 if the limit was passed. 148 * 149 * Caller's context 150 * p->p_lock must be held across the call. 151 */ 152 /*ARGSUSED*/ 153 static int 154 task_lwps_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, rctl_val_t *rcntl, 155 rctl_qty_t incr, 156 uint_t flags) 157 { 158 rctl_qty_t nlwps; 159 160 ASSERT(MUTEX_HELD(&p->p_lock)); 161 ASSERT(e->rcep_t == RCENTITY_TASK); 162 if (e->rcep_p.task == NULL) 163 return (0); 164 165 ASSERT(MUTEX_HELD(&(e->rcep_p.task->tk_zone->zone_nlwps_lock))); 166 nlwps = e->rcep_p.task->tk_nlwps; 167 168 if (nlwps + incr > rcntl->rcv_value) 169 return (1); 170 171 return (0); 172 } 173 /*ARGSUSED*/ 174 static int 175 task_lwps_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e, rctl_qty_t nv) { 176 177 ASSERT(MUTEX_HELD(&p->p_lock)); 178 ASSERT(e->rcep_t == RCENTITY_TASK); 179 if (e->rcep_p.task == NULL) 180 return (0); 181 182 e->rcep_p.task->tk_nlwps_ctl = nv; 183 return (0); 184 } 185 186 /* 187 * static rctl_qty_t task_usage_cpu_secs(void *taskp) 188 * 189 * Overview 190 * task_usage_cpu_secs() is the usage operation for the resource control 191 * associated with the total accrued CPU seconds for a task. 192 * 193 * Return values 194 * The number of CPU seconds consumed by the task is returned. 195 * 196 * Caller's context 197 * The given task must be held across the call. 198 */ 199 /*ARGSUSED*/ 200 static rctl_qty_t 201 task_cpu_time_usage(rctl_t *r, proc_t *p) 202 { 203 task_t *t = p->p_task; 204 205 ASSERT(MUTEX_HELD(&p->p_lock)); 206 return (t->tk_cpu_time / hz); 207 } 208 209 /* 210 * static int task_test_cpu_secs(void *taskp, rctl_val_t *, int64_t incr, 211 * int flags) 212 * 213 * Overview 214 * task_test_cpu_secs() is the test-if-valid-increment for the resource 215 * control for the total accrued CPU seconds for a task. 216 * 217 * Return values 218 * 0 if the threshold limit was not passed, 1 if the limit was passed. 219 * 220 * Caller's context 221 * The given task must be held across the call. 222 */ 223 /*ARGSUSED*/ 224 static int 225 task_cpu_time_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, 226 struct rctl_val *rcntl, rctl_qty_t incr, uint_t flags) 227 { 228 task_t *t; 229 230 ASSERT(MUTEX_HELD(&p->p_lock)); 231 ASSERT(e->rcep_t == RCENTITY_TASK); 232 if (e->rcep_p.task == NULL) 233 return (0); 234 235 t = e->rcep_p.task; 236 if ((t->tk_cpu_time + incr) / hz >= rcntl->rcv_value) 237 return (1); 238 239 return (0); 240 } 241 242 static task_t * 243 task_find(taskid_t id, zoneid_t zoneid) 244 { 245 task_t *tk; 246 247 ASSERT(MUTEX_HELD(&task_hash_lock)); 248 249 if (mod_hash_find(task_hash, (mod_hash_key_t)(uintptr_t)id, 250 (mod_hash_val_t *)&tk) == MH_ERR_NOTFOUND || 251 (zoneid != ALL_ZONES && zoneid != tk->tk_zone->zone_id)) 252 return (NULL); 253 254 return (tk); 255 } 256 257 /* 258 * task_hold_by_id(), task_hold_by_id_zone() 259 * 260 * Overview 261 * task_hold_by_id() is used to take a reference on a task by its task id, 262 * supporting the various system call interfaces for obtaining resource data, 263 * delivering signals, and so forth. 264 * 265 * Return values 266 * Returns a pointer to the task_t with taskid_t id. The task is returned 267 * with its hold count incremented by one. Returns NULL if there 268 * is no task with the requested id. 269 * 270 * Caller's context 271 * Caller must not be holding task_hash_lock. No restrictions on context. 272 */ 273 task_t * 274 task_hold_by_id_zone(taskid_t id, zoneid_t zoneid) 275 { 276 task_t *tk; 277 278 mutex_enter(&task_hash_lock); 279 if ((tk = task_find(id, zoneid)) != NULL) 280 atomic_add_32(&tk->tk_hold_count, 1); 281 mutex_exit(&task_hash_lock); 282 283 return (tk); 284 } 285 286 task_t * 287 task_hold_by_id(taskid_t id) 288 { 289 zoneid_t zoneid; 290 291 if (INGLOBALZONE(curproc)) 292 zoneid = ALL_ZONES; 293 else 294 zoneid = getzoneid(); 295 return (task_hold_by_id_zone(id, zoneid)); 296 } 297 298 /* 299 * void task_hold(task_t *) 300 * 301 * Overview 302 * task_hold() is used to take an additional reference to the given task. 303 * 304 * Return values 305 * None. 306 * 307 * Caller's context 308 * No restriction on context. 309 */ 310 void 311 task_hold(task_t *tk) 312 { 313 atomic_add_32(&tk->tk_hold_count, 1); 314 } 315 316 /* 317 * void task_rele(task_t *) 318 * 319 * Overview 320 * task_rele() relinquishes a reference on the given task, which was acquired 321 * via task_hold() or task_hold_by_id(). If this is the last member or 322 * observer of the task, dispatch it for commitment via the accounting 323 * subsystem. 324 * 325 * Return values 326 * None. 327 * 328 * Caller's context 329 * Caller must not be holding the task_hash_lock. 330 * Caller's context must be acceptable for KM_SLEEP allocations. 331 */ 332 void 333 task_rele(task_t *tk) 334 { 335 mutex_enter(&task_hash_lock); 336 if (atomic_add_32_nv(&tk->tk_hold_count, -1) > 0) { 337 mutex_exit(&task_hash_lock); 338 return; 339 } 340 341 mutex_enter(&tk->tk_zone->zone_nlwps_lock); 342 tk->tk_proj->kpj_ntasks--; 343 mutex_exit(&tk->tk_zone->zone_nlwps_lock); 344 345 if (mod_hash_destroy(task_hash, 346 (mod_hash_key_t)(uintptr_t)tk->tk_tkid) != 0) 347 panic("unable to delete task %d", tk->tk_tkid); 348 mutex_exit(&task_hash_lock); 349 350 /* 351 * At this point, there are no members or observers of the task, so we 352 * can safely send it on for commitment to the accounting subsystem. 353 * The task will be destroyed in task_end() subsequent to commitment. 354 */ 355 (void) taskq_dispatch(exacct_queue, exacct_commit_task, tk, KM_SLEEP); 356 } 357 358 /* 359 * task_t *task_create(projid_t, zone *) 360 * 361 * Overview 362 * A process constructing a new task calls task_create() to construct and 363 * preinitialize the task for the appropriate destination project. Only one 364 * task, the primordial task0, is not created with task_create(). 365 * 366 * Return values 367 * None. 368 * 369 * Caller's context 370 * Caller's context should be safe for KM_SLEEP allocations. 371 * The caller should appropriately bump the kpj_ntasks counter on the 372 * project that contains this task. 373 */ 374 task_t * 375 task_create(projid_t projid, zone_t *zone) 376 { 377 task_t *tk = kmem_cache_alloc(task_cache, KM_SLEEP); 378 task_t *ancestor_tk; 379 taskid_t tkid; 380 task_usage_t *tu = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 381 mod_hash_hndl_t hndl; 382 rctl_set_t *set = rctl_set_create(); 383 rctl_alloc_gp_t *gp; 384 rctl_entity_p_t e; 385 386 bzero(tk, sizeof (task_t)); 387 388 tk->tk_tkid = tkid = id_alloc(taskid_space); 389 tk->tk_nlwps = 0; 390 tk->tk_nlwps_ctl = INT_MAX; 391 tk->tk_usage = tu; 392 tk->tk_proj = project_hold_by_id(projid, zone->zone_id, 393 PROJECT_HOLD_INSERT); 394 tk->tk_flags = TASK_NORMAL; 395 396 /* 397 * Copy ancestor task's resource controls. 398 */ 399 zone_task_hold(zone); 400 mutex_enter(&curproc->p_lock); 401 ancestor_tk = curproc->p_task; 402 task_hold(ancestor_tk); 403 tk->tk_zone = zone; 404 mutex_exit(&curproc->p_lock); 405 406 for (;;) { 407 gp = rctl_set_dup_prealloc(ancestor_tk->tk_rctls); 408 409 mutex_enter(&ancestor_tk->tk_rctls->rcs_lock); 410 if (rctl_set_dup_ready(ancestor_tk->tk_rctls, gp)) 411 break; 412 413 mutex_exit(&ancestor_tk->tk_rctls->rcs_lock); 414 415 rctl_prealloc_destroy(gp); 416 } 417 418 /* 419 * At this point, curproc does not have the appropriate linkage 420 * through the task to the project. So, rctl_set_dup should only 421 * copy the rctls, and leave the callbacks for later. 422 */ 423 e.rcep_p.task = tk; 424 e.rcep_t = RCENTITY_TASK; 425 tk->tk_rctls = rctl_set_dup(ancestor_tk->tk_rctls, curproc, curproc, &e, 426 set, gp, RCD_DUP); 427 mutex_exit(&ancestor_tk->tk_rctls->rcs_lock); 428 429 rctl_prealloc_destroy(gp); 430 431 /* 432 * Record the ancestor task's ID for use by extended accounting. 433 */ 434 tu->tu_anctaskid = ancestor_tk->tk_tkid; 435 task_rele(ancestor_tk); 436 437 /* 438 * Put new task structure in the hash table. 439 */ 440 (void) mod_hash_reserve(task_hash, &hndl); 441 mutex_enter(&task_hash_lock); 442 ASSERT(task_find(tkid, getzoneid()) == NULL); 443 if (mod_hash_insert_reserve(task_hash, (mod_hash_key_t)(uintptr_t)tkid, 444 (mod_hash_val_t *)tk, hndl) != 0) { 445 mod_hash_cancel(task_hash, &hndl); 446 panic("unable to insert task %d(%p)", tkid, (void *)tk); 447 } 448 mutex_exit(&task_hash_lock); 449 450 return (tk); 451 } 452 453 /* 454 * void task_attach(task_t *, proc_t *) 455 * 456 * Overview 457 * task_attach() is used to attach a process to a task; this operation is only 458 * performed as a result of a fork() or settaskid() system call. The proc_t's 459 * p_tasknext and p_taskprev fields will be set such that the proc_t is a 460 * member of the doubly-linked list of proc_t's that make up the task. 461 * 462 * Return values 463 * None. 464 * 465 * Caller's context 466 * pidlock and p->p_lock must be held on entry. 467 */ 468 void 469 task_attach(task_t *tk, proc_t *p) 470 { 471 proc_t *first, *prev; 472 rctl_entity_p_t e; 473 ASSERT(tk != NULL); 474 ASSERT(p != NULL); 475 ASSERT(MUTEX_HELD(&pidlock)); 476 ASSERT(MUTEX_HELD(&p->p_lock)); 477 478 if (tk->tk_memb_list == NULL) { 479 p->p_tasknext = p; 480 p->p_taskprev = p; 481 } else { 482 first = tk->tk_memb_list; 483 prev = first->p_taskprev; 484 first->p_taskprev = p; 485 p->p_tasknext = first; 486 p->p_taskprev = prev; 487 prev->p_tasknext = p; 488 } 489 tk->tk_memb_list = p; 490 task_hold(tk); 491 p->p_task = tk; 492 493 /* 494 * Now that the linkage from process to task and project is 495 * complete, do the required callbacks for the task and project 496 * rctl sets. 497 */ 498 e.rcep_p.proj = tk->tk_proj; 499 e.rcep_t = RCENTITY_PROJECT; 500 (void) rctl_set_dup(NULL, NULL, p, &e, tk->tk_proj->kpj_rctls, NULL, 501 RCD_CALLBACK); 502 503 e.rcep_p.task = tk; 504 e.rcep_t = RCENTITY_TASK; 505 (void) rctl_set_dup(NULL, NULL, p, &e, tk->tk_rctls, NULL, 506 RCD_CALLBACK); 507 508 } 509 510 /* 511 * task_begin() 512 * 513 * Overview 514 * A process constructing a new task calls task_begin() to initialize the 515 * task, by attaching itself as a member. 516 * 517 * Return values 518 * None. 519 * 520 * Caller's context 521 * pidlock and p_lock must be held across the call to task_begin(). 522 */ 523 void 524 task_begin(task_t *tk, proc_t *p) 525 { 526 timestruc_t ts; 527 task_usage_t *tu; 528 529 ASSERT(MUTEX_HELD(&pidlock)); 530 ASSERT(MUTEX_HELD(&p->p_lock)); 531 532 mutex_enter(&tk->tk_usage_lock); 533 tu = tk->tk_usage; 534 gethrestime(&ts); 535 tu->tu_startsec = (uint64_t)ts.tv_sec; 536 tu->tu_startnsec = (uint64_t)ts.tv_nsec; 537 mutex_exit(&tk->tk_usage_lock); 538 539 /* 540 * Join process to the task as a member. 541 */ 542 task_attach(tk, p); 543 } 544 545 /* 546 * void task_detach(proc_t *) 547 * 548 * Overview 549 * task_detach() removes the specified process from its task. task_detach 550 * sets the process's task membership to NULL, in anticipation of a final exit 551 * or of joining a new task. Because task_rele() requires a context safe for 552 * KM_SLEEP allocations, a task_detach() is followed by a subsequent 553 * task_rele() once appropriate context is available. 554 * 555 * Because task_detach() involves relinquishing the process's membership in 556 * the project, any observational rctls the process may have had on the task 557 * or project are destroyed. 558 * 559 * Return values 560 * None. 561 * 562 * Caller's context 563 * pidlock and p_lock held across task_detach(). 564 */ 565 void 566 task_detach(proc_t *p) 567 { 568 task_t *tk = p->p_task; 569 570 ASSERT(MUTEX_HELD(&pidlock)); 571 ASSERT(MUTEX_HELD(&p->p_lock)); 572 ASSERT(p->p_task != NULL); 573 ASSERT(tk->tk_memb_list != NULL); 574 575 if (tk->tk_memb_list == p) 576 tk->tk_memb_list = p->p_tasknext; 577 if (tk->tk_memb_list == p) 578 tk->tk_memb_list = NULL; 579 p->p_taskprev->p_tasknext = p->p_tasknext; 580 p->p_tasknext->p_taskprev = p->p_taskprev; 581 582 rctl_set_tearoff(p->p_task->tk_rctls, p); 583 rctl_set_tearoff(p->p_task->tk_proj->kpj_rctls, p); 584 585 p->p_task = NULL; 586 p->p_tasknext = p->p_taskprev = NULL; 587 } 588 589 /* 590 * task_change(task_t *, proc_t *) 591 * 592 * Overview 593 * task_change() removes the specified process from its current task. The 594 * process is then attached to the specified task. This routine is called 595 * from settaskid() when process is being moved to a new task. 596 * 597 * Return values 598 * None. 599 * 600 * Caller's context 601 * pidlock and p_lock held across task_change() 602 */ 603 void 604 task_change(task_t *newtk, proc_t *p) 605 { 606 task_t *oldtk = p->p_task; 607 608 ASSERT(MUTEX_HELD(&pidlock)); 609 ASSERT(MUTEX_HELD(&p->p_lock)); 610 ASSERT(oldtk != NULL); 611 ASSERT(oldtk->tk_memb_list != NULL); 612 613 mutex_enter(&p->p_zone->zone_nlwps_lock); 614 oldtk->tk_nlwps -= p->p_lwpcnt; 615 mutex_exit(&p->p_zone->zone_nlwps_lock); 616 617 mutex_enter(&newtk->tk_zone->zone_nlwps_lock); 618 newtk->tk_nlwps += p->p_lwpcnt; 619 mutex_exit(&newtk->tk_zone->zone_nlwps_lock); 620 621 task_detach(p); 622 task_begin(newtk, p); 623 } 624 625 /* 626 * task_end() 627 * 628 * Overview 629 * task_end() contains the actions executed once the final member of 630 * a task has released the task, and all actions connected with the task, such 631 * as committing an accounting record to a file, are completed. It is called 632 * by the known last consumer of the task information. Additionally, 633 * task_end() must never refer to any process in the system. 634 * 635 * Return values 636 * None. 637 * 638 * Caller's context 639 * No restrictions on context, beyond that given above. 640 */ 641 void 642 task_end(task_t *tk) 643 { 644 ASSERT(tk->tk_hold_count == 0); 645 646 project_rele(tk->tk_proj); 647 kmem_free(tk->tk_usage, sizeof (task_usage_t)); 648 if (tk->tk_prevusage != NULL) 649 kmem_free(tk->tk_prevusage, sizeof (task_usage_t)); 650 if (tk->tk_zoneusage != NULL) 651 kmem_free(tk->tk_zoneusage, sizeof (task_usage_t)); 652 rctl_set_free(tk->tk_rctls); 653 id_free(taskid_space, tk->tk_tkid); 654 zone_task_rele(tk->tk_zone); 655 kmem_cache_free(task_cache, tk); 656 } 657 658 static void 659 changeproj(proc_t *p, kproject_t *kpj, zone_t *zone, void *projbuf, 660 void *zonebuf) 661 { 662 kproject_t *oldkpj; 663 kthread_t *t; 664 665 ASSERT(MUTEX_HELD(&pidlock)); 666 ASSERT(MUTEX_HELD(&p->p_lock)); 667 668 if ((t = p->p_tlist) != NULL) { 669 do { 670 (void) project_hold(kpj); 671 672 thread_lock(t); 673 oldkpj = ttoproj(t); 674 t->t_proj = kpj; 675 t->t_pre_sys = 1; /* For cred update */ 676 thread_unlock(t); 677 fss_changeproj(t, kpj, zone, projbuf, zonebuf); 678 679 project_rele(oldkpj); 680 } while ((t = t->t_forw) != p->p_tlist); 681 } 682 } 683 684 /* 685 * task_join() 686 * 687 * Overview 688 * task_join() contains the actions that must be executed when the first 689 * member (curproc) of a newly created task joins it. It may never fail. 690 * 691 * The caller must make sure holdlwps() is called so that all other lwps are 692 * stopped prior to calling this function. 693 * 694 * NB: It returns with curproc->p_lock held. 695 * 696 * Return values 697 * Pointer to the old task. 698 * 699 * Caller's context 700 * cpu_lock must be held entering the function. It will acquire pidlock, 701 * p_crlock and p_lock during execution. 702 */ 703 task_t * 704 task_join(task_t *tk, uint_t flags) 705 { 706 proc_t *p = ttoproc(curthread); 707 task_t *prev_tk; 708 void *projbuf, *zonebuf; 709 zone_t *zone = tk->tk_zone; 710 projid_t projid = tk->tk_proj->kpj_id; 711 cred_t *oldcr; 712 713 /* 714 * We can't know for sure if holdlwps() was called, but we can check to 715 * ensure we're single-threaded. 716 */ 717 ASSERT(curthread == p->p_agenttp || p->p_lwprcnt == 1); 718 719 /* 720 * Changing the credential is always hard because we cannot 721 * allocate memory when holding locks but we don't know whether 722 * we need to change it. We first get a reference to the current 723 * cred if we need to change it. Then we create a credential 724 * with an updated project id. Finally we install it, first 725 * releasing the reference we had on the p_cred at the time we 726 * acquired the lock the first time and later we release the 727 * reference to p_cred at the time we acquired the lock the 728 * second time. 729 */ 730 mutex_enter(&p->p_crlock); 731 if (crgetprojid(p->p_cred) == projid) 732 oldcr = NULL; 733 else 734 crhold(oldcr = p->p_cred); 735 mutex_exit(&p->p_crlock); 736 737 if (oldcr != NULL) { 738 cred_t *newcr = crdup(oldcr); 739 crsetprojid(newcr, projid); 740 crfree(oldcr); 741 742 mutex_enter(&p->p_crlock); 743 oldcr = p->p_cred; 744 p->p_cred = newcr; 745 mutex_exit(&p->p_crlock); 746 crfree(oldcr); 747 } 748 749 /* 750 * Make sure that the number of processor sets is constant 751 * across this operation. 752 */ 753 ASSERT(MUTEX_HELD(&cpu_lock)); 754 755 projbuf = fss_allocbuf(FSS_NPSET_BUF, FSS_ALLOC_PROJ); 756 zonebuf = fss_allocbuf(FSS_NPSET_BUF, FSS_ALLOC_ZONE); 757 758 mutex_enter(&pidlock); 759 mutex_enter(&p->p_lock); 760 761 prev_tk = p->p_task; 762 task_change(tk, p); 763 764 /* 765 * Now move threads one by one to their new project. 766 */ 767 changeproj(p, tk->tk_proj, zone, projbuf, zonebuf); 768 if (flags & TASK_FINAL) 769 p->p_task->tk_flags |= TASK_FINAL; 770 771 mutex_exit(&pidlock); 772 773 fss_freebuf(zonebuf, FSS_ALLOC_ZONE); 774 fss_freebuf(projbuf, FSS_ALLOC_PROJ); 775 return (prev_tk); 776 } 777 778 /* 779 * rctl ops vectors 780 */ 781 static rctl_ops_t task_lwps_ops = { 782 rcop_no_action, 783 task_lwps_usage, 784 task_lwps_set, 785 task_lwps_test 786 }; 787 788 static rctl_ops_t task_cpu_time_ops = { 789 rcop_no_action, 790 task_cpu_time_usage, 791 rcop_no_set, 792 task_cpu_time_test 793 }; 794 795 /*ARGSUSED*/ 796 /* 797 * void task_init(void) 798 * 799 * Overview 800 * task_init() initializes task-related hashes, caches, and the task id 801 * space. Additionally, task_init() establishes p0 as a member of task0. 802 * Called by main(). 803 * 804 * Return values 805 * None. 806 * 807 * Caller's context 808 * task_init() must be called prior to MP startup. 809 */ 810 void 811 task_init(void) 812 { 813 proc_t *p = &p0; 814 mod_hash_hndl_t hndl; 815 rctl_set_t *set; 816 rctl_alloc_gp_t *gp; 817 rctl_entity_p_t e; 818 /* 819 * Initialize task_cache and taskid_space. 820 */ 821 task_cache = kmem_cache_create("task_cache", sizeof (task_t), 822 0, NULL, NULL, NULL, NULL, NULL, 0); 823 taskid_space = id_space_create("taskid_space", 0, MAX_TASKID); 824 825 /* 826 * Initialize task hash table. 827 */ 828 task_hash = mod_hash_create_idhash("task_hash", task_hash_size, 829 mod_hash_null_valdtor); 830 831 /* 832 * Initialize task-based rctls. 833 */ 834 rc_task_lwps = rctl_register("task.max-lwps", RCENTITY_TASK, 835 RCTL_GLOBAL_NOACTION | RCTL_GLOBAL_COUNT, INT_MAX, INT_MAX, 836 &task_lwps_ops); 837 rc_task_cpu_time = rctl_register("task.max-cpu-time", RCENTITY_TASK, 838 RCTL_GLOBAL_NOACTION | RCTL_GLOBAL_DENY_NEVER | 839 RCTL_GLOBAL_CPU_TIME | RCTL_GLOBAL_INFINITE | 840 RCTL_GLOBAL_UNOBSERVABLE | RCTL_GLOBAL_SECONDS, UINT64_MAX, 841 UINT64_MAX, &task_cpu_time_ops); 842 843 /* 844 * Create task0 and place p0 in it as a member. 845 */ 846 task0p = kmem_cache_alloc(task_cache, KM_SLEEP); 847 bzero(task0p, sizeof (task_t)); 848 849 task0p->tk_tkid = id_alloc(taskid_space); 850 task0p->tk_usage = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 851 task0p->tk_proj = project_hold_by_id(0, GLOBAL_ZONEID, 852 PROJECT_HOLD_INSERT); 853 task0p->tk_flags = TASK_NORMAL; 854 task0p->tk_nlwps = p->p_lwpcnt; 855 task0p->tk_zone = global_zone; 856 857 set = rctl_set_create(); 858 gp = rctl_set_init_prealloc(RCENTITY_TASK); 859 mutex_enter(&curproc->p_lock); 860 e.rcep_p.task = task0p; 861 e.rcep_t = RCENTITY_TASK; 862 task0p->tk_rctls = rctl_set_init(RCENTITY_TASK, curproc, &e, set, gp); 863 mutex_exit(&curproc->p_lock); 864 rctl_prealloc_destroy(gp); 865 866 (void) mod_hash_reserve(task_hash, &hndl); 867 mutex_enter(&task_hash_lock); 868 ASSERT(task_find(task0p->tk_tkid, GLOBAL_ZONEID) == NULL); 869 if (mod_hash_insert_reserve(task_hash, 870 (mod_hash_key_t)(uintptr_t)task0p->tk_tkid, 871 (mod_hash_val_t *)task0p, hndl) != 0) { 872 mod_hash_cancel(task_hash, &hndl); 873 panic("unable to insert task %d(%p)", task0p->tk_tkid, 874 (void *)task0p); 875 } 876 mutex_exit(&task_hash_lock); 877 878 task0p->tk_memb_list = p; 879 880 /* 881 * Initialize task pointers for p0, including doubly linked list of task 882 * members. 883 */ 884 p->p_task = task0p; 885 p->p_taskprev = p->p_tasknext = p; 886 task_hold(task0p); 887 } 888