kern_racct.c revision 225938
1220137Strasz/*- 2220137Strasz * Copyright (c) 2010 The FreeBSD Foundation 3220137Strasz * All rights reserved. 4220137Strasz * 5220137Strasz * This software was developed by Edward Tomasz Napierala under sponsorship 6220137Strasz * from the FreeBSD Foundation. 7220137Strasz * 8220137Strasz * Redistribution and use in source and binary forms, with or without 9220137Strasz * modification, are permitted provided that the following conditions 10220137Strasz * are met: 11220137Strasz * 1. Redistributions of source code must retain the above copyright 12220137Strasz * notice, this list of conditions and the following disclaimer. 13220137Strasz * 2. Redistributions in binary form must reproduce the above copyright 14220137Strasz * notice, this list of conditions and the following disclaimer in the 15220137Strasz * documentation and/or other materials provided with the distribution. 16220137Strasz * 17220137Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18220137Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19220137Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20220137Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21220137Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22220137Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23220137Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24220137Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25220137Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26220137Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27220137Strasz * SUCH DAMAGE. 28220137Strasz * 29220137Strasz * $FreeBSD: head/sys/kern/kern_racct.c 225938 2011-10-03 15:32:15Z trasz $ 30220137Strasz */ 31220137Strasz 32220137Strasz#include <sys/cdefs.h> 33220137Strasz__FBSDID("$FreeBSD: head/sys/kern/kern_racct.c 225938 2011-10-03 15:32:15Z trasz $"); 34220137Strasz 35220137Strasz#include "opt_kdtrace.h" 36220137Strasz 37220137Strasz#include <sys/param.h> 38220137Strasz#include <sys/eventhandler.h> 39220137Strasz#include <sys/param.h> 40220137Strasz#include <sys/jail.h> 41220137Strasz#include <sys/kernel.h> 42220137Strasz#include <sys/kthread.h> 43220137Strasz#include <sys/lock.h> 44220137Strasz#include <sys/loginclass.h> 45220137Strasz#include <sys/malloc.h> 46220137Strasz#include <sys/mutex.h> 47220137Strasz#include <sys/proc.h> 48220137Strasz#include <sys/racct.h> 49220137Strasz#include <sys/resourcevar.h> 50220137Strasz#include <sys/sbuf.h> 51220137Strasz#include <sys/sched.h> 52220137Strasz#include <sys/sdt.h> 53220137Strasz#include <sys/sx.h> 54220137Strasz#include <sys/sysent.h> 55220137Strasz#include <sys/sysproto.h> 56220137Strasz#include <sys/systm.h> 57220137Strasz#include <sys/umtx.h> 58220137Strasz 59220137Strasz#ifdef RCTL 60220137Strasz#include <sys/rctl.h> 61220137Strasz#endif 62220137Strasz 63220137Strasz#ifdef RACCT 64220137Strasz 65220137StraszFEATURE(racct, "Resource Accounting"); 66220137Strasz 67220137Straszstatic struct mtx racct_lock; 68220137StraszMTX_SYSINIT(racct_lock, &racct_lock, "racct lock", MTX_DEF); 69220137Strasz 70220137Straszstatic uma_zone_t racct_zone; 71220137Strasz 72220137Straszstatic void racct_sub_racct(struct racct *dest, const struct racct *src); 73220137Straszstatic void racct_sub_cred_locked(struct ucred *cred, int resource, 74220137Strasz uint64_t amount); 75220137Straszstatic void racct_add_cred_locked(struct ucred *cred, int resource, 76220137Strasz uint64_t amount); 77220137Strasz 78220137StraszSDT_PROVIDER_DEFINE(racct); 79220137StraszSDT_PROBE_DEFINE3(racct, kernel, rusage, add, add, "struct proc *", "int", 80220137Strasz "uint64_t"); 81220137StraszSDT_PROBE_DEFINE3(racct, kernel, rusage, add_failure, add-failure, 82220137Strasz "struct proc *", "int", "uint64_t"); 83220137StraszSDT_PROBE_DEFINE3(racct, kernel, rusage, add_cred, add-cred, "struct ucred *", 84220137Strasz "int", "uint64_t"); 85220137StraszSDT_PROBE_DEFINE3(racct, kernel, rusage, add_force, add-force, "struct proc *", 86220137Strasz "int", "uint64_t"); 87220137StraszSDT_PROBE_DEFINE3(racct, kernel, rusage, set, set, "struct proc *", "int", 88220137Strasz "uint64_t"); 89220137StraszSDT_PROBE_DEFINE3(racct, kernel, rusage, set_failure, set-failure, 90220137Strasz "struct proc *", "int", "uint64_t"); 91220137StraszSDT_PROBE_DEFINE3(racct, kernel, rusage, sub, sub, "struct proc *", "int", 92220137Strasz "uint64_t"); 93220137StraszSDT_PROBE_DEFINE3(racct, kernel, rusage, sub_cred, sub-cred, "struct ucred *", 94220137Strasz "int", "uint64_t"); 95220137StraszSDT_PROBE_DEFINE1(racct, kernel, racct, create, create, "struct racct *"); 96220137StraszSDT_PROBE_DEFINE1(racct, kernel, racct, destroy, destroy, "struct racct *"); 97220137StraszSDT_PROBE_DEFINE2(racct, kernel, racct, join, join, "struct racct *", 98220137Strasz "struct racct *"); 99220137StraszSDT_PROBE_DEFINE2(racct, kernel, racct, join_failure, join-failure, 100220137Strasz "struct racct *", "struct racct *"); 101220137StraszSDT_PROBE_DEFINE2(racct, kernel, racct, leave, leave, "struct racct *", 102220137Strasz "struct racct *"); 103220137Strasz 104220137Straszint racct_types[] = { 105220137Strasz [RACCT_CPU] = 106224036Strasz RACCT_IN_MILLIONS, 107220137Strasz [RACCT_DATA] = 108220137Strasz RACCT_RECLAIMABLE | RACCT_INHERITABLE | RACCT_DENIABLE, 109220137Strasz [RACCT_STACK] = 110220137Strasz RACCT_RECLAIMABLE | RACCT_INHERITABLE | RACCT_DENIABLE, 111220137Strasz [RACCT_CORE] = 112220137Strasz RACCT_DENIABLE, 113220137Strasz [RACCT_RSS] = 114220137Strasz RACCT_RECLAIMABLE, 115220137Strasz [RACCT_MEMLOCK] = 116220137Strasz RACCT_RECLAIMABLE | RACCT_DENIABLE, 117220137Strasz [RACCT_NPROC] = 118220137Strasz RACCT_RECLAIMABLE | RACCT_DENIABLE, 119220137Strasz [RACCT_NOFILE] = 120220137Strasz RACCT_RECLAIMABLE | RACCT_INHERITABLE | RACCT_DENIABLE, 121220137Strasz [RACCT_VMEM] = 122220137Strasz RACCT_RECLAIMABLE | RACCT_INHERITABLE | RACCT_DENIABLE, 123220137Strasz [RACCT_NPTS] = 124220137Strasz RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 125220137Strasz [RACCT_SWAP] = 126220137Strasz RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 127220137Strasz [RACCT_NTHR] = 128220137Strasz RACCT_RECLAIMABLE | RACCT_DENIABLE, 129220137Strasz [RACCT_MSGQQUEUED] = 130220137Strasz RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 131220137Strasz [RACCT_MSGQSIZE] = 132220137Strasz RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 133220137Strasz [RACCT_NMSGQ] = 134220137Strasz RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 135220137Strasz [RACCT_NSEM] = 136220137Strasz RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 137220137Strasz [RACCT_NSEMOP] = 138220137Strasz RACCT_RECLAIMABLE | RACCT_INHERITABLE | RACCT_DENIABLE, 139220137Strasz [RACCT_NSHM] = 140220137Strasz RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 141220137Strasz [RACCT_SHMSIZE] = 142220137Strasz RACCT_RECLAIMABLE | RACCT_DENIABLE | RACCT_SLOPPY, 143220137Strasz [RACCT_WALLCLOCK] = 144224036Strasz RACCT_IN_MILLIONS }; 145220137Strasz 146220137Straszstatic void 147220137Straszracct_add_racct(struct racct *dest, const struct racct *src) 148220137Strasz{ 149220137Strasz int i; 150220137Strasz 151220137Strasz mtx_assert(&racct_lock, MA_OWNED); 152220137Strasz 153220137Strasz /* 154220137Strasz * Update resource usage in dest. 155220137Strasz */ 156220137Strasz for (i = 0; i <= RACCT_MAX; i++) { 157220137Strasz KASSERT(dest->r_resources[i] >= 0, 158220137Strasz ("racct propagation meltdown: dest < 0")); 159220137Strasz KASSERT(src->r_resources[i] >= 0, 160220137Strasz ("racct propagation meltdown: src < 0")); 161220137Strasz dest->r_resources[i] += src->r_resources[i]; 162220137Strasz } 163220137Strasz} 164220137Strasz 165220137Straszstatic void 166220137Straszracct_sub_racct(struct racct *dest, const struct racct *src) 167220137Strasz{ 168220137Strasz int i; 169220137Strasz 170220137Strasz mtx_assert(&racct_lock, MA_OWNED); 171220137Strasz 172220137Strasz /* 173220137Strasz * Update resource usage in dest. 174220137Strasz */ 175220137Strasz for (i = 0; i <= RACCT_MAX; i++) { 176223844Strasz if (!RACCT_IS_SLOPPY(i)) { 177220137Strasz KASSERT(dest->r_resources[i] >= 0, 178220137Strasz ("racct propagation meltdown: dest < 0")); 179220137Strasz KASSERT(src->r_resources[i] >= 0, 180220137Strasz ("racct propagation meltdown: src < 0")); 181220137Strasz KASSERT(src->r_resources[i] <= dest->r_resources[i], 182220137Strasz ("racct propagation meltdown: src > dest")); 183220137Strasz } 184223844Strasz if (RACCT_IS_RECLAIMABLE(i)) { 185220137Strasz dest->r_resources[i] -= src->r_resources[i]; 186220137Strasz if (dest->r_resources[i] < 0) { 187223844Strasz KASSERT(RACCT_IS_SLOPPY(i), 188220137Strasz ("racct_sub_racct: usage < 0")); 189220137Strasz dest->r_resources[i] = 0; 190220137Strasz } 191220137Strasz } 192220137Strasz } 193220137Strasz} 194220137Strasz 195220137Straszvoid 196220137Straszracct_create(struct racct **racctp) 197220137Strasz{ 198220137Strasz 199220137Strasz SDT_PROBE(racct, kernel, racct, create, racctp, 0, 0, 0, 0); 200220137Strasz 201220137Strasz KASSERT(*racctp == NULL, ("racct already allocated")); 202220137Strasz 203220137Strasz *racctp = uma_zalloc(racct_zone, M_WAITOK | M_ZERO); 204220137Strasz} 205220137Strasz 206220137Straszstatic void 207220137Straszracct_destroy_locked(struct racct **racctp) 208220137Strasz{ 209220137Strasz int i; 210220137Strasz struct racct *racct; 211220137Strasz 212220137Strasz SDT_PROBE(racct, kernel, racct, destroy, racctp, 0, 0, 0, 0); 213220137Strasz 214220137Strasz mtx_assert(&racct_lock, MA_OWNED); 215220137Strasz KASSERT(racctp != NULL, ("NULL racctp")); 216220137Strasz KASSERT(*racctp != NULL, ("NULL racct")); 217220137Strasz 218220137Strasz racct = *racctp; 219220137Strasz 220220137Strasz for (i = 0; i <= RACCT_MAX; i++) { 221223844Strasz if (RACCT_IS_SLOPPY(i)) 222220137Strasz continue; 223223844Strasz if (!RACCT_IS_RECLAIMABLE(i)) 224220137Strasz continue; 225220137Strasz KASSERT(racct->r_resources[i] == 0, 226220137Strasz ("destroying non-empty racct: " 227220137Strasz "%ju allocated for resource %d\n", 228220137Strasz racct->r_resources[i], i)); 229220137Strasz } 230220137Strasz uma_zfree(racct_zone, racct); 231220137Strasz *racctp = NULL; 232220137Strasz} 233220137Strasz 234220137Straszvoid 235220137Straszracct_destroy(struct racct **racct) 236220137Strasz{ 237220137Strasz 238220137Strasz mtx_lock(&racct_lock); 239220137Strasz racct_destroy_locked(racct); 240220137Strasz mtx_unlock(&racct_lock); 241220137Strasz} 242220137Strasz 243220137Strasz/* 244220137Strasz * Increase consumption of 'resource' by 'amount' for 'racct' 245220137Strasz * and all its parents. Differently from other cases, 'amount' here 246220137Strasz * may be less than zero. 247220137Strasz */ 248220137Straszstatic void 249220137Straszracct_alloc_resource(struct racct *racct, int resource, 250220137Strasz uint64_t amount) 251220137Strasz{ 252220137Strasz 253220137Strasz mtx_assert(&racct_lock, MA_OWNED); 254220137Strasz KASSERT(racct != NULL, ("NULL racct")); 255220137Strasz 256220137Strasz racct->r_resources[resource] += amount; 257220137Strasz if (racct->r_resources[resource] < 0) { 258223844Strasz KASSERT(RACCT_IS_SLOPPY(resource), 259220137Strasz ("racct_alloc_resource: usage < 0")); 260220137Strasz racct->r_resources[resource] = 0; 261220137Strasz } 262220137Strasz} 263220137Strasz 264220137Strasz/* 265220137Strasz * Increase allocation of 'resource' by 'amount' for process 'p'. 266220137Strasz * Return 0 if it's below limits, or errno, if it's not. 267220137Strasz */ 268220137Straszint 269220137Straszracct_add(struct proc *p, int resource, uint64_t amount) 270220137Strasz{ 271220137Strasz#ifdef RCTL 272220137Strasz int error; 273220137Strasz#endif 274220137Strasz 275220137Strasz if (p->p_flag & P_SYSTEM) 276220137Strasz return (0); 277220137Strasz 278220137Strasz SDT_PROBE(racct, kernel, rusage, add, p, resource, amount, 0, 0); 279220137Strasz 280220137Strasz /* 281220137Strasz * We need proc lock to dereference p->p_ucred. 282220137Strasz */ 283220137Strasz PROC_LOCK_ASSERT(p, MA_OWNED); 284220137Strasz 285220137Strasz mtx_lock(&racct_lock); 286220137Strasz#ifdef RCTL 287220137Strasz error = rctl_enforce(p, resource, amount); 288223844Strasz if (error && RACCT_IS_DENIABLE(resource)) { 289220137Strasz SDT_PROBE(racct, kernel, rusage, add_failure, p, resource, 290220137Strasz amount, 0, 0); 291220137Strasz mtx_unlock(&racct_lock); 292220137Strasz return (error); 293220137Strasz } 294220137Strasz#endif 295220137Strasz racct_alloc_resource(p->p_racct, resource, amount); 296220137Strasz racct_add_cred_locked(p->p_ucred, resource, amount); 297220137Strasz mtx_unlock(&racct_lock); 298220137Strasz 299220137Strasz return (0); 300220137Strasz} 301220137Strasz 302220137Straszstatic void 303220137Straszracct_add_cred_locked(struct ucred *cred, int resource, uint64_t amount) 304220137Strasz{ 305220137Strasz struct prison *pr; 306220137Strasz 307220137Strasz SDT_PROBE(racct, kernel, rusage, add_cred, cred, resource, amount, 308220137Strasz 0, 0); 309220137Strasz 310220137Strasz racct_alloc_resource(cred->cr_ruidinfo->ui_racct, resource, amount); 311220137Strasz for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) 312221362Strasz racct_alloc_resource(pr->pr_prison_racct->prr_racct, resource, 313221362Strasz amount); 314220137Strasz racct_alloc_resource(cred->cr_loginclass->lc_racct, resource, amount); 315220137Strasz} 316220137Strasz 317220137Strasz/* 318220137Strasz * Increase allocation of 'resource' by 'amount' for credential 'cred'. 319220137Strasz * Doesn't check for limits and never fails. 320220137Strasz * 321220137Strasz * XXX: Shouldn't this ever return an error? 322220137Strasz */ 323220137Straszvoid 324220137Straszracct_add_cred(struct ucred *cred, int resource, uint64_t amount) 325220137Strasz{ 326220137Strasz 327220137Strasz mtx_lock(&racct_lock); 328220137Strasz racct_add_cred_locked(cred, resource, amount); 329220137Strasz mtx_unlock(&racct_lock); 330220137Strasz} 331220137Strasz 332220137Strasz/* 333220137Strasz * Increase allocation of 'resource' by 'amount' for process 'p'. 334220137Strasz * Doesn't check for limits and never fails. 335220137Strasz */ 336220137Straszvoid 337220137Straszracct_add_force(struct proc *p, int resource, uint64_t amount) 338220137Strasz{ 339220137Strasz 340220137Strasz if (p->p_flag & P_SYSTEM) 341220137Strasz return; 342220137Strasz 343220137Strasz SDT_PROBE(racct, kernel, rusage, add_force, p, resource, amount, 0, 0); 344220137Strasz 345220137Strasz /* 346220137Strasz * We need proc lock to dereference p->p_ucred. 347220137Strasz */ 348220137Strasz PROC_LOCK_ASSERT(p, MA_OWNED); 349220137Strasz 350220137Strasz mtx_lock(&racct_lock); 351220137Strasz racct_alloc_resource(p->p_racct, resource, amount); 352220137Strasz mtx_unlock(&racct_lock); 353220137Strasz racct_add_cred(p->p_ucred, resource, amount); 354220137Strasz} 355220137Strasz 356220137Straszstatic int 357220137Straszracct_set_locked(struct proc *p, int resource, uint64_t amount) 358220137Strasz{ 359220137Strasz int64_t diff; 360220137Strasz#ifdef RCTL 361220137Strasz int error; 362220137Strasz#endif 363220137Strasz 364220137Strasz if (p->p_flag & P_SYSTEM) 365220137Strasz return (0); 366220137Strasz 367220137Strasz SDT_PROBE(racct, kernel, rusage, set, p, resource, amount, 0, 0); 368220137Strasz 369220137Strasz /* 370220137Strasz * We need proc lock to dereference p->p_ucred. 371220137Strasz */ 372220137Strasz PROC_LOCK_ASSERT(p, MA_OWNED); 373220137Strasz 374220137Strasz diff = amount - p->p_racct->r_resources[resource]; 375220137Strasz#ifdef notyet 376223844Strasz KASSERT(diff >= 0 || RACCT_IS_RECLAIMABLE(resource), 377220137Strasz ("racct_set: usage of non-reclaimable resource %d dropping", 378220137Strasz resource)); 379220137Strasz#endif 380220137Strasz#ifdef RCTL 381220137Strasz if (diff > 0) { 382220137Strasz error = rctl_enforce(p, resource, diff); 383223844Strasz if (error && RACCT_IS_DENIABLE(resource)) { 384220137Strasz SDT_PROBE(racct, kernel, rusage, set_failure, p, 385220137Strasz resource, amount, 0, 0); 386220137Strasz return (error); 387220137Strasz } 388220137Strasz } 389220137Strasz#endif 390220137Strasz racct_alloc_resource(p->p_racct, resource, diff); 391220137Strasz if (diff > 0) 392220137Strasz racct_add_cred_locked(p->p_ucred, resource, diff); 393220137Strasz else if (diff < 0) 394220137Strasz racct_sub_cred_locked(p->p_ucred, resource, -diff); 395220137Strasz 396220137Strasz return (0); 397220137Strasz} 398220137Strasz 399220137Strasz/* 400220137Strasz * Set allocation of 'resource' to 'amount' for process 'p'. 401220137Strasz * Return 0 if it's below limits, or errno, if it's not. 402220137Strasz * 403220137Strasz * Note that decreasing the allocation always returns 0, 404220137Strasz * even if it's above the limit. 405220137Strasz */ 406220137Straszint 407220137Straszracct_set(struct proc *p, int resource, uint64_t amount) 408220137Strasz{ 409220137Strasz int error; 410220137Strasz 411220137Strasz mtx_lock(&racct_lock); 412220137Strasz error = racct_set_locked(p, resource, amount); 413220137Strasz mtx_unlock(&racct_lock); 414220137Strasz return (error); 415220137Strasz} 416220137Strasz 417220137Straszvoid 418220137Straszracct_set_force(struct proc *p, int resource, uint64_t amount) 419220137Strasz{ 420220137Strasz int64_t diff; 421220137Strasz 422220137Strasz if (p->p_flag & P_SYSTEM) 423220137Strasz return; 424220137Strasz 425220137Strasz SDT_PROBE(racct, kernel, rusage, set, p, resource, amount, 0, 0); 426220137Strasz 427220137Strasz /* 428220137Strasz * We need proc lock to dereference p->p_ucred. 429220137Strasz */ 430220137Strasz PROC_LOCK_ASSERT(p, MA_OWNED); 431220137Strasz 432220137Strasz mtx_lock(&racct_lock); 433220137Strasz diff = amount - p->p_racct->r_resources[resource]; 434220137Strasz racct_alloc_resource(p->p_racct, resource, diff); 435220137Strasz if (diff > 0) 436220137Strasz racct_add_cred_locked(p->p_ucred, resource, diff); 437220137Strasz else if (diff < 0) 438220137Strasz racct_sub_cred_locked(p->p_ucred, resource, -diff); 439220137Strasz mtx_unlock(&racct_lock); 440220137Strasz} 441220137Strasz 442220137Strasz/* 443220137Strasz * Returns amount of 'resource' the process 'p' can keep allocated. 444220137Strasz * Allocating more than that would be denied, unless the resource 445220137Strasz * is marked undeniable. Amount of already allocated resource does 446220137Strasz * not matter. 447220137Strasz */ 448220137Straszuint64_t 449220137Straszracct_get_limit(struct proc *p, int resource) 450220137Strasz{ 451220137Strasz 452220137Strasz#ifdef RCTL 453220137Strasz return (rctl_get_limit(p, resource)); 454220137Strasz#else 455220137Strasz return (UINT64_MAX); 456220137Strasz#endif 457220137Strasz} 458220137Strasz 459220137Strasz/* 460220137Strasz * Returns amount of 'resource' the process 'p' can keep allocated. 461220137Strasz * Allocating more than that would be denied, unless the resource 462220137Strasz * is marked undeniable. Amount of already allocated resource does 463220137Strasz * matter. 464220137Strasz */ 465220137Straszuint64_t 466220137Straszracct_get_available(struct proc *p, int resource) 467220137Strasz{ 468220137Strasz 469220137Strasz#ifdef RCTL 470220137Strasz return (rctl_get_available(p, resource)); 471220137Strasz#else 472220137Strasz return (UINT64_MAX); 473220137Strasz#endif 474220137Strasz} 475220137Strasz 476220137Strasz/* 477220137Strasz * Decrease allocation of 'resource' by 'amount' for process 'p'. 478220137Strasz */ 479220137Straszvoid 480220137Straszracct_sub(struct proc *p, int resource, uint64_t amount) 481220137Strasz{ 482220137Strasz 483220137Strasz if (p->p_flag & P_SYSTEM) 484220137Strasz return; 485220137Strasz 486220137Strasz SDT_PROBE(racct, kernel, rusage, sub, p, resource, amount, 0, 0); 487220137Strasz 488220137Strasz /* 489220137Strasz * We need proc lock to dereference p->p_ucred. 490220137Strasz */ 491220137Strasz PROC_LOCK_ASSERT(p, MA_OWNED); 492223844Strasz KASSERT(RACCT_IS_RECLAIMABLE(resource), 493220137Strasz ("racct_sub: called for non-reclaimable resource %d", resource)); 494220137Strasz 495220137Strasz mtx_lock(&racct_lock); 496220137Strasz KASSERT(amount <= p->p_racct->r_resources[resource], 497220137Strasz ("racct_sub: freeing %ju of resource %d, which is more " 498220137Strasz "than allocated %jd for %s (pid %d)", amount, resource, 499220137Strasz (intmax_t)p->p_racct->r_resources[resource], p->p_comm, p->p_pid)); 500220137Strasz 501220137Strasz racct_alloc_resource(p->p_racct, resource, -amount); 502220137Strasz racct_sub_cred_locked(p->p_ucred, resource, amount); 503220137Strasz mtx_unlock(&racct_lock); 504220137Strasz} 505220137Strasz 506220137Straszstatic void 507220137Straszracct_sub_cred_locked(struct ucred *cred, int resource, uint64_t amount) 508220137Strasz{ 509220137Strasz struct prison *pr; 510220137Strasz 511220137Strasz SDT_PROBE(racct, kernel, rusage, sub_cred, cred, resource, amount, 512220137Strasz 0, 0); 513220137Strasz 514220137Strasz#ifdef notyet 515223844Strasz KASSERT(RACCT_IS_RECLAIMABLE(resource), 516220137Strasz ("racct_sub_cred: called for non-reclaimable resource %d", 517220137Strasz resource)); 518220137Strasz#endif 519220137Strasz 520220137Strasz racct_alloc_resource(cred->cr_ruidinfo->ui_racct, resource, -amount); 521220137Strasz for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) 522221362Strasz racct_alloc_resource(pr->pr_prison_racct->prr_racct, resource, 523221362Strasz -amount); 524220137Strasz racct_alloc_resource(cred->cr_loginclass->lc_racct, resource, -amount); 525220137Strasz} 526220137Strasz 527220137Strasz/* 528220137Strasz * Decrease allocation of 'resource' by 'amount' for credential 'cred'. 529220137Strasz */ 530220137Straszvoid 531220137Straszracct_sub_cred(struct ucred *cred, int resource, uint64_t amount) 532220137Strasz{ 533220137Strasz 534220137Strasz mtx_lock(&racct_lock); 535220137Strasz racct_sub_cred_locked(cred, resource, amount); 536220137Strasz mtx_unlock(&racct_lock); 537220137Strasz} 538220137Strasz 539220137Strasz/* 540220137Strasz * Inherit resource usage information from the parent process. 541220137Strasz */ 542220137Straszint 543220137Straszracct_proc_fork(struct proc *parent, struct proc *child) 544220137Strasz{ 545220137Strasz int i, error = 0; 546220137Strasz 547220137Strasz /* 548220137Strasz * Create racct for the child process. 549220137Strasz */ 550220137Strasz racct_create(&child->p_racct); 551220137Strasz 552220137Strasz /* 553220137Strasz * No resource accounting for kernel processes. 554220137Strasz */ 555220137Strasz if (child->p_flag & P_SYSTEM) 556220137Strasz return (0); 557220137Strasz 558220137Strasz PROC_LOCK(parent); 559220137Strasz PROC_LOCK(child); 560220137Strasz mtx_lock(&racct_lock); 561220137Strasz 562220137Strasz /* 563220137Strasz * Inherit resource usage. 564220137Strasz */ 565220137Strasz for (i = 0; i <= RACCT_MAX; i++) { 566220137Strasz if (parent->p_racct->r_resources[i] == 0 || 567223844Strasz !RACCT_IS_INHERITABLE(i)) 568220137Strasz continue; 569220137Strasz 570220137Strasz error = racct_set_locked(child, i, 571220137Strasz parent->p_racct->r_resources[i]); 572225938Strasz if (error != 0) 573220137Strasz goto out; 574220137Strasz } 575220137Strasz 576220137Strasz#ifdef RCTL 577220137Strasz error = rctl_proc_fork(parent, child); 578220137Strasz#endif 579220137Strasz 580220137Straszout: 581220137Strasz mtx_unlock(&racct_lock); 582220137Strasz PROC_UNLOCK(child); 583220137Strasz PROC_UNLOCK(parent); 584220137Strasz 585220137Strasz return (error); 586220137Strasz} 587220137Strasz 588220137Straszvoid 589220137Straszracct_proc_exit(struct proc *p) 590220137Strasz{ 591225364Strasz int i; 592220137Strasz uint64_t runtime; 593220137Strasz 594220137Strasz PROC_LOCK(p); 595220137Strasz /* 596220137Strasz * We don't need to calculate rux, proc_reap() has already done this. 597220137Strasz */ 598220137Strasz runtime = cputick2usec(p->p_rux.rux_runtime); 599220137Strasz#ifdef notyet 600220137Strasz KASSERT(runtime >= p->p_prev_runtime, ("runtime < p_prev_runtime")); 601220137Strasz#else 602220137Strasz if (runtime < p->p_prev_runtime) 603220137Strasz runtime = p->p_prev_runtime; 604220137Strasz#endif 605225364Strasz mtx_lock(&racct_lock); 606225364Strasz racct_set_locked(p, RACCT_CPU, runtime); 607220137Strasz 608225364Strasz for (i = 0; i <= RACCT_MAX; i++) { 609225364Strasz if (p->p_racct->r_resources[i] == 0) 610225364Strasz continue; 611225364Strasz if (!RACCT_IS_RECLAIMABLE(i)) 612225364Strasz continue; 613225364Strasz racct_set_locked(p, i, 0); 614225364Strasz } 615225364Strasz 616225364Strasz mtx_unlock(&racct_lock); 617220137Strasz PROC_UNLOCK(p); 618220137Strasz 619220137Strasz#ifdef RCTL 620220137Strasz rctl_racct_release(p->p_racct); 621220137Strasz#endif 622220137Strasz racct_destroy(&p->p_racct); 623220137Strasz} 624220137Strasz 625220137Strasz/* 626220137Strasz * Called after credentials change, to move resource utilisation 627220137Strasz * between raccts. 628220137Strasz */ 629220137Straszvoid 630220137Straszracct_proc_ucred_changed(struct proc *p, struct ucred *oldcred, 631220137Strasz struct ucred *newcred) 632220137Strasz{ 633220137Strasz struct uidinfo *olduip, *newuip; 634220137Strasz struct loginclass *oldlc, *newlc; 635220137Strasz struct prison *oldpr, *newpr, *pr; 636220137Strasz 637220137Strasz PROC_LOCK_ASSERT(p, MA_NOTOWNED); 638220137Strasz 639220137Strasz newuip = newcred->cr_ruidinfo; 640220137Strasz olduip = oldcred->cr_ruidinfo; 641220137Strasz newlc = newcred->cr_loginclass; 642220137Strasz oldlc = oldcred->cr_loginclass; 643220137Strasz newpr = newcred->cr_prison; 644220137Strasz oldpr = oldcred->cr_prison; 645220137Strasz 646220137Strasz mtx_lock(&racct_lock); 647220137Strasz if (newuip != olduip) { 648220137Strasz racct_sub_racct(olduip->ui_racct, p->p_racct); 649220137Strasz racct_add_racct(newuip->ui_racct, p->p_racct); 650220137Strasz } 651220137Strasz if (newlc != oldlc) { 652220137Strasz racct_sub_racct(oldlc->lc_racct, p->p_racct); 653220137Strasz racct_add_racct(newlc->lc_racct, p->p_racct); 654220137Strasz } 655220137Strasz if (newpr != oldpr) { 656220137Strasz for (pr = oldpr; pr != NULL; pr = pr->pr_parent) 657221362Strasz racct_sub_racct(pr->pr_prison_racct->prr_racct, 658221362Strasz p->p_racct); 659220137Strasz for (pr = newpr; pr != NULL; pr = pr->pr_parent) 660221362Strasz racct_add_racct(pr->pr_prison_racct->prr_racct, 661221362Strasz p->p_racct); 662220137Strasz } 663220137Strasz mtx_unlock(&racct_lock); 664220137Strasz 665220137Strasz#ifdef RCTL 666220137Strasz rctl_proc_ucred_changed(p, newcred); 667220137Strasz#endif 668220137Strasz} 669220137Strasz 670220137Straszstatic void 671220137Straszracctd(void) 672220137Strasz{ 673220137Strasz struct thread *td; 674220137Strasz struct proc *p; 675220137Strasz struct timeval wallclock; 676220137Strasz uint64_t runtime; 677220137Strasz 678220137Strasz for (;;) { 679220137Strasz sx_slock(&allproc_lock); 680220137Strasz 681220137Strasz FOREACH_PROC_IN_SYSTEM(p) { 682220137Strasz if (p->p_state != PRS_NORMAL) 683220137Strasz continue; 684220137Strasz if (p->p_flag & P_SYSTEM) 685220137Strasz continue; 686220137Strasz 687220137Strasz microuptime(&wallclock); 688220137Strasz timevalsub(&wallclock, &p->p_stats->p_start); 689220137Strasz PROC_LOCK(p); 690220137Strasz PROC_SLOCK(p); 691220137Strasz FOREACH_THREAD_IN_PROC(p, td) { 692220137Strasz ruxagg(p, td); 693220137Strasz thread_lock(td); 694220137Strasz thread_unlock(td); 695220137Strasz } 696220137Strasz runtime = cputick2usec(p->p_rux.rux_runtime); 697220137Strasz PROC_SUNLOCK(p); 698220137Strasz#ifdef notyet 699220137Strasz KASSERT(runtime >= p->p_prev_runtime, 700220137Strasz ("runtime < p_prev_runtime")); 701220137Strasz#else 702220137Strasz if (runtime < p->p_prev_runtime) 703220137Strasz runtime = p->p_prev_runtime; 704220137Strasz#endif 705220137Strasz p->p_prev_runtime = runtime; 706220137Strasz mtx_lock(&racct_lock); 707220137Strasz racct_set_locked(p, RACCT_CPU, runtime); 708220137Strasz racct_set_locked(p, RACCT_WALLCLOCK, 709220137Strasz wallclock.tv_sec * 1000000 + wallclock.tv_usec); 710220137Strasz mtx_unlock(&racct_lock); 711220137Strasz PROC_UNLOCK(p); 712220137Strasz } 713220137Strasz sx_sunlock(&allproc_lock); 714220137Strasz pause("-", hz); 715220137Strasz } 716220137Strasz} 717220137Strasz 718220137Straszstatic struct kproc_desc racctd_kp = { 719220137Strasz "racctd", 720220137Strasz racctd, 721220137Strasz NULL 722220137Strasz}; 723220137StraszSYSINIT(racctd, SI_SUB_RACCTD, SI_ORDER_FIRST, kproc_start, &racctd_kp); 724220137Strasz 725220137Straszstatic void 726220137Straszracct_init(void) 727220137Strasz{ 728220137Strasz 729220137Strasz racct_zone = uma_zcreate("racct", sizeof(struct racct), 730220137Strasz NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); 731220137Strasz /* 732220137Strasz * XXX: Move this somewhere. 733220137Strasz */ 734221362Strasz prison0.pr_prison_racct = prison_racct_find("0"); 735220137Strasz} 736220137StraszSYSINIT(racct, SI_SUB_RACCT, SI_ORDER_FIRST, racct_init, NULL); 737220137Strasz 738220137Strasz#else /* !RACCT */ 739220137Strasz 740220137Straszint 741220137Straszracct_add(struct proc *p, int resource, uint64_t amount) 742220137Strasz{ 743220137Strasz 744220137Strasz return (0); 745220137Strasz} 746220137Strasz 747220137Straszvoid 748220137Straszracct_add_cred(struct ucred *cred, int resource, uint64_t amount) 749220137Strasz{ 750220137Strasz} 751220137Strasz 752220137Straszvoid 753220137Straszracct_add_force(struct proc *p, int resource, uint64_t amount) 754220137Strasz{ 755220137Strasz 756220137Strasz return; 757220137Strasz} 758220137Strasz 759220137Straszint 760220137Straszracct_set(struct proc *p, int resource, uint64_t amount) 761220137Strasz{ 762220137Strasz 763220137Strasz return (0); 764220137Strasz} 765220137Strasz 766220137Straszvoid 767220372Straszracct_set_force(struct proc *p, int resource, uint64_t amount) 768220372Strasz{ 769220372Strasz} 770220372Strasz 771220372Straszvoid 772220137Straszracct_sub(struct proc *p, int resource, uint64_t amount) 773220137Strasz{ 774220137Strasz} 775220137Strasz 776220137Straszvoid 777220137Straszracct_sub_cred(struct ucred *cred, int resource, uint64_t amount) 778220137Strasz{ 779220137Strasz} 780220137Strasz 781220137Straszuint64_t 782220137Straszracct_get_limit(struct proc *p, int resource) 783220137Strasz{ 784220137Strasz 785220137Strasz return (UINT64_MAX); 786220137Strasz} 787220137Strasz 788220372Straszuint64_t 789220372Straszracct_get_available(struct proc *p, int resource) 790220372Strasz{ 791220372Strasz 792220372Strasz return (UINT64_MAX); 793220372Strasz} 794220372Strasz 795220137Straszvoid 796220137Straszracct_create(struct racct **racctp) 797220137Strasz{ 798220137Strasz} 799220137Strasz 800220137Straszvoid 801220137Straszracct_destroy(struct racct **racctp) 802220137Strasz{ 803220137Strasz} 804220137Strasz 805220137Straszint 806220137Straszracct_proc_fork(struct proc *parent, struct proc *child) 807220137Strasz{ 808220137Strasz 809220137Strasz return (0); 810220137Strasz} 811220137Strasz 812220137Straszvoid 813220137Straszracct_proc_exit(struct proc *p) 814220137Strasz{ 815220137Strasz} 816220137Strasz 817220137Strasz#endif /* !RACCT */ 818