kern_racct.c revision 220137
1/*- 2 * Copyright (c) 2010 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Edward Tomasz Napierala under sponsorship 6 * from the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: head/sys/kern/kern_racct.c 220137 2011-03-29 17:47:25Z trasz $ 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: head/sys/kern/kern_racct.c 220137 2011-03-29 17:47:25Z trasz $"); 34 35#include "opt_kdtrace.h" 36 37#include <sys/param.h> 38#include <sys/eventhandler.h> 39#include <sys/param.h> 40#include <sys/jail.h> 41#include <sys/kernel.h> 42#include <sys/kthread.h> 43#include <sys/lock.h> 44#include <sys/loginclass.h> 45#include <sys/malloc.h> 46#include <sys/mutex.h> 47#include <sys/proc.h> 48#include <sys/racct.h> 49#include <sys/resourcevar.h> 50#include <sys/sbuf.h> 51#include <sys/sched.h> 52#include <sys/sdt.h> 53#include <sys/sx.h> 54#include <sys/sysent.h> 55#include <sys/sysproto.h> 56#include <sys/systm.h> 57#include <sys/umtx.h> 58 59#ifdef RCTL 60#include <sys/rctl.h> 61#endif 62 63#ifdef RACCT 64 65FEATURE(racct, "Resource Accounting"); 66 67static struct mtx racct_lock; 68MTX_SYSINIT(racct_lock, &racct_lock, "racct lock", MTX_DEF); 69 70static uma_zone_t racct_zone; 71 72static void racct_sub_racct(struct racct *dest, const struct racct *src); 73static void racct_sub_cred_locked(struct ucred *cred, int resource, 74 uint64_t amount); 75static void racct_add_cred_locked(struct ucred *cred, int resource, 76 uint64_t amount); 77 78SDT_PROVIDER_DEFINE(racct); 79SDT_PROBE_DEFINE3(racct, kernel, rusage, add, add, "struct proc *", "int", 80 "uint64_t"); 81SDT_PROBE_DEFINE3(racct, kernel, rusage, add_failure, add-failure, 82 "struct proc *", "int", "uint64_t"); 83SDT_PROBE_DEFINE3(racct, kernel, rusage, add_cred, add-cred, "struct ucred *", 84 "int", "uint64_t"); 85SDT_PROBE_DEFINE3(racct, kernel, rusage, add_force, add-force, "struct proc *", 86 "int", "uint64_t"); 87SDT_PROBE_DEFINE3(racct, kernel, rusage, set, set, "struct proc *", "int", 88 "uint64_t"); 89SDT_PROBE_DEFINE3(racct, kernel, rusage, set_failure, set-failure, 90 "struct proc *", "int", "uint64_t"); 91SDT_PROBE_DEFINE3(racct, kernel, rusage, sub, sub, "struct proc *", "int", 92 "uint64_t"); 93SDT_PROBE_DEFINE3(racct, kernel, rusage, sub_cred, sub-cred, "struct ucred *", 94 "int", "uint64_t"); 95SDT_PROBE_DEFINE1(racct, kernel, racct, create, create, "struct racct *"); 96SDT_PROBE_DEFINE1(racct, kernel, racct, destroy, destroy, "struct racct *"); 97SDT_PROBE_DEFINE2(racct, kernel, racct, join, join, "struct racct *", 98 "struct racct *"); 99SDT_PROBE_DEFINE2(racct, kernel, racct, join_failure, join-failure, 100 "struct racct *", "struct racct *"); 101SDT_PROBE_DEFINE2(racct, kernel, racct, leave, leave, "struct racct *", 102 "struct racct *"); 103 104int racct_types[] = { 105 [RACCT_CPU] = 106 RACCT_IN_THOUSANDS, 107 [RACCT_FSIZE] = 108 RACCT_RECLAIMABLE | RACCT_INHERITABLE | RACCT_DENIABLE, 109 [RACCT_DATA] = 110 RACCT_RECLAIMABLE | RACCT_INHERITABLE | RACCT_DENIABLE, 111 [RACCT_STACK] = 112 RACCT_RECLAIMABLE | RACCT_INHERITABLE | RACCT_DENIABLE, 113 [RACCT_CORE] = 114 RACCT_DENIABLE, 115 [RACCT_RSS] = 116 RACCT_RECLAIMABLE, 117 [RACCT_MEMLOCK] = 118 RACCT_RECLAIMABLE | RACCT_DENIABLE, 119 [RACCT_NPROC] = 120 RACCT_RECLAIMABLE | RACCT_DENIABLE, 121 [RACCT_NOFILE] = 122 RACCT_RECLAIMABLE | RACCT_INHERITABLE | RACCT_DENIABLE, 123 [RACCT_SBSIZE] = 124 RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 125 [RACCT_VMEM] = 126 RACCT_RECLAIMABLE | RACCT_INHERITABLE | RACCT_DENIABLE, 127 [RACCT_NPTS] = 128 RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 129 [RACCT_SWAP] = 130 RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 131 [RACCT_NTHR] = 132 RACCT_RECLAIMABLE | RACCT_DENIABLE, 133 [RACCT_MSGQQUEUED] = 134 RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 135 [RACCT_MSGQSIZE] = 136 RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 137 [RACCT_NMSGQ] = 138 RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 139 [RACCT_NSEM] = 140 RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 141 [RACCT_NSEMOP] = 142 RACCT_RECLAIMABLE | RACCT_INHERITABLE | RACCT_DENIABLE, 143 [RACCT_NSHM] = 144 RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 145 [RACCT_SHMSIZE] = 146 RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 147 [RACCT_WALLCLOCK] = 148 RACCT_IN_THOUSANDS }; 149 150static void 151racct_add_racct(struct racct *dest, const struct racct *src) 152{ 153 int i; 154 155 mtx_assert(&racct_lock, MA_OWNED); 156 157 /* 158 * Update resource usage in dest. 159 */ 160 for (i = 0; i <= RACCT_MAX; i++) { 161 KASSERT(dest->r_resources[i] >= 0, 162 ("racct propagation meltdown: dest < 0")); 163 KASSERT(src->r_resources[i] >= 0, 164 ("racct propagation meltdown: src < 0")); 165 dest->r_resources[i] += src->r_resources[i]; 166 } 167} 168 169static void 170racct_sub_racct(struct racct *dest, const struct racct *src) 171{ 172 int i; 173 174 mtx_assert(&racct_lock, MA_OWNED); 175 176 /* 177 * Update resource usage in dest. 178 */ 179 for (i = 0; i <= RACCT_MAX; i++) { 180 if (!racct_is_sloppy(i)) { 181 KASSERT(dest->r_resources[i] >= 0, 182 ("racct propagation meltdown: dest < 0")); 183 KASSERT(src->r_resources[i] >= 0, 184 ("racct propagation meltdown: src < 0")); 185 KASSERT(src->r_resources[i] <= dest->r_resources[i], 186 ("racct propagation meltdown: src > dest")); 187 } 188 if (racct_is_reclaimable(i)) { 189 dest->r_resources[i] -= src->r_resources[i]; 190 if (dest->r_resources[i] < 0) { 191 KASSERT(racct_is_sloppy(i), 192 ("racct_sub_racct: usage < 0")); 193 dest->r_resources[i] = 0; 194 } 195 } 196 } 197} 198 199void 200racct_create(struct racct **racctp) 201{ 202 203 SDT_PROBE(racct, kernel, racct, create, racctp, 0, 0, 0, 0); 204 205 KASSERT(*racctp == NULL, ("racct already allocated")); 206 207 *racctp = uma_zalloc(racct_zone, M_WAITOK | M_ZERO); 208} 209 210static void 211racct_destroy_locked(struct racct **racctp) 212{ 213 int i; 214 struct racct *racct; 215 216 SDT_PROBE(racct, kernel, racct, destroy, racctp, 0, 0, 0, 0); 217 218 mtx_assert(&racct_lock, MA_OWNED); 219 KASSERT(racctp != NULL, ("NULL racctp")); 220 KASSERT(*racctp != NULL, ("NULL racct")); 221 222 racct = *racctp; 223 224 for (i = 0; i <= RACCT_MAX; i++) { 225 if (racct_is_sloppy(i)) 226 continue; 227 if (!racct_is_reclaimable(i)) 228 continue; 229 KASSERT(racct->r_resources[i] == 0, 230 ("destroying non-empty racct: " 231 "%ju allocated for resource %d\n", 232 racct->r_resources[i], i)); 233 } 234 uma_zfree(racct_zone, racct); 235 *racctp = NULL; 236} 237 238void 239racct_destroy(struct racct **racct) 240{ 241 242 mtx_lock(&racct_lock); 243 racct_destroy_locked(racct); 244 mtx_unlock(&racct_lock); 245} 246 247/* 248 * Increase consumption of 'resource' by 'amount' for 'racct' 249 * and all its parents. Differently from other cases, 'amount' here 250 * may be less than zero. 251 */ 252static void 253racct_alloc_resource(struct racct *racct, int resource, 254 uint64_t amount) 255{ 256 257 mtx_assert(&racct_lock, MA_OWNED); 258 KASSERT(racct != NULL, ("NULL racct")); 259 260 racct->r_resources[resource] += amount; 261 if (racct->r_resources[resource] < 0) { 262 KASSERT(racct_is_sloppy(resource), 263 ("racct_alloc_resource: usage < 0")); 264 racct->r_resources[resource] = 0; 265 } 266} 267 268/* 269 * Increase allocation of 'resource' by 'amount' for process 'p'. 270 * Return 0 if it's below limits, or errno, if it's not. 271 */ 272int 273racct_add(struct proc *p, int resource, uint64_t amount) 274{ 275#ifdef RCTL 276 int error; 277#endif 278 279 if (p->p_flag & P_SYSTEM) 280 return (0); 281 282 SDT_PROBE(racct, kernel, rusage, add, p, resource, amount, 0, 0); 283 284 /* 285 * We need proc lock to dereference p->p_ucred. 286 */ 287 PROC_LOCK_ASSERT(p, MA_OWNED); 288 KASSERT(amount >= 0, ("racct_add: invalid amount for resource %d: %ju", 289 resource, amount)); 290 291 mtx_lock(&racct_lock); 292#ifdef RCTL 293 error = rctl_enforce(p, resource, amount); 294 if (error && racct_is_deniable(resource)) { 295 SDT_PROBE(racct, kernel, rusage, add_failure, p, resource, 296 amount, 0, 0); 297 mtx_unlock(&racct_lock); 298 return (error); 299 } 300#endif 301 racct_alloc_resource(p->p_racct, resource, amount); 302 racct_add_cred_locked(p->p_ucred, resource, amount); 303 mtx_unlock(&racct_lock); 304 305 return (0); 306} 307 308static void 309racct_add_cred_locked(struct ucred *cred, int resource, uint64_t amount) 310{ 311 struct prison *pr; 312 313 SDT_PROBE(racct, kernel, rusage, add_cred, cred, resource, amount, 314 0, 0); 315 316 KASSERT(amount >= 0, 317 ("racct_add_cred: invalid amount for resource %d: %ju", 318 resource, amount)); 319 320 racct_alloc_resource(cred->cr_ruidinfo->ui_racct, resource, amount); 321 for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) 322 racct_alloc_resource(pr->pr_racct, resource, amount); 323 racct_alloc_resource(cred->cr_loginclass->lc_racct, resource, amount); 324} 325 326/* 327 * Increase allocation of 'resource' by 'amount' for credential 'cred'. 328 * Doesn't check for limits and never fails. 329 * 330 * XXX: Shouldn't this ever return an error? 331 */ 332void 333racct_add_cred(struct ucred *cred, int resource, uint64_t amount) 334{ 335 336 mtx_lock(&racct_lock); 337 racct_add_cred_locked(cred, resource, amount); 338 mtx_unlock(&racct_lock); 339} 340 341/* 342 * Increase allocation of 'resource' by 'amount' for process 'p'. 343 * Doesn't check for limits and never fails. 344 */ 345void 346racct_add_force(struct proc *p, int resource, uint64_t amount) 347{ 348 349 if (p->p_flag & P_SYSTEM) 350 return; 351 352 SDT_PROBE(racct, kernel, rusage, add_force, p, resource, amount, 0, 0); 353 354 /* 355 * We need proc lock to dereference p->p_ucred. 356 */ 357 PROC_LOCK_ASSERT(p, MA_OWNED); 358 KASSERT(amount >= 0, 359 ("racct_add_force: invalid amount for resource %d: %ju", 360 resource, amount)); 361 362 mtx_lock(&racct_lock); 363 racct_alloc_resource(p->p_racct, resource, amount); 364 mtx_unlock(&racct_lock); 365 racct_add_cred(p->p_ucred, resource, amount); 366} 367 368static int 369racct_set_locked(struct proc *p, int resource, uint64_t amount) 370{ 371 int64_t diff; 372#ifdef RCTL 373 int error; 374#endif 375 376 if (p->p_flag & P_SYSTEM) 377 return (0); 378 379 SDT_PROBE(racct, kernel, rusage, set, p, resource, amount, 0, 0); 380 381 /* 382 * We need proc lock to dereference p->p_ucred. 383 */ 384 PROC_LOCK_ASSERT(p, MA_OWNED); 385 KASSERT(amount >= 0, ("racct_set: invalid amount for resource %d: %ju", 386 resource, amount)); 387 388 diff = amount - p->p_racct->r_resources[resource]; 389#ifdef notyet 390 KASSERT(diff >= 0 || racct_is_reclaimable(resource), 391 ("racct_set: usage of non-reclaimable resource %d dropping", 392 resource)); 393#endif 394#ifdef RCTL 395 if (diff > 0) { 396 error = rctl_enforce(p, resource, diff); 397 if (error && racct_is_deniable(resource)) { 398 SDT_PROBE(racct, kernel, rusage, set_failure, p, 399 resource, amount, 0, 0); 400 return (error); 401 } 402 } 403#endif 404 racct_alloc_resource(p->p_racct, resource, diff); 405 if (diff > 0) 406 racct_add_cred_locked(p->p_ucred, resource, diff); 407 else if (diff < 0) 408 racct_sub_cred_locked(p->p_ucred, resource, -diff); 409 410 return (0); 411} 412 413/* 414 * Set allocation of 'resource' to 'amount' for process 'p'. 415 * Return 0 if it's below limits, or errno, if it's not. 416 * 417 * Note that decreasing the allocation always returns 0, 418 * even if it's above the limit. 419 */ 420int 421racct_set(struct proc *p, int resource, uint64_t amount) 422{ 423 int error; 424 425 mtx_lock(&racct_lock); 426 error = racct_set_locked(p, resource, amount); 427 mtx_unlock(&racct_lock); 428 return (error); 429} 430 431void 432racct_set_force(struct proc *p, int resource, uint64_t amount) 433{ 434 int64_t diff; 435 436 if (p->p_flag & P_SYSTEM) 437 return; 438 439 SDT_PROBE(racct, kernel, rusage, set, p, resource, amount, 0, 0); 440 441 /* 442 * We need proc lock to dereference p->p_ucred. 443 */ 444 PROC_LOCK_ASSERT(p, MA_OWNED); 445 KASSERT(amount >= 0, 446 ("racct_set_force: invalid amount for resource %d: %ju", 447 resource, amount)); 448 449 mtx_lock(&racct_lock); 450 diff = amount - p->p_racct->r_resources[resource]; 451 racct_alloc_resource(p->p_racct, resource, diff); 452 if (diff > 0) 453 racct_add_cred_locked(p->p_ucred, resource, diff); 454 else if (diff < 0) 455 racct_sub_cred_locked(p->p_ucred, resource, -diff); 456 mtx_unlock(&racct_lock); 457} 458 459/* 460 * Returns amount of 'resource' the process 'p' can keep allocated. 461 * Allocating more than that would be denied, unless the resource 462 * is marked undeniable. Amount of already allocated resource does 463 * not matter. 464 */ 465uint64_t 466racct_get_limit(struct proc *p, int resource) 467{ 468 469#ifdef RCTL 470 return (rctl_get_limit(p, resource)); 471#else 472 return (UINT64_MAX); 473#endif 474} 475 476/* 477 * Returns amount of 'resource' the process 'p' can keep allocated. 478 * Allocating more than that would be denied, unless the resource 479 * is marked undeniable. Amount of already allocated resource does 480 * matter. 481 */ 482uint64_t 483racct_get_available(struct proc *p, int resource) 484{ 485 486#ifdef RCTL 487 return (rctl_get_available(p, resource)); 488#else 489 return (UINT64_MAX); 490#endif 491} 492 493/* 494 * Decrease allocation of 'resource' by 'amount' for process 'p'. 495 */ 496void 497racct_sub(struct proc *p, int resource, uint64_t amount) 498{ 499 500 if (p->p_flag & P_SYSTEM) 501 return; 502 503 SDT_PROBE(racct, kernel, rusage, sub, p, resource, amount, 0, 0); 504 505 /* 506 * We need proc lock to dereference p->p_ucred. 507 */ 508 PROC_LOCK_ASSERT(p, MA_OWNED); 509 KASSERT(amount >= 0, ("racct_sub: invalid amount for resource %d: %ju", 510 resource, amount)); 511 KASSERT(racct_is_reclaimable(resource), 512 ("racct_sub: called for non-reclaimable resource %d", resource)); 513 514 mtx_lock(&racct_lock); 515 KASSERT(amount <= p->p_racct->r_resources[resource], 516 ("racct_sub: freeing %ju of resource %d, which is more " 517 "than allocated %jd for %s (pid %d)", amount, resource, 518 (intmax_t)p->p_racct->r_resources[resource], p->p_comm, p->p_pid)); 519 520 racct_alloc_resource(p->p_racct, resource, -amount); 521 racct_sub_cred_locked(p->p_ucred, resource, amount); 522 mtx_unlock(&racct_lock); 523} 524 525static void 526racct_sub_cred_locked(struct ucred *cred, int resource, uint64_t amount) 527{ 528 struct prison *pr; 529 530 SDT_PROBE(racct, kernel, rusage, sub_cred, cred, resource, amount, 531 0, 0); 532 533 KASSERT(amount >= 0, 534 ("racct_sub_cred: invalid amount for resource %d: %ju", 535 resource, amount)); 536#ifdef notyet 537 KASSERT(racct_is_reclaimable(resource), 538 ("racct_sub_cred: called for non-reclaimable resource %d", 539 resource)); 540#endif 541 542 racct_alloc_resource(cred->cr_ruidinfo->ui_racct, resource, -amount); 543 for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) 544 racct_alloc_resource(pr->pr_racct, resource, -amount); 545 racct_alloc_resource(cred->cr_loginclass->lc_racct, resource, -amount); 546} 547 548/* 549 * Decrease allocation of 'resource' by 'amount' for credential 'cred'. 550 */ 551void 552racct_sub_cred(struct ucred *cred, int resource, uint64_t amount) 553{ 554 555 mtx_lock(&racct_lock); 556 racct_sub_cred_locked(cred, resource, amount); 557 mtx_unlock(&racct_lock); 558} 559 560/* 561 * Inherit resource usage information from the parent process. 562 */ 563int 564racct_proc_fork(struct proc *parent, struct proc *child) 565{ 566 int i, error = 0; 567 568 /* 569 * Create racct for the child process. 570 */ 571 racct_create(&child->p_racct); 572 573 /* 574 * No resource accounting for kernel processes. 575 */ 576 if (child->p_flag & P_SYSTEM) 577 return (0); 578 579 PROC_LOCK(parent); 580 PROC_LOCK(child); 581 mtx_lock(&racct_lock); 582 583 /* 584 * Inherit resource usage. 585 */ 586 for (i = 0; i <= RACCT_MAX; i++) { 587 if (parent->p_racct->r_resources[i] == 0 || 588 !racct_is_inheritable(i)) 589 continue; 590 591 error = racct_set_locked(child, i, 592 parent->p_racct->r_resources[i]); 593 if (error != 0) { 594 /* 595 * XXX: The only purpose of these two lines is 596 * to prevent from tripping checks in racct_destroy(). 597 */ 598 for (i = 0; i <= RACCT_MAX; i++) 599 racct_set_locked(child, i, 0); 600 goto out; 601 } 602 } 603 604#ifdef RCTL 605 error = rctl_proc_fork(parent, child); 606 if (error != 0) { 607 /* 608 * XXX: The only purpose of these two lines is to prevent from 609 * tripping checks in racct_destroy(). 610 */ 611 for (i = 0; i <= RACCT_MAX; i++) 612 racct_set_locked(child, i, 0); 613 } 614#endif 615 616out: 617 if (error != 0) 618 racct_destroy_locked(&child->p_racct); 619 mtx_unlock(&racct_lock); 620 PROC_UNLOCK(child); 621 PROC_UNLOCK(parent); 622 623 return (error); 624} 625 626void 627racct_proc_exit(struct proc *p) 628{ 629 uint64_t runtime; 630 631 PROC_LOCK(p); 632 /* 633 * We don't need to calculate rux, proc_reap() has already done this. 634 */ 635 runtime = cputick2usec(p->p_rux.rux_runtime); 636#ifdef notyet 637 KASSERT(runtime >= p->p_prev_runtime, ("runtime < p_prev_runtime")); 638#else 639 if (runtime < p->p_prev_runtime) 640 runtime = p->p_prev_runtime; 641#endif 642 racct_set(p, RACCT_CPU, runtime); 643 644 /* 645 * XXX: Free this some other way. 646 */ 647 racct_set(p, RACCT_FSIZE, 0); 648 racct_set(p, RACCT_NPTS, 0); 649 racct_set(p, RACCT_NTHR, 0); 650 racct_set(p, RACCT_RSS, 0); 651 PROC_UNLOCK(p); 652 653#ifdef RCTL 654 rctl_racct_release(p->p_racct); 655#endif 656 racct_destroy(&p->p_racct); 657} 658 659/* 660 * Called after credentials change, to move resource utilisation 661 * between raccts. 662 */ 663void 664racct_proc_ucred_changed(struct proc *p, struct ucred *oldcred, 665 struct ucred *newcred) 666{ 667 struct uidinfo *olduip, *newuip; 668 struct loginclass *oldlc, *newlc; 669 struct prison *oldpr, *newpr, *pr; 670 671 PROC_LOCK_ASSERT(p, MA_NOTOWNED); 672 673 newuip = newcred->cr_ruidinfo; 674 olduip = oldcred->cr_ruidinfo; 675 newlc = newcred->cr_loginclass; 676 oldlc = oldcred->cr_loginclass; 677 newpr = newcred->cr_prison; 678 oldpr = oldcred->cr_prison; 679 680 mtx_lock(&racct_lock); 681 if (newuip != olduip) { 682 racct_sub_racct(olduip->ui_racct, p->p_racct); 683 racct_add_racct(newuip->ui_racct, p->p_racct); 684 } 685 if (newlc != oldlc) { 686 racct_sub_racct(oldlc->lc_racct, p->p_racct); 687 racct_add_racct(newlc->lc_racct, p->p_racct); 688 } 689 if (newpr != oldpr) { 690 for (pr = oldpr; pr != NULL; pr = pr->pr_parent) 691 racct_sub_racct(pr->pr_racct, p->p_racct); 692 for (pr = newpr; pr != NULL; pr = pr->pr_parent) 693 racct_add_racct(pr->pr_racct, p->p_racct); 694 } 695 mtx_unlock(&racct_lock); 696 697#ifdef RCTL 698 rctl_proc_ucred_changed(p, newcred); 699#endif 700} 701 702static void 703racctd(void) 704{ 705 struct thread *td; 706 struct proc *p; 707 struct timeval wallclock; 708 uint64_t runtime; 709 710 for (;;) { 711 sx_slock(&allproc_lock); 712 713 FOREACH_PROC_IN_SYSTEM(p) { 714 if (p->p_state != PRS_NORMAL) 715 continue; 716 if (p->p_flag & P_SYSTEM) 717 continue; 718 719 microuptime(&wallclock); 720 timevalsub(&wallclock, &p->p_stats->p_start); 721 PROC_LOCK(p); 722 PROC_SLOCK(p); 723 FOREACH_THREAD_IN_PROC(p, td) { 724 ruxagg(p, td); 725 thread_lock(td); 726 thread_unlock(td); 727 } 728 runtime = cputick2usec(p->p_rux.rux_runtime); 729 PROC_SUNLOCK(p); 730#ifdef notyet 731 KASSERT(runtime >= p->p_prev_runtime, 732 ("runtime < p_prev_runtime")); 733#else 734 if (runtime < p->p_prev_runtime) 735 runtime = p->p_prev_runtime; 736#endif 737 p->p_prev_runtime = runtime; 738 mtx_lock(&racct_lock); 739 racct_set_locked(p, RACCT_CPU, runtime); 740 racct_set_locked(p, RACCT_WALLCLOCK, 741 wallclock.tv_sec * 1000000 + wallclock.tv_usec); 742 mtx_unlock(&racct_lock); 743 PROC_UNLOCK(p); 744 } 745 sx_sunlock(&allproc_lock); 746 pause("-", hz); 747 } 748} 749 750static struct kproc_desc racctd_kp = { 751 "racctd", 752 racctd, 753 NULL 754}; 755SYSINIT(racctd, SI_SUB_RACCTD, SI_ORDER_FIRST, kproc_start, &racctd_kp); 756 757static void 758racct_init(void) 759{ 760 761 racct_zone = uma_zcreate("racct", sizeof(struct racct), 762 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); 763 /* 764 * XXX: Move this somewhere. 765 */ 766 racct_create(&prison0.pr_racct); 767} 768SYSINIT(racct, SI_SUB_RACCT, SI_ORDER_FIRST, racct_init, NULL); 769 770#else /* !RACCT */ 771 772int 773racct_add(struct proc *p, int resource, uint64_t amount) 774{ 775 776 return (0); 777} 778 779void 780racct_add_cred(struct ucred *cred, int resource, uint64_t amount) 781{ 782} 783 784void 785racct_add_force(struct proc *p, int resource, uint64_t amount) 786{ 787 788 return; 789} 790 791int 792racct_set(struct proc *p, int resource, uint64_t amount) 793{ 794 795 return (0); 796} 797 798void 799racct_sub(struct proc *p, int resource, uint64_t amount) 800{ 801} 802 803void 804racct_sub_cred(struct ucred *cred, int resource, uint64_t amount) 805{ 806} 807 808uint64_t 809racct_get_limit(struct proc *p, int resource) 810{ 811 812 return (UINT64_MAX); 813} 814 815void 816racct_create(struct racct **racctp) 817{ 818} 819 820void 821racct_destroy(struct racct **racctp) 822{ 823} 824 825int 826racct_proc_fork(struct proc *parent, struct proc *child) 827{ 828 829 return (0); 830} 831 832void 833racct_proc_exit(struct proc *p) 834{ 835} 836 837#endif /* !RACCT */ 838