xref: /csrg-svn/sys/kern/kern_resource.c (revision 68311)
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