149594Sbostic /*-
263176Sbostic * Copyright (c) 1982, 1986, 1991, 1993
363176Sbostic * The Regents of the University of California. All rights reserved.
465771Sbostic * (c) UNIX System Laboratories, Inc.
565771Sbostic * All or some portions of this file are derived from material licensed
665771Sbostic * to the University of California by American Telephone and Telegraph
765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic * the permission of UNIX System Laboratories, Inc.
923373Smckusick *
1049594Sbostic * %sccs.include.redist.c%
1149594Sbostic *
12*68311Scgd * @(#)kern_resource.c 8.8 (Berkeley) 02/14/95
1323373Smckusick */
147Sbill
1556517Sbostic #include <sys/param.h>
16*68311Scgd #include <sys/systm.h>
1756517Sbostic #include <sys/kernel.h>
1858775Smckusick #include <sys/file.h>
1956517Sbostic #include <sys/resourcevar.h>
2056517Sbostic #include <sys/malloc.h>
2156517Sbostic #include <sys/proc.h>
227Sbill
23*68311Scgd #include <sys/mount.h>
24*68311Scgd #include <sys/syscallargs.h>
25*68311Scgd
2656517Sbostic #include <vm/vm.h>
2749282Shibler
28*68311Scgd int donice __P((struct proc *curp, struct proc *chgp, int n));
29*68311Scgd int dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
30*68311Scgd
318176Sroot /*
328176Sroot * Resource controls and accounting.
338176Sroot */
348176Sroot
35*68311Scgd int
getpriority(curp,uap,retval)3643365Smckusick getpriority(curp, uap, retval)
3743365Smckusick struct proc *curp;
38*68311Scgd register struct getpriority_args /* {
39*68311Scgd syscallarg(int) which;
40*68311Scgd syscallarg(int) who;
41*68311Scgd } */ *uap;
42*68311Scgd register_t *retval;
4343365Smckusick {
448031Sroot register struct proc *p;
4535810Smarc register int low = PRIO_MAX + 1;
468031Sroot
47*68311Scgd switch (SCARG(uap, which)) {
488031Sroot
498031Sroot case PRIO_PROCESS:
50*68311Scgd if (SCARG(uap, who) == 0)
5143365Smckusick p = curp;
528031Sroot else
53*68311Scgd p = pfind(SCARG(uap, who));
548031Sroot if (p == 0)
5528149Skarels break;
5617400Skarels low = p->p_nice;
578031Sroot break;
588031Sroot
5935810Smarc case PRIO_PGRP: {
6035810Smarc register struct pgrp *pg;
6135810Smarc
62*68311Scgd if (SCARG(uap, who) == 0)
6343365Smckusick pg = curp->p_pgrp;
64*68311Scgd else if ((pg = pgfind(SCARG(uap, who))) == NULL)
6535810Smarc break;
6667732Smckusick for (p = pg->pg_members.lh_first; p != 0;
67*68311Scgd p = p->p_pglist.le_next) {
6835810Smarc if (p->p_nice < low)
6917400Skarels low = p->p_nice;
70*68311Scgd }
718031Sroot break;
7235810Smarc }
738031Sroot
748176Sroot case PRIO_USER:
75*68311Scgd if (SCARG(uap, who) == 0)
76*68311Scgd SCARG(uap, who) = curp->p_ucred->cr_uid;
7767732Smckusick for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
78*68311Scgd if (p->p_ucred->cr_uid == SCARG(uap, who) &&
79*68311Scgd p->p_nice < low)
8017400Skarels low = p->p_nice;
818176Sroot break;
828176Sroot
838031Sroot default:
8444405Skarels return (EINVAL);
858031Sroot }
8643365Smckusick if (low == PRIO_MAX + 1)
8744405Skarels return (ESRCH);
8843365Smckusick *retval = low;
8944405Skarels return (0);
908031Sroot }
918031Sroot
9243365Smckusick /* ARGSUSED */
93*68311Scgd int
setpriority(curp,uap,retval)9443365Smckusick setpriority(curp, uap, retval)
9543365Smckusick struct proc *curp;
96*68311Scgd register struct setpriority_args /* {
97*68311Scgd syscallarg(int) which;
98*68311Scgd syscallarg(int) who;
99*68311Scgd syscallarg(int) prio;
100*68311Scgd } */ *uap;
101*68311Scgd register_t *retval;
10243365Smckusick {
1038031Sroot register struct proc *p;
10443365Smckusick int found = 0, error = 0;
1058031Sroot
106*68311Scgd switch (SCARG(uap, which)) {
1078031Sroot
1088031Sroot case PRIO_PROCESS:
109*68311Scgd if (SCARG(uap, who) == 0)
11043365Smckusick p = curp;
1118176Sroot else
112*68311Scgd p = pfind(SCARG(uap, who));
1138031Sroot if (p == 0)
11428149Skarels break;
115*68311Scgd error = donice(curp, p, SCARG(uap, prio));
11617400Skarels found++;
1178031Sroot break;
1188031Sroot
11935810Smarc case PRIO_PGRP: {
12035810Smarc register struct pgrp *pg;
12135810Smarc
122*68311Scgd if (SCARG(uap, who) == 0)
12343365Smckusick pg = curp->p_pgrp;
124*68311Scgd else if ((pg = pgfind(SCARG(uap, who))) == NULL)
12535810Smarc break;
126*68311Scgd for (p = pg->pg_members.lh_first; p != 0;
127*68311Scgd p = p->p_pglist.le_next) {
128*68311Scgd error = donice(curp, p, SCARG(uap, prio));
12935810Smarc found++;
13035810Smarc }
1318031Sroot break;
13235810Smarc }
1338031Sroot
1348176Sroot case PRIO_USER:
135*68311Scgd if (SCARG(uap, who) == 0)
136*68311Scgd SCARG(uap, who) = curp->p_ucred->cr_uid;
13767732Smckusick for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
138*68311Scgd if (p->p_ucred->cr_uid == SCARG(uap, who)) {
139*68311Scgd error = donice(curp, p, SCARG(uap, prio));
14017400Skarels found++;
14117400Skarels }
1428176Sroot break;
1438176Sroot
1448031Sroot default:
14544405Skarels return (EINVAL);
1468031Sroot }
14717400Skarels if (found == 0)
14844405Skarels return (ESRCH);
14965081Smckusick return (error);
1508031Sroot }
1518031Sroot
152*68311Scgd int
donice(curp,chgp,n)15343365Smckusick donice(curp, chgp, n)
15443365Smckusick register struct proc *curp, *chgp;
1558031Sroot register int n;
1568031Sroot {
15747541Skarels register struct pcred *pcred = curp->p_cred;
1588031Sroot
15947541Skarels if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
16047541Skarels pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
16147541Skarels pcred->p_ruid != chgp->p_ucred->cr_uid)
16243365Smckusick return (EPERM);
16317400Skarels if (n > PRIO_MAX)
16417400Skarels n = PRIO_MAX;
16517400Skarels if (n < PRIO_MIN)
16617400Skarels n = PRIO_MIN;
16747541Skarels if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
16843365Smckusick return (EACCES);
16943365Smckusick chgp->p_nice = n;
17064407Sbostic (void)resetpriority(chgp);
17143365Smckusick return (0);
1728031Sroot }
1738031Sroot
17454345Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
17543365Smckusick /* ARGSUSED */
176*68311Scgd int
compat_43_setrlimit(p,uap,retval)177*68311Scgd compat_43_setrlimit(p, uap, retval)
17843365Smckusick struct proc *p;
179*68311Scgd struct compat_43_setrlimit_args /* {
180*68311Scgd syscallarg(u_int) which;
181*68311Scgd syscallarg(struct ogetrlimit *) rlp;
182*68311Scgd } */ *uap;
183*68311Scgd register_t *retval;
18453761Smckusick {
18553761Smckusick struct orlimit olim;
18653761Smckusick struct rlimit lim;
18753761Smckusick int error;
18853761Smckusick
189*68311Scgd if (error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&olim,
190*68311Scgd sizeof (struct orlimit)))
19153761Smckusick return (error);
19253761Smckusick lim.rlim_cur = olim.rlim_cur;
19353761Smckusick lim.rlim_max = olim.rlim_max;
194*68311Scgd return (dosetrlimit(p, SCARG(uap, which), &lim));
19553761Smckusick }
19653761Smckusick
19753761Smckusick /* ARGSUSED */
198*68311Scgd int
compat_43_getrlimit(p,uap,retval)199*68311Scgd compat_43_getrlimit(p, uap, retval)
20053761Smckusick struct proc *p;
201*68311Scgd register struct compat_43_getrlimit_args /* {
202*68311Scgd syscallarg(u_int) which;
203*68311Scgd syscallarg(struct ogetrlimit *) rlp;
204*68311Scgd } */ *uap;
205*68311Scgd register_t *retval;
20653761Smckusick {
20753761Smckusick struct orlimit olim;
20853761Smckusick
209*68311Scgd if (SCARG(uap, which) >= RLIM_NLIMITS)
21053761Smckusick return (EINVAL);
211*68311Scgd olim.rlim_cur = p->p_rlimit[SCARG(uap, which)].rlim_cur;
21253761Smckusick if (olim.rlim_cur == -1)
21353761Smckusick olim.rlim_cur = 0x7fffffff;
214*68311Scgd olim.rlim_max = p->p_rlimit[SCARG(uap, which)].rlim_max;
21553761Smckusick if (olim.rlim_max == -1)
21653761Smckusick olim.rlim_max = 0x7fffffff;
217*68311Scgd return (copyout((caddr_t)&olim, (caddr_t)SCARG(uap, rlp),
218*68311Scgd sizeof(olim)));
21953761Smckusick }
22054345Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
22153761Smckusick
22253761Smckusick /* ARGSUSED */
223*68311Scgd int
setrlimit(p,uap,retval)22460411Smckusick setrlimit(p, uap, retval)
22553761Smckusick struct proc *p;
226*68311Scgd register struct setrlimit_args /* {
227*68311Scgd syscallarg(u_int) which;
228*68311Scgd syscallarg(struct rlimit *) rlp;
229*68311Scgd } */ *uap;
230*68311Scgd register_t *retval;
23143365Smckusick {
2328031Sroot struct rlimit alim;
23353761Smckusick int error;
23453761Smckusick
235*68311Scgd if (error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&alim,
236*68311Scgd sizeof (struct rlimit)))
23753761Smckusick return (error);
238*68311Scgd return (dosetrlimit(p, SCARG(uap, which), &alim));
23953761Smckusick }
24053761Smckusick
241*68311Scgd int
dosetrlimit(p,which,limp)24253761Smckusick dosetrlimit(p, which, limp)
24353761Smckusick struct proc *p;
24453761Smckusick u_int which;
24553761Smckusick struct rlimit *limp;
24653761Smckusick {
2478031Sroot register struct rlimit *alimp;
24825257Skarels extern unsigned maxdmap;
24943365Smckusick int error;
2508031Sroot
25153761Smckusick if (which >= RLIM_NLIMITS)
25244405Skarels return (EINVAL);
25353761Smckusick alimp = &p->p_rlimit[which];
25453761Smckusick if (limp->rlim_cur > alimp->rlim_max ||
25553761Smckusick limp->rlim_max > alimp->rlim_max)
25647541Skarels if (error = suser(p->p_ucred, &p->p_acflag))
25744405Skarels return (error);
25853761Smckusick if (limp->rlim_cur > limp->rlim_max)
25953761Smckusick limp->rlim_cur = limp->rlim_max;
26047541Skarels if (p->p_limit->p_refcnt > 1 &&
26147541Skarels (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
26247541Skarels p->p_limit->p_refcnt--;
26347541Skarels p->p_limit = limcopy(p->p_limit);
26453761Smckusick alimp = &p->p_rlimit[which];
26547541Skarels }
26647541Skarels
26753761Smckusick switch (which) {
2688031Sroot
2698031Sroot case RLIMIT_DATA:
27053761Smckusick if (limp->rlim_cur > maxdmap)
27153761Smckusick limp->rlim_cur = maxdmap;
27253761Smckusick if (limp->rlim_max > maxdmap)
27353761Smckusick limp->rlim_max = maxdmap;
2748031Sroot break;
2758031Sroot
2768031Sroot case RLIMIT_STACK:
27753761Smckusick if (limp->rlim_cur > maxdmap)
27853761Smckusick limp->rlim_cur = maxdmap;
27953761Smckusick if (limp->rlim_max > maxdmap)
28053761Smckusick limp->rlim_max = maxdmap;
28149282Shibler /*
28249282Shibler * Stack is allocated to the max at exec time with only
28349282Shibler * "rlim_cur" bytes accessible. If stack limit is going
28449282Shibler * up make more accessible, if going down make inaccessible.
28549282Shibler */
28653761Smckusick if (limp->rlim_cur != alimp->rlim_cur) {
28749282Shibler vm_offset_t addr;
28849282Shibler vm_size_t size;
28949282Shibler vm_prot_t prot;
29049282Shibler
29153761Smckusick if (limp->rlim_cur > alimp->rlim_cur) {
29249282Shibler prot = VM_PROT_ALL;
29353761Smckusick size = limp->rlim_cur - alimp->rlim_cur;
29453761Smckusick addr = USRSTACK - limp->rlim_cur;
29549282Shibler } else {
29649282Shibler prot = VM_PROT_NONE;
29753761Smckusick size = alimp->rlim_cur - limp->rlim_cur;
29849282Shibler addr = USRSTACK - alimp->rlim_cur;
29949282Shibler }
30049282Shibler addr = trunc_page(addr);
30149282Shibler size = round_page(size);
30249282Shibler (void) vm_map_protect(&p->p_vmspace->vm_map,
30349282Shibler addr, addr+size, prot, FALSE);
30449282Shibler }
3058031Sroot break;
30658775Smckusick
30758775Smckusick case RLIMIT_NOFILE:
30858775Smckusick if (limp->rlim_cur > maxfiles)
30958775Smckusick limp->rlim_cur = maxfiles;
31058775Smckusick if (limp->rlim_max > maxfiles)
31158775Smckusick limp->rlim_max = maxfiles;
31258775Smckusick break;
31359614Smckusick
31459614Smckusick case RLIMIT_NPROC:
31559614Smckusick if (limp->rlim_cur > maxproc)
31659614Smckusick limp->rlim_cur = maxproc;
31759614Smckusick if (limp->rlim_max > maxproc)
31859614Smckusick limp->rlim_max = maxproc;
31959614Smckusick break;
3208031Sroot }
32153761Smckusick *alimp = *limp;
32244405Skarels return (0);
3238031Sroot }
3248031Sroot
32543365Smckusick /* ARGSUSED */
326*68311Scgd int
getrlimit(p,uap,retval)32760411Smckusick getrlimit(p, uap, retval)
32843365Smckusick struct proc *p;
329*68311Scgd register struct getrlimit_args /* {
330*68311Scgd syscallarg(u_int) which;
331*68311Scgd syscallarg(struct rlimit *) rlp;
332*68311Scgd } */ *uap;
333*68311Scgd register_t *retval;
33443365Smckusick {
3358031Sroot
336*68311Scgd if (SCARG(uap, which) >= RLIM_NLIMITS)
33744405Skarels return (EINVAL);
338*68311Scgd return (copyout((caddr_t)&p->p_rlimit[SCARG(uap, which)],
339*68311Scgd (caddr_t)SCARG(uap, rlp), sizeof (struct rlimit)));
3408031Sroot }
3418031Sroot
34254783Storek /*
34354783Storek * Transform the running time and tick information in proc p into user,
34454783Storek * system, and interrupt time usage.
34554783Storek */
34668171Scgd void
calcru(p,up,sp,ip)34754783Storek calcru(p, up, sp, ip)
34854783Storek register struct proc *p;
34954783Storek register struct timeval *up;
35054783Storek register struct timeval *sp;
35154783Storek register struct timeval *ip;
35254783Storek {
35354815Storek register u_quad_t u, st, ut, it, tot;
35454815Storek register u_long sec, usec;
35554815Storek register int s;
35654815Storek struct timeval tv;
35754783Storek
35854783Storek s = splstatclock();
35954783Storek st = p->p_sticks;
36054783Storek ut = p->p_uticks;
36154783Storek it = p->p_iticks;
36254783Storek splx(s);
36354783Storek
36454783Storek tot = st + ut + it;
36554783Storek if (tot == 0) {
36654783Storek up->tv_sec = up->tv_usec = 0;
36754783Storek sp->tv_sec = sp->tv_usec = 0;
36854783Storek if (ip != NULL)
36954783Storek ip->tv_sec = ip->tv_usec = 0;
37054783Storek return;
37154783Storek }
37254815Storek
37354815Storek sec = p->p_rtime.tv_sec;
37454815Storek usec = p->p_rtime.tv_usec;
37554815Storek if (p == curproc) {
37654815Storek /*
37754815Storek * Adjust for the current time slice. This is actually fairly
37854815Storek * important since the error here is on the order of a time
37954815Storek * quantum, which is much greater than the sampling error.
38054815Storek */
38154815Storek microtime(&tv);
38254815Storek sec += tv.tv_sec - runtime.tv_sec;
38354815Storek usec += tv.tv_usec - runtime.tv_usec;
38454815Storek }
38554815Storek u = sec * 1000000 + usec;
38654815Storek st = (u * st) / tot;
38754783Storek sp->tv_sec = st / 1000000;
38854783Storek sp->tv_usec = st % 1000000;
38954815Storek ut = (u * ut) / tot;
39054783Storek up->tv_sec = ut / 1000000;
39154783Storek up->tv_usec = ut % 1000000;
39254783Storek if (ip != NULL) {
39354815Storek it = (u * it) / tot;
39454783Storek ip->tv_sec = it / 1000000;
39554783Storek ip->tv_usec = it % 1000000;
39654783Storek }
39754783Storek }
39854783Storek
39943365Smckusick /* ARGSUSED */
400*68311Scgd int
getrusage(p,uap,retval)40143365Smckusick getrusage(p, uap, retval)
40243365Smckusick register struct proc *p;
403*68311Scgd register struct getrusage_args /* {
404*68311Scgd syscallarg(int) who;
405*68311Scgd syscallarg(struct rusage *) rusage;
406*68311Scgd } */ *uap;
407*68311Scgd register_t *retval;
40843365Smckusick {
4098031Sroot register struct rusage *rup;
4108031Sroot
411*68311Scgd switch (SCARG(uap, who)) {
4128031Sroot
41354815Storek case RUSAGE_SELF:
41447541Skarels rup = &p->p_stats->p_ru;
41554815Storek calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
4168031Sroot break;
4178031Sroot
4188031Sroot case RUSAGE_CHILDREN:
41947541Skarels rup = &p->p_stats->p_cru;
4208031Sroot break;
4218031Sroot
4228031Sroot default:
42344405Skarels return (EINVAL);
4248031Sroot }
425*68311Scgd return (copyout((caddr_t)rup, (caddr_t)SCARG(uap, rusage),
42643365Smckusick sizeof (struct rusage)));
4278031Sroot }
4288031Sroot
42968171Scgd void
ruadd(ru,ru2)4308031Sroot ruadd(ru, ru2)
4318031Sroot register struct rusage *ru, *ru2;
4328031Sroot {
4338666Sroot register long *ip, *ip2;
4348031Sroot register int i;
4358031Sroot
4368031Sroot timevaladd(&ru->ru_utime, &ru2->ru_utime);
4378031Sroot timevaladd(&ru->ru_stime, &ru2->ru_stime);
4388031Sroot if (ru->ru_maxrss < ru2->ru_maxrss)
4398031Sroot ru->ru_maxrss = ru2->ru_maxrss;
4408031Sroot ip = &ru->ru_first; ip2 = &ru2->ru_first;
44153644Sbostic for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
4428031Sroot *ip++ += *ip2++;
4438031Sroot }
44447541Skarels
44547541Skarels /*
44647541Skarels * Make a copy of the plimit structure.
44747541Skarels * We share these structures copy-on-write after fork,
44847541Skarels * and copy when a limit is changed.
44947541Skarels */
45047541Skarels struct plimit *
limcopy(lim)45147541Skarels limcopy(lim)
45247541Skarels struct plimit *lim;
45347541Skarels {
45447541Skarels register struct plimit *copy;
45547541Skarels
45647541Skarels MALLOC(copy, struct plimit *, sizeof(struct plimit),
45747541Skarels M_SUBPROC, M_WAITOK);
45847541Skarels bcopy(lim->pl_rlimit, copy->pl_rlimit,
45947541Skarels sizeof(struct rlimit) * RLIM_NLIMITS);
46047541Skarels copy->p_lflags = 0;
46147541Skarels copy->p_refcnt = 1;
46247541Skarels return (copy);
46347541Skarels }
464