1*49594Sbostic /*- 2*49594Sbostic * Copyright (c) 1982, 1986, 1991 The Regents of the University of California. 3*49594Sbostic * All rights reserved. 423373Smckusick * 5*49594Sbostic * %sccs.include.redist.c% 6*49594Sbostic * 7*49594Sbostic * @(#)kern_resource.c 7.13 (Berkeley) 05/09/91 823373Smckusick */ 97Sbill 1017092Sbloom #include "param.h" 1147541Skarels #include "resourcevar.h" 1247541Skarels #include "malloc.h" 1317092Sbloom #include "proc.h" 147Sbill 1549282Shibler #include "vm/vm.h" 1649282Shibler 178176Sroot /* 188176Sroot * Resource controls and accounting. 198176Sroot */ 208176Sroot 2143365Smckusick getpriority(curp, uap, retval) 2243365Smckusick struct proc *curp; 2343365Smckusick register struct args { 248031Sroot int which; 258031Sroot int who; 2643365Smckusick } *uap; 2743365Smckusick int *retval; 2843365Smckusick { 298031Sroot register struct proc *p; 3035810Smarc register int low = PRIO_MAX + 1; 318031Sroot 328031Sroot switch (uap->which) { 338031Sroot 348031Sroot case PRIO_PROCESS: 358031Sroot if (uap->who == 0) 3643365Smckusick p = curp; 378031Sroot else 388031Sroot p = pfind(uap->who); 398031Sroot if (p == 0) 4028149Skarels break; 4117400Skarels low = p->p_nice; 428031Sroot break; 438031Sroot 4435810Smarc case PRIO_PGRP: { 4535810Smarc register struct pgrp *pg; 4635810Smarc 478031Sroot if (uap->who == 0) 4843365Smckusick pg = curp->p_pgrp; 4935810Smarc else if ((pg = pgfind(uap->who)) == NULL) 5035810Smarc break; 5135810Smarc for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) { 5235810Smarc if (p->p_nice < low) 5317400Skarels low = p->p_nice; 548176Sroot } 558031Sroot break; 5635810Smarc } 578031Sroot 588176Sroot case PRIO_USER: 598176Sroot if (uap->who == 0) 6047541Skarels uap->who = curp->p_ucred->cr_uid; 6116530Skarels for (p = allproc; p != NULL; p = p->p_nxt) { 6247541Skarels if (p->p_ucred->cr_uid == uap->who && 6317400Skarels p->p_nice < low) 6417400Skarels low = p->p_nice; 658176Sroot } 668176Sroot break; 678176Sroot 688031Sroot default: 6944405Skarels return (EINVAL); 708031Sroot } 7143365Smckusick if (low == PRIO_MAX + 1) 7244405Skarels return (ESRCH); 7343365Smckusick *retval = low; 7444405Skarels return (0); 758031Sroot } 768031Sroot 7743365Smckusick /* ARGSUSED */ 7843365Smckusick setpriority(curp, uap, retval) 7943365Smckusick struct proc *curp; 8043365Smckusick register struct args { 818031Sroot int which; 828031Sroot int who; 838031Sroot int prio; 8443365Smckusick } *uap; 8543365Smckusick int *retval; 8643365Smckusick { 878031Sroot register struct proc *p; 8843365Smckusick int found = 0, error = 0; 898031Sroot 908031Sroot switch (uap->which) { 918031Sroot 928031Sroot case PRIO_PROCESS: 938176Sroot if (uap->who == 0) 9443365Smckusick p = curp; 958176Sroot else 968176Sroot p = pfind(uap->who); 978031Sroot if (p == 0) 9828149Skarels break; 9943365Smckusick error = donice(curp, p, uap->prio); 10017400Skarels found++; 1018031Sroot break; 1028031Sroot 10335810Smarc case PRIO_PGRP: { 10435810Smarc register struct pgrp *pg; 10535810Smarc 1068176Sroot if (uap->who == 0) 10743365Smckusick pg = curp->p_pgrp; 10835810Smarc else if ((pg = pgfind(uap->who)) == NULL) 10935810Smarc break; 11035810Smarc for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) { 11143365Smckusick error = donice(curp, p, uap->prio); 11235810Smarc found++; 11335810Smarc } 1148031Sroot break; 11535810Smarc } 1168031Sroot 1178176Sroot case PRIO_USER: 1188176Sroot if (uap->who == 0) 11947541Skarels uap->who = curp->p_ucred->cr_uid; 12016530Skarels for (p = allproc; p != NULL; p = p->p_nxt) 12147541Skarels if (p->p_ucred->cr_uid == uap->who) { 12243365Smckusick error = donice(curp, p, uap->prio); 12317400Skarels found++; 12417400Skarels } 1258176Sroot break; 1268176Sroot 1278031Sroot default: 12844405Skarels return (EINVAL); 1298031Sroot } 13017400Skarels if (found == 0) 13144405Skarels return (ESRCH); 13244405Skarels return (0); 1338031Sroot } 1348031Sroot 13543365Smckusick donice(curp, chgp, n) 13643365Smckusick register struct proc *curp, *chgp; 1378031Sroot register int n; 1388031Sroot { 13947541Skarels register struct pcred *pcred = curp->p_cred; 1408031Sroot 14147541Skarels if (pcred->pc_ucred->cr_uid && pcred->p_ruid && 14247541Skarels pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid && 14347541Skarels pcred->p_ruid != chgp->p_ucred->cr_uid) 14443365Smckusick return (EPERM); 14517400Skarels if (n > PRIO_MAX) 14617400Skarels n = PRIO_MAX; 14717400Skarels if (n < PRIO_MIN) 14817400Skarels n = PRIO_MIN; 14947541Skarels if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag)) 15043365Smckusick return (EACCES); 15143365Smckusick chgp->p_nice = n; 15243365Smckusick (void) setpri(chgp); 15343365Smckusick return (0); 1548031Sroot } 1558031Sroot 15643365Smckusick /* ARGSUSED */ 15743365Smckusick setrlimit(p, uap, retval) 15843365Smckusick struct proc *p; 15943365Smckusick register struct args { 1608031Sroot u_int which; 1618031Sroot struct rlimit *lim; 16243365Smckusick } *uap; 16343365Smckusick int *retval; 16443365Smckusick { 1658031Sroot struct rlimit alim; 1668031Sroot register struct rlimit *alimp; 16725257Skarels extern unsigned maxdmap; 16843365Smckusick int error; 1698031Sroot 17043365Smckusick if (uap->which >= RLIM_NLIMITS) 17144405Skarels return (EINVAL); 17247541Skarels alimp = &p->p_rlimit[uap->which]; 17343365Smckusick if (error = 17443365Smckusick copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit))) 17544405Skarels return (error); 1768031Sroot if (alim.rlim_cur > alimp->rlim_max || alim.rlim_max > alimp->rlim_max) 17747541Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 17844405Skarels return (error); 17947541Skarels if (p->p_limit->p_refcnt > 1 && 18047541Skarels (p->p_limit->p_lflags & PL_SHAREMOD) == 0) { 18147541Skarels p->p_limit->p_refcnt--; 18247541Skarels p->p_limit = limcopy(p->p_limit); 18347541Skarels } 18447541Skarels 1858031Sroot switch (uap->which) { 1868031Sroot 1878031Sroot case RLIMIT_DATA: 18818279Smckusick if (alim.rlim_cur > maxdmap) 18918279Smckusick alim.rlim_cur = maxdmap; 19018279Smckusick if (alim.rlim_max > maxdmap) 19118279Smckusick alim.rlim_max = maxdmap; 1928031Sroot break; 1938031Sroot 1948031Sroot case RLIMIT_STACK: 19518279Smckusick if (alim.rlim_cur > maxdmap) 19618279Smckusick alim.rlim_cur = maxdmap; 19718279Smckusick if (alim.rlim_max > maxdmap) 19818279Smckusick alim.rlim_max = maxdmap; 19949282Shibler /* 20049282Shibler * Stack is allocated to the max at exec time with only 20149282Shibler * "rlim_cur" bytes accessible. If stack limit is going 20249282Shibler * up make more accessible, if going down make inaccessible. 20349282Shibler */ 20449282Shibler if (alim.rlim_cur != alimp->rlim_cur) { 20549282Shibler vm_offset_t addr; 20649282Shibler vm_size_t size; 20749282Shibler vm_prot_t prot; 20849282Shibler 20949282Shibler if (alim.rlim_cur > alimp->rlim_cur) { 21049282Shibler prot = VM_PROT_ALL; 21149282Shibler size = alim.rlim_cur - alimp->rlim_cur; 21249282Shibler addr = USRSTACK - alim.rlim_cur; 21349282Shibler } else { 21449282Shibler prot = VM_PROT_NONE; 21549282Shibler size = alimp->rlim_cur - alim.rlim_cur; 21649282Shibler addr = USRSTACK - alimp->rlim_cur; 21749282Shibler } 21849282Shibler addr = trunc_page(addr); 21949282Shibler size = round_page(size); 22049282Shibler (void) vm_map_protect(&p->p_vmspace->vm_map, 22149282Shibler addr, addr+size, prot, FALSE); 22249282Shibler } 2238031Sroot break; 2248031Sroot } 22548419Skarels p->p_rlimit[uap->which] = alim; 22644405Skarels return (0); 2278031Sroot } 2288031Sroot 22943365Smckusick /* ARGSUSED */ 23043365Smckusick getrlimit(p, uap, retval) 23143365Smckusick struct proc *p; 23243365Smckusick register struct args { 2338031Sroot u_int which; 2348031Sroot struct rlimit *rlp; 23543365Smckusick } *uap; 23643365Smckusick int *retval; 23743365Smckusick { 2388031Sroot 23943365Smckusick if (uap->which >= RLIM_NLIMITS) 24044405Skarels return (EINVAL); 24147541Skarels return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp, 24243365Smckusick sizeof (struct rlimit))); 2438031Sroot } 2448031Sroot 24543365Smckusick /* ARGSUSED */ 24643365Smckusick getrusage(p, uap, retval) 24743365Smckusick register struct proc *p; 24843365Smckusick register struct args { 2498031Sroot int who; 2508031Sroot struct rusage *rusage; 25143365Smckusick } *uap; 25243365Smckusick int *retval; 25343365Smckusick { 2548031Sroot register struct rusage *rup; 2558031Sroot 2568031Sroot switch (uap->who) { 2578031Sroot 25840705Skarels case RUSAGE_SELF: { 25940705Skarels int s; 26040705Skarels 26147541Skarels rup = &p->p_stats->p_ru; 26240705Skarels s = splclock(); 26340705Skarels rup->ru_stime = p->p_stime; 26440705Skarels rup->ru_utime = p->p_utime; 26540705Skarels splx(s); 2668031Sroot break; 26740705Skarels } 2688031Sroot 2698031Sroot case RUSAGE_CHILDREN: 27047541Skarels rup = &p->p_stats->p_cru; 2718031Sroot break; 2728031Sroot 2738031Sroot default: 27444405Skarels return (EINVAL); 2758031Sroot } 27644405Skarels return (copyout((caddr_t)rup, (caddr_t)uap->rusage, 27743365Smckusick sizeof (struct rusage))); 2788031Sroot } 2798031Sroot 2808031Sroot ruadd(ru, ru2) 2818031Sroot register struct rusage *ru, *ru2; 2828031Sroot { 2838666Sroot register long *ip, *ip2; 2848031Sroot register int i; 2858031Sroot 2868031Sroot timevaladd(&ru->ru_utime, &ru2->ru_utime); 2878031Sroot timevaladd(&ru->ru_stime, &ru2->ru_stime); 2888031Sroot if (ru->ru_maxrss < ru2->ru_maxrss) 2898031Sroot ru->ru_maxrss = ru2->ru_maxrss; 2908031Sroot ip = &ru->ru_first; ip2 = &ru2->ru_first; 2918031Sroot for (i = &ru->ru_last - &ru->ru_first; i > 0; i--) 2928031Sroot *ip++ += *ip2++; 2938031Sroot } 29447541Skarels 29547541Skarels /* 29647541Skarels * Make a copy of the plimit structure. 29747541Skarels * We share these structures copy-on-write after fork, 29847541Skarels * and copy when a limit is changed. 29947541Skarels */ 30047541Skarels struct plimit * 30147541Skarels limcopy(lim) 30247541Skarels struct plimit *lim; 30347541Skarels { 30447541Skarels register struct plimit *copy; 30547541Skarels 30647541Skarels MALLOC(copy, struct plimit *, sizeof(struct plimit), 30747541Skarels M_SUBPROC, M_WAITOK); 30847541Skarels bcopy(lim->pl_rlimit, copy->pl_rlimit, 30947541Skarels sizeof(struct rlimit) * RLIM_NLIMITS); 31047541Skarels copy->p_lflags = 0; 31147541Skarels copy->p_refcnt = 1; 31247541Skarels return (copy); 31347541Skarels } 314