xref: /csrg-svn/sys/kern/kern_resource.c (revision 54935)
149594Sbostic /*-
249594Sbostic  * Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
349594Sbostic  * All rights reserved.
423373Smckusick  *
549594Sbostic  * %sccs.include.redist.c%
649594Sbostic  *
7*54935Storek  *	@(#)kern_resource.c	7.21 (Berkeley) 07/10/92
823373Smckusick  */
97Sbill 
1017092Sbloom #include "param.h"
1154815Storek #include "kernel.h"
1247541Skarels #include "resourcevar.h"
1347541Skarels #include "malloc.h"
1417092Sbloom #include "proc.h"
157Sbill 
1649282Shibler #include "vm/vm.h"
1749282Shibler 
188176Sroot /*
198176Sroot  * Resource controls and accounting.
208176Sroot  */
218176Sroot 
22*54935Storek struct getpriority_args {
23*54935Storek 	int	which;
24*54935Storek 	int	who;
25*54935Storek };
2643365Smckusick getpriority(curp, uap, retval)
2743365Smckusick 	struct proc *curp;
28*54935Storek 	register struct getpriority_args *uap;
2943365Smckusick 	int *retval;
3043365Smckusick {
318031Sroot 	register struct proc *p;
3235810Smarc 	register int low = PRIO_MAX + 1;
338031Sroot 
348031Sroot 	switch (uap->which) {
358031Sroot 
368031Sroot 	case PRIO_PROCESS:
378031Sroot 		if (uap->who == 0)
3843365Smckusick 			p = curp;
398031Sroot 		else
408031Sroot 			p = pfind(uap->who);
418031Sroot 		if (p == 0)
4228149Skarels 			break;
4317400Skarels 		low = p->p_nice;
448031Sroot 		break;
458031Sroot 
4635810Smarc 	case PRIO_PGRP: {
4735810Smarc 		register struct pgrp *pg;
4835810Smarc 
498031Sroot 		if (uap->who == 0)
5043365Smckusick 			pg = curp->p_pgrp;
5135810Smarc 		else if ((pg = pgfind(uap->who)) == NULL)
5235810Smarc 			break;
5335810Smarc 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
5435810Smarc 			if (p->p_nice < low)
5517400Skarels 				low = p->p_nice;
568176Sroot 		}
578031Sroot 		break;
5835810Smarc 	}
598031Sroot 
608176Sroot 	case PRIO_USER:
618176Sroot 		if (uap->who == 0)
6247541Skarels 			uap->who = curp->p_ucred->cr_uid;
6354783Storek 		for (p = (struct proc *)allproc; p != NULL; p = p->p_nxt) {
6447541Skarels 			if (p->p_ucred->cr_uid == uap->who &&
6517400Skarels 			    p->p_nice < low)
6617400Skarels 				low = p->p_nice;
678176Sroot 		}
688176Sroot 		break;
698176Sroot 
708031Sroot 	default:
7144405Skarels 		return (EINVAL);
728031Sroot 	}
7343365Smckusick 	if (low == PRIO_MAX + 1)
7444405Skarels 		return (ESRCH);
7543365Smckusick 	*retval = low;
7644405Skarels 	return (0);
778031Sroot }
788031Sroot 
79*54935Storek struct setpriority_args {
80*54935Storek 	int	which;
81*54935Storek 	int	who;
82*54935Storek 	int	prio;
83*54935Storek };
8443365Smckusick /* ARGSUSED */
8543365Smckusick setpriority(curp, uap, retval)
8643365Smckusick 	struct proc *curp;
87*54935Storek 	register struct setpriority_args *uap;
8843365Smckusick 	int *retval;
8943365Smckusick {
908031Sroot 	register struct proc *p;
9143365Smckusick 	int found = 0, error = 0;
928031Sroot 
938031Sroot 	switch (uap->which) {
948031Sroot 
958031Sroot 	case PRIO_PROCESS:
968176Sroot 		if (uap->who == 0)
9743365Smckusick 			p = curp;
988176Sroot 		else
998176Sroot 			p = pfind(uap->who);
1008031Sroot 		if (p == 0)
10128149Skarels 			break;
10243365Smckusick 		error = donice(curp, p, uap->prio);
10317400Skarels 		found++;
1048031Sroot 		break;
1058031Sroot 
10635810Smarc 	case PRIO_PGRP: {
10735810Smarc 		register struct pgrp *pg;
10835810Smarc 
1098176Sroot 		if (uap->who == 0)
11043365Smckusick 			pg = curp->p_pgrp;
11135810Smarc 		else if ((pg = pgfind(uap->who)) == NULL)
11235810Smarc 			break;
11335810Smarc 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
11443365Smckusick 			error = donice(curp, p, uap->prio);
11535810Smarc 			found++;
11635810Smarc 		}
1178031Sroot 		break;
11835810Smarc 	}
1198031Sroot 
1208176Sroot 	case PRIO_USER:
1218176Sroot 		if (uap->who == 0)
12247541Skarels 			uap->who = curp->p_ucred->cr_uid;
12354783Storek 		for (p = (struct proc *)allproc; p != NULL; p = p->p_nxt)
12447541Skarels 			if (p->p_ucred->cr_uid == uap->who) {
12543365Smckusick 				error = donice(curp, p, uap->prio);
12617400Skarels 				found++;
12717400Skarels 			}
1288176Sroot 		break;
1298176Sroot 
1308031Sroot 	default:
13144405Skarels 		return (EINVAL);
1328031Sroot 	}
13317400Skarels 	if (found == 0)
13444405Skarels 		return (ESRCH);
13544405Skarels 	return (0);
1368031Sroot }
1378031Sroot 
13843365Smckusick donice(curp, chgp, n)
13943365Smckusick 	register struct proc *curp, *chgp;
1408031Sroot 	register int n;
1418031Sroot {
14247541Skarels 	register struct pcred *pcred = curp->p_cred;
1438031Sroot 
14447541Skarels 	if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
14547541Skarels 	    pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
14647541Skarels 	    pcred->p_ruid != chgp->p_ucred->cr_uid)
14743365Smckusick 		return (EPERM);
14817400Skarels 	if (n > PRIO_MAX)
14917400Skarels 		n = PRIO_MAX;
15017400Skarels 	if (n < PRIO_MIN)
15117400Skarels 		n = PRIO_MIN;
15247541Skarels 	if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
15343365Smckusick 		return (EACCES);
15443365Smckusick 	chgp->p_nice = n;
15543365Smckusick 	(void) setpri(chgp);
15643365Smckusick 	return (0);
1578031Sroot }
1588031Sroot 
15954345Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
160*54935Storek struct setrlimit_args {
161*54935Storek 	u_int	which;
162*54935Storek 	struct	orlimit *lim;
163*54935Storek };
16443365Smckusick /* ARGSUSED */
16543365Smckusick setrlimit(p, uap, retval)
16643365Smckusick 	struct proc *p;
167*54935Storek 	register struct setrlimit_args *uap;
16853761Smckusick 	int *retval;
16953761Smckusick {
17053761Smckusick 	struct orlimit olim;
17153761Smckusick 	struct rlimit lim;
17253761Smckusick 	int error;
17353761Smckusick 
17453761Smckusick 	if (error =
17553761Smckusick 	    copyin((caddr_t)uap->lim, (caddr_t)&olim, sizeof (struct orlimit)))
17653761Smckusick 		return (error);
17753761Smckusick 	lim.rlim_cur = olim.rlim_cur;
17853761Smckusick 	lim.rlim_max = olim.rlim_max;
17953761Smckusick 	return (dosetrlimit(p, uap->which, &lim));
18053761Smckusick }
18153761Smckusick 
182*54935Storek struct getrlimit_args {
183*54935Storek 	u_int	which;
184*54935Storek 	struct	orlimit *rlp;
185*54935Storek };
18653761Smckusick /* ARGSUSED */
18753761Smckusick getrlimit(p, uap, retval)
18853761Smckusick 	struct proc *p;
189*54935Storek 	register struct getrlimit_args *uap;
19053761Smckusick 	int *retval;
19153761Smckusick {
19253761Smckusick 	struct orlimit olim;
19353761Smckusick 
19453761Smckusick 	if (uap->which >= RLIM_NLIMITS)
19553761Smckusick 		return (EINVAL);
19653761Smckusick 	olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
19753761Smckusick 	if (olim.rlim_cur == -1)
19853761Smckusick 		olim.rlim_cur = 0x7fffffff;
19953761Smckusick 	olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
20053761Smckusick 	if (olim.rlim_max == -1)
20153761Smckusick 		olim.rlim_max = 0x7fffffff;
20253761Smckusick 	return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
20353761Smckusick }
20454345Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
20553761Smckusick 
206*54935Storek struct __setrlimit_args {
207*54935Storek 	u_int	which;
208*54935Storek 	struct	rlimit *lim;
209*54935Storek };
21053761Smckusick /* ARGSUSED */
21153761Smckusick __setrlimit(p, uap, retval)
21253761Smckusick 	struct proc *p;
213*54935Storek 	register struct __setrlimit_args *uap;
21443365Smckusick 	int *retval;
21543365Smckusick {
2168031Sroot 	struct rlimit alim;
21753761Smckusick 	int error;
21853761Smckusick 
21953761Smckusick 	if (error =
22053761Smckusick 	    copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit)))
22153761Smckusick 		return (error);
22253761Smckusick 	return (dosetrlimit(p, uap->which, &alim));
22353761Smckusick }
22453761Smckusick 
22553761Smckusick dosetrlimit(p, which, limp)
22653761Smckusick 	struct proc *p;
22753761Smckusick 	u_int which;
22853761Smckusick 	struct rlimit *limp;
22953761Smckusick {
2308031Sroot 	register struct rlimit *alimp;
23125257Skarels 	extern unsigned maxdmap;
23243365Smckusick 	int error;
2338031Sroot 
23453761Smckusick 	if (which >= RLIM_NLIMITS)
23544405Skarels 		return (EINVAL);
23653761Smckusick 	alimp = &p->p_rlimit[which];
23753761Smckusick 	if (limp->rlim_cur > alimp->rlim_max ||
23853761Smckusick 	    limp->rlim_max > alimp->rlim_max)
23947541Skarels 		if (error = suser(p->p_ucred, &p->p_acflag))
24044405Skarels 			return (error);
24153761Smckusick 	if (limp->rlim_cur > limp->rlim_max)
24253761Smckusick 		limp->rlim_cur = limp->rlim_max;
24347541Skarels 	if (p->p_limit->p_refcnt > 1 &&
24447541Skarels 	    (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
24547541Skarels 		p->p_limit->p_refcnt--;
24647541Skarels 		p->p_limit = limcopy(p->p_limit);
24753761Smckusick 		alimp = &p->p_rlimit[which];
24847541Skarels 	}
24947541Skarels 
25053761Smckusick 	switch (which) {
2518031Sroot 
2528031Sroot 	case RLIMIT_DATA:
25353761Smckusick 		if (limp->rlim_cur > maxdmap)
25453761Smckusick 			limp->rlim_cur = maxdmap;
25553761Smckusick 		if (limp->rlim_max > maxdmap)
25653761Smckusick 			limp->rlim_max = maxdmap;
2578031Sroot 		break;
2588031Sroot 
2598031Sroot 	case RLIMIT_STACK:
26053761Smckusick 		if (limp->rlim_cur > maxdmap)
26153761Smckusick 			limp->rlim_cur = maxdmap;
26253761Smckusick 		if (limp->rlim_max > maxdmap)
26353761Smckusick 			limp->rlim_max = maxdmap;
26449282Shibler 		/*
26549282Shibler 		 * Stack is allocated to the max at exec time with only
26649282Shibler 		 * "rlim_cur" bytes accessible.  If stack limit is going
26749282Shibler 		 * up make more accessible, if going down make inaccessible.
26849282Shibler 		 */
26953761Smckusick 		if (limp->rlim_cur != alimp->rlim_cur) {
27049282Shibler 			vm_offset_t addr;
27149282Shibler 			vm_size_t size;
27249282Shibler 			vm_prot_t prot;
27349282Shibler 
27453761Smckusick 			if (limp->rlim_cur > alimp->rlim_cur) {
27549282Shibler 				prot = VM_PROT_ALL;
27653761Smckusick 				size = limp->rlim_cur - alimp->rlim_cur;
27753761Smckusick 				addr = USRSTACK - limp->rlim_cur;
27849282Shibler 			} else {
27949282Shibler 				prot = VM_PROT_NONE;
28053761Smckusick 				size = alimp->rlim_cur - limp->rlim_cur;
28149282Shibler 				addr = USRSTACK - alimp->rlim_cur;
28249282Shibler 			}
28349282Shibler 			addr = trunc_page(addr);
28449282Shibler 			size = round_page(size);
28549282Shibler 			(void) vm_map_protect(&p->p_vmspace->vm_map,
28649282Shibler 					      addr, addr+size, prot, FALSE);
28749282Shibler 		}
2888031Sroot 		break;
2898031Sroot 	}
29053761Smckusick 	*alimp = *limp;
29144405Skarels 	return (0);
2928031Sroot }
2938031Sroot 
294*54935Storek struct __getrlimit_args {
295*54935Storek 	u_int	which;
296*54935Storek 	struct	rlimit *rlp;
297*54935Storek };
29843365Smckusick /* ARGSUSED */
29953761Smckusick __getrlimit(p, uap, retval)
30043365Smckusick 	struct proc *p;
301*54935Storek 	register struct __getrlimit_args *uap;
30243365Smckusick 	int *retval;
30343365Smckusick {
3048031Sroot 
30543365Smckusick 	if (uap->which >= RLIM_NLIMITS)
30644405Skarels 		return (EINVAL);
30747541Skarels 	return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
30843365Smckusick 	    sizeof (struct rlimit)));
3098031Sroot }
3108031Sroot 
31154783Storek /*
31254783Storek  * Transform the running time and tick information in proc p into user,
31354783Storek  * system, and interrupt time usage.
31454783Storek  */
31554783Storek calcru(p, up, sp, ip)
31654783Storek 	register struct proc *p;
31754783Storek 	register struct timeval *up;
31854783Storek 	register struct timeval *sp;
31954783Storek 	register struct timeval *ip;
32054783Storek {
32154815Storek 	register u_quad_t u, st, ut, it, tot;
32254815Storek 	register u_long sec, usec;
32354815Storek 	register int s;
32454815Storek 	struct timeval tv;
32554783Storek 
32654783Storek 	s = splstatclock();
32754783Storek 	st = p->p_sticks;
32854783Storek 	ut = p->p_uticks;
32954783Storek 	it = p->p_iticks;
33054783Storek 	splx(s);
33154783Storek 
33254783Storek 	tot = st + ut + it;
33354783Storek 	if (tot == 0) {
33454783Storek 		up->tv_sec = up->tv_usec = 0;
33554783Storek 		sp->tv_sec = sp->tv_usec = 0;
33654783Storek 		if (ip != NULL)
33754783Storek 			ip->tv_sec = ip->tv_usec = 0;
33854783Storek 		return;
33954783Storek 	}
34054815Storek 
34154815Storek 	sec = p->p_rtime.tv_sec;
34254815Storek 	usec = p->p_rtime.tv_usec;
34354815Storek 	if (p == curproc) {
34454815Storek 		/*
34554815Storek 		 * Adjust for the current time slice.  This is actually fairly
34654815Storek 		 * important since the error here is on the order of a time
34754815Storek 		 * quantum, which is much greater than the sampling error.
34854815Storek 		 */
34954815Storek 		microtime(&tv);
35054815Storek 		sec += tv.tv_sec - runtime.tv_sec;
35154815Storek 		usec += tv.tv_usec - runtime.tv_usec;
35254815Storek 	}
35354815Storek 	u = sec * 1000000 + usec;
35454815Storek 	st = (u * st) / tot;
35554783Storek 	sp->tv_sec = st / 1000000;
35654783Storek 	sp->tv_usec = st % 1000000;
35754815Storek 	ut = (u * ut) / tot;
35854783Storek 	up->tv_sec = ut / 1000000;
35954783Storek 	up->tv_usec = ut % 1000000;
36054783Storek 	if (ip != NULL) {
36154815Storek 		it = (u * it) / tot;
36254783Storek 		ip->tv_sec = it / 1000000;
36354783Storek 		ip->tv_usec = it % 1000000;
36454783Storek 	}
36554783Storek }
36654783Storek 
367*54935Storek struct getrusage_args {
368*54935Storek 	int	who;
369*54935Storek 	struct	rusage *rusage;
370*54935Storek };
37143365Smckusick /* ARGSUSED */
37243365Smckusick getrusage(p, uap, retval)
37343365Smckusick 	register struct proc *p;
374*54935Storek 	register struct getrusage_args *uap;
37543365Smckusick 	int *retval;
37643365Smckusick {
3778031Sroot 	register struct rusage *rup;
3788031Sroot 
3798031Sroot 	switch (uap->who) {
3808031Sroot 
38154815Storek 	case RUSAGE_SELF:
38247541Skarels 		rup = &p->p_stats->p_ru;
38354815Storek 		calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
3848031Sroot 		break;
3858031Sroot 
3868031Sroot 	case RUSAGE_CHILDREN:
38747541Skarels 		rup = &p->p_stats->p_cru;
3888031Sroot 		break;
3898031Sroot 
3908031Sroot 	default:
39144405Skarels 		return (EINVAL);
3928031Sroot 	}
39344405Skarels 	return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
39443365Smckusick 	    sizeof (struct rusage)));
3958031Sroot }
3968031Sroot 
3978031Sroot ruadd(ru, ru2)
3988031Sroot 	register struct rusage *ru, *ru2;
3998031Sroot {
4008666Sroot 	register long *ip, *ip2;
4018031Sroot 	register int i;
4028031Sroot 
4038031Sroot 	timevaladd(&ru->ru_utime, &ru2->ru_utime);
4048031Sroot 	timevaladd(&ru->ru_stime, &ru2->ru_stime);
4058031Sroot 	if (ru->ru_maxrss < ru2->ru_maxrss)
4068031Sroot 		ru->ru_maxrss = ru2->ru_maxrss;
4078031Sroot 	ip = &ru->ru_first; ip2 = &ru2->ru_first;
40853644Sbostic 	for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
4098031Sroot 		*ip++ += *ip2++;
4108031Sroot }
41147541Skarels 
41247541Skarels /*
41347541Skarels  * Make a copy of the plimit structure.
41447541Skarels  * We share these structures copy-on-write after fork,
41547541Skarels  * and copy when a limit is changed.
41647541Skarels  */
41747541Skarels struct plimit *
41847541Skarels limcopy(lim)
41947541Skarels 	struct plimit *lim;
42047541Skarels {
42147541Skarels 	register struct plimit *copy;
42247541Skarels 
42347541Skarels 	MALLOC(copy, struct plimit *, sizeof(struct plimit),
42447541Skarels 	    M_SUBPROC, M_WAITOK);
42547541Skarels 	bcopy(lim->pl_rlimit, copy->pl_rlimit,
42647541Skarels 	    sizeof(struct rlimit) * RLIM_NLIMITS);
42747541Skarels 	copy->p_lflags = 0;
42847541Skarels 	copy->p_refcnt = 1;
42947541Skarels 	return (copy);
43047541Skarels }
431