xref: /csrg-svn/sys/kern/kern_resource.c (revision 54815)
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*54815Storek  *	@(#)kern_resource.c	7.20 (Berkeley) 07/08/92
823373Smckusick  */
97Sbill 
1017092Sbloom #include "param.h"
11*54815Storek #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 
2243365Smckusick getpriority(curp, uap, retval)
2343365Smckusick 	struct proc *curp;
2443365Smckusick 	register struct args {
258031Sroot 		int	which;
268031Sroot 		int	who;
2743365Smckusick 	} *uap;
2843365Smckusick 	int *retval;
2943365Smckusick {
308031Sroot 	register struct proc *p;
3135810Smarc 	register int low = PRIO_MAX + 1;
328031Sroot 
338031Sroot 	switch (uap->which) {
348031Sroot 
358031Sroot 	case PRIO_PROCESS:
368031Sroot 		if (uap->who == 0)
3743365Smckusick 			p = curp;
388031Sroot 		else
398031Sroot 			p = pfind(uap->who);
408031Sroot 		if (p == 0)
4128149Skarels 			break;
4217400Skarels 		low = p->p_nice;
438031Sroot 		break;
448031Sroot 
4535810Smarc 	case PRIO_PGRP: {
4635810Smarc 		register struct pgrp *pg;
4735810Smarc 
488031Sroot 		if (uap->who == 0)
4943365Smckusick 			pg = curp->p_pgrp;
5035810Smarc 		else if ((pg = pgfind(uap->who)) == NULL)
5135810Smarc 			break;
5235810Smarc 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
5335810Smarc 			if (p->p_nice < low)
5417400Skarels 				low = p->p_nice;
558176Sroot 		}
568031Sroot 		break;
5735810Smarc 	}
588031Sroot 
598176Sroot 	case PRIO_USER:
608176Sroot 		if (uap->who == 0)
6147541Skarels 			uap->who = curp->p_ucred->cr_uid;
6254783Storek 		for (p = (struct proc *)allproc; p != NULL; p = p->p_nxt) {
6347541Skarels 			if (p->p_ucred->cr_uid == uap->who &&
6417400Skarels 			    p->p_nice < low)
6517400Skarels 				low = p->p_nice;
668176Sroot 		}
678176Sroot 		break;
688176Sroot 
698031Sroot 	default:
7044405Skarels 		return (EINVAL);
718031Sroot 	}
7243365Smckusick 	if (low == PRIO_MAX + 1)
7344405Skarels 		return (ESRCH);
7443365Smckusick 	*retval = low;
7544405Skarels 	return (0);
768031Sroot }
778031Sroot 
7843365Smckusick /* ARGSUSED */
7943365Smckusick setpriority(curp, uap, retval)
8043365Smckusick 	struct proc *curp;
8143365Smckusick 	register struct args {
828031Sroot 		int	which;
838031Sroot 		int	who;
848031Sroot 		int	prio;
8543365Smckusick 	} *uap;
8643365Smckusick 	int *retval;
8743365Smckusick {
888031Sroot 	register struct proc *p;
8943365Smckusick 	int found = 0, error = 0;
908031Sroot 
918031Sroot 	switch (uap->which) {
928031Sroot 
938031Sroot 	case PRIO_PROCESS:
948176Sroot 		if (uap->who == 0)
9543365Smckusick 			p = curp;
968176Sroot 		else
978176Sroot 			p = pfind(uap->who);
988031Sroot 		if (p == 0)
9928149Skarels 			break;
10043365Smckusick 		error = donice(curp, p, uap->prio);
10117400Skarels 		found++;
1028031Sroot 		break;
1038031Sroot 
10435810Smarc 	case PRIO_PGRP: {
10535810Smarc 		register struct pgrp *pg;
10635810Smarc 
1078176Sroot 		if (uap->who == 0)
10843365Smckusick 			pg = curp->p_pgrp;
10935810Smarc 		else if ((pg = pgfind(uap->who)) == NULL)
11035810Smarc 			break;
11135810Smarc 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
11243365Smckusick 			error = donice(curp, p, uap->prio);
11335810Smarc 			found++;
11435810Smarc 		}
1158031Sroot 		break;
11635810Smarc 	}
1178031Sroot 
1188176Sroot 	case PRIO_USER:
1198176Sroot 		if (uap->who == 0)
12047541Skarels 			uap->who = curp->p_ucred->cr_uid;
12154783Storek 		for (p = (struct proc *)allproc; p != NULL; p = p->p_nxt)
12247541Skarels 			if (p->p_ucred->cr_uid == uap->who) {
12343365Smckusick 				error = donice(curp, p, uap->prio);
12417400Skarels 				found++;
12517400Skarels 			}
1268176Sroot 		break;
1278176Sroot 
1288031Sroot 	default:
12944405Skarels 		return (EINVAL);
1308031Sroot 	}
13117400Skarels 	if (found == 0)
13244405Skarels 		return (ESRCH);
13344405Skarels 	return (0);
1348031Sroot }
1358031Sroot 
13643365Smckusick donice(curp, chgp, n)
13743365Smckusick 	register struct proc *curp, *chgp;
1388031Sroot 	register int n;
1398031Sroot {
14047541Skarels 	register struct pcred *pcred = curp->p_cred;
1418031Sroot 
14247541Skarels 	if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
14347541Skarels 	    pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
14447541Skarels 	    pcred->p_ruid != chgp->p_ucred->cr_uid)
14543365Smckusick 		return (EPERM);
14617400Skarels 	if (n > PRIO_MAX)
14717400Skarels 		n = PRIO_MAX;
14817400Skarels 	if (n < PRIO_MIN)
14917400Skarels 		n = PRIO_MIN;
15047541Skarels 	if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
15143365Smckusick 		return (EACCES);
15243365Smckusick 	chgp->p_nice = n;
15343365Smckusick 	(void) setpri(chgp);
15443365Smckusick 	return (0);
1558031Sroot }
1568031Sroot 
15754345Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
15843365Smckusick /* ARGSUSED */
15943365Smckusick setrlimit(p, uap, retval)
16043365Smckusick 	struct proc *p;
16143365Smckusick 	register struct args {
1628031Sroot 		u_int	which;
16353761Smckusick 		struct	orlimit *lim;
16453761Smckusick 	} *uap;
16553761Smckusick 	int *retval;
16653761Smckusick {
16753761Smckusick 	struct orlimit olim;
16853761Smckusick 	struct rlimit lim;
16953761Smckusick 	int error;
17053761Smckusick 
17153761Smckusick 	if (error =
17253761Smckusick 	    copyin((caddr_t)uap->lim, (caddr_t)&olim, sizeof (struct orlimit)))
17353761Smckusick 		return (error);
17453761Smckusick 	lim.rlim_cur = olim.rlim_cur;
17553761Smckusick 	lim.rlim_max = olim.rlim_max;
17653761Smckusick 	return (dosetrlimit(p, uap->which, &lim));
17753761Smckusick }
17853761Smckusick 
17953761Smckusick /* ARGSUSED */
18053761Smckusick getrlimit(p, uap, retval)
18153761Smckusick 	struct proc *p;
18253761Smckusick 	register struct args {
18353761Smckusick 		u_int	which;
18453761Smckusick 		struct	orlimit *rlp;
18553761Smckusick 	} *uap;
18653761Smckusick 	int *retval;
18753761Smckusick {
18853761Smckusick 	struct orlimit olim;
18953761Smckusick 
19053761Smckusick 	if (uap->which >= RLIM_NLIMITS)
19153761Smckusick 		return (EINVAL);
19253761Smckusick 	olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
19353761Smckusick 	if (olim.rlim_cur == -1)
19453761Smckusick 		olim.rlim_cur = 0x7fffffff;
19553761Smckusick 	olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
19653761Smckusick 	if (olim.rlim_max == -1)
19753761Smckusick 		olim.rlim_max = 0x7fffffff;
19853761Smckusick 	return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
19953761Smckusick }
20054345Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
20153761Smckusick 
20253761Smckusick /* ARGSUSED */
20353761Smckusick __setrlimit(p, uap, retval)
20453761Smckusick 	struct proc *p;
20553761Smckusick 	register struct args {
20653761Smckusick 		u_int	which;
2078031Sroot 		struct	rlimit *lim;
20843365Smckusick 	} *uap;
20943365Smckusick 	int *retval;
21043365Smckusick {
2118031Sroot 	struct rlimit alim;
21253761Smckusick 	int error;
21353761Smckusick 
21453761Smckusick 	if (error =
21553761Smckusick 	    copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit)))
21653761Smckusick 		return (error);
21753761Smckusick 	return (dosetrlimit(p, uap->which, &alim));
21853761Smckusick }
21953761Smckusick 
22053761Smckusick dosetrlimit(p, which, limp)
22153761Smckusick 	struct proc *p;
22253761Smckusick 	u_int which;
22353761Smckusick 	struct rlimit *limp;
22453761Smckusick {
2258031Sroot 	register struct rlimit *alimp;
22625257Skarels 	extern unsigned maxdmap;
22743365Smckusick 	int error;
2288031Sroot 
22953761Smckusick 	if (which >= RLIM_NLIMITS)
23044405Skarels 		return (EINVAL);
23153761Smckusick 	alimp = &p->p_rlimit[which];
23253761Smckusick 	if (limp->rlim_cur > alimp->rlim_max ||
23353761Smckusick 	    limp->rlim_max > alimp->rlim_max)
23447541Skarels 		if (error = suser(p->p_ucred, &p->p_acflag))
23544405Skarels 			return (error);
23653761Smckusick 	if (limp->rlim_cur > limp->rlim_max)
23753761Smckusick 		limp->rlim_cur = limp->rlim_max;
23847541Skarels 	if (p->p_limit->p_refcnt > 1 &&
23947541Skarels 	    (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
24047541Skarels 		p->p_limit->p_refcnt--;
24147541Skarels 		p->p_limit = limcopy(p->p_limit);
24253761Smckusick 		alimp = &p->p_rlimit[which];
24347541Skarels 	}
24447541Skarels 
24553761Smckusick 	switch (which) {
2468031Sroot 
2478031Sroot 	case RLIMIT_DATA:
24853761Smckusick 		if (limp->rlim_cur > maxdmap)
24953761Smckusick 			limp->rlim_cur = maxdmap;
25053761Smckusick 		if (limp->rlim_max > maxdmap)
25153761Smckusick 			limp->rlim_max = maxdmap;
2528031Sroot 		break;
2538031Sroot 
2548031Sroot 	case RLIMIT_STACK:
25553761Smckusick 		if (limp->rlim_cur > maxdmap)
25653761Smckusick 			limp->rlim_cur = maxdmap;
25753761Smckusick 		if (limp->rlim_max > maxdmap)
25853761Smckusick 			limp->rlim_max = maxdmap;
25949282Shibler 		/*
26049282Shibler 		 * Stack is allocated to the max at exec time with only
26149282Shibler 		 * "rlim_cur" bytes accessible.  If stack limit is going
26249282Shibler 		 * up make more accessible, if going down make inaccessible.
26349282Shibler 		 */
26453761Smckusick 		if (limp->rlim_cur != alimp->rlim_cur) {
26549282Shibler 			vm_offset_t addr;
26649282Shibler 			vm_size_t size;
26749282Shibler 			vm_prot_t prot;
26849282Shibler 
26953761Smckusick 			if (limp->rlim_cur > alimp->rlim_cur) {
27049282Shibler 				prot = VM_PROT_ALL;
27153761Smckusick 				size = limp->rlim_cur - alimp->rlim_cur;
27253761Smckusick 				addr = USRSTACK - limp->rlim_cur;
27349282Shibler 			} else {
27449282Shibler 				prot = VM_PROT_NONE;
27553761Smckusick 				size = alimp->rlim_cur - limp->rlim_cur;
27649282Shibler 				addr = USRSTACK - alimp->rlim_cur;
27749282Shibler 			}
27849282Shibler 			addr = trunc_page(addr);
27949282Shibler 			size = round_page(size);
28049282Shibler 			(void) vm_map_protect(&p->p_vmspace->vm_map,
28149282Shibler 					      addr, addr+size, prot, FALSE);
28249282Shibler 		}
2838031Sroot 		break;
2848031Sroot 	}
28553761Smckusick 	*alimp = *limp;
28644405Skarels 	return (0);
2878031Sroot }
2888031Sroot 
28943365Smckusick /* ARGSUSED */
29053761Smckusick __getrlimit(p, uap, retval)
29143365Smckusick 	struct proc *p;
29243365Smckusick 	register struct args {
2938031Sroot 		u_int	which;
2948031Sroot 		struct	rlimit *rlp;
29543365Smckusick 	} *uap;
29643365Smckusick 	int *retval;
29743365Smckusick {
2988031Sroot 
29943365Smckusick 	if (uap->which >= RLIM_NLIMITS)
30044405Skarels 		return (EINVAL);
30147541Skarels 	return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
30243365Smckusick 	    sizeof (struct rlimit)));
3038031Sroot }
3048031Sroot 
30554783Storek /*
30654783Storek  * Transform the running time and tick information in proc p into user,
30754783Storek  * system, and interrupt time usage.
30854783Storek  */
30954783Storek calcru(p, up, sp, ip)
31054783Storek 	register struct proc *p;
31154783Storek 	register struct timeval *up;
31254783Storek 	register struct timeval *sp;
31354783Storek 	register struct timeval *ip;
31454783Storek {
315*54815Storek 	register u_quad_t u, st, ut, it, tot;
316*54815Storek 	register u_long sec, usec;
317*54815Storek 	register int s;
318*54815Storek 	struct timeval tv;
31954783Storek 
32054783Storek 	s = splstatclock();
32154783Storek 	st = p->p_sticks;
32254783Storek 	ut = p->p_uticks;
32354783Storek 	it = p->p_iticks;
32454783Storek 	splx(s);
32554783Storek 
32654783Storek 	tot = st + ut + it;
32754783Storek 	if (tot == 0) {
32854783Storek 		up->tv_sec = up->tv_usec = 0;
32954783Storek 		sp->tv_sec = sp->tv_usec = 0;
33054783Storek 		if (ip != NULL)
33154783Storek 			ip->tv_sec = ip->tv_usec = 0;
33254783Storek 		return;
33354783Storek 	}
334*54815Storek 
335*54815Storek 	sec = p->p_rtime.tv_sec;
336*54815Storek 	usec = p->p_rtime.tv_usec;
337*54815Storek 	if (p == curproc) {
338*54815Storek 		/*
339*54815Storek 		 * Adjust for the current time slice.  This is actually fairly
340*54815Storek 		 * important since the error here is on the order of a time
341*54815Storek 		 * quantum, which is much greater than the sampling error.
342*54815Storek 		 */
343*54815Storek 		microtime(&tv);
344*54815Storek 		sec += tv.tv_sec - runtime.tv_sec;
345*54815Storek 		usec += tv.tv_usec - runtime.tv_usec;
346*54815Storek 	}
347*54815Storek 	u = sec * 1000000 + usec;
348*54815Storek 	st = (u * st) / tot;
34954783Storek 	sp->tv_sec = st / 1000000;
35054783Storek 	sp->tv_usec = st % 1000000;
351*54815Storek 	ut = (u * ut) / tot;
35254783Storek 	up->tv_sec = ut / 1000000;
35354783Storek 	up->tv_usec = ut % 1000000;
35454783Storek 	if (ip != NULL) {
355*54815Storek 		it = (u * it) / tot;
35654783Storek 		ip->tv_sec = it / 1000000;
35754783Storek 		ip->tv_usec = it % 1000000;
35854783Storek 	}
35954783Storek }
36054783Storek 
36143365Smckusick /* ARGSUSED */
36243365Smckusick getrusage(p, uap, retval)
36343365Smckusick 	register struct proc *p;
36443365Smckusick 	register struct args {
3658031Sroot 		int	who;
3668031Sroot 		struct	rusage *rusage;
36743365Smckusick 	} *uap;
36843365Smckusick 	int *retval;
36943365Smckusick {
3708031Sroot 	register struct rusage *rup;
3718031Sroot 
3728031Sroot 	switch (uap->who) {
3738031Sroot 
374*54815Storek 	case RUSAGE_SELF:
37547541Skarels 		rup = &p->p_stats->p_ru;
376*54815Storek 		calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
3778031Sroot 		break;
3788031Sroot 
3798031Sroot 	case RUSAGE_CHILDREN:
38047541Skarels 		rup = &p->p_stats->p_cru;
3818031Sroot 		break;
3828031Sroot 
3838031Sroot 	default:
38444405Skarels 		return (EINVAL);
3858031Sroot 	}
38644405Skarels 	return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
38743365Smckusick 	    sizeof (struct rusage)));
3888031Sroot }
3898031Sroot 
3908031Sroot ruadd(ru, ru2)
3918031Sroot 	register struct rusage *ru, *ru2;
3928031Sroot {
3938666Sroot 	register long *ip, *ip2;
3948031Sroot 	register int i;
3958031Sroot 
3968031Sroot 	timevaladd(&ru->ru_utime, &ru2->ru_utime);
3978031Sroot 	timevaladd(&ru->ru_stime, &ru2->ru_stime);
3988031Sroot 	if (ru->ru_maxrss < ru2->ru_maxrss)
3998031Sroot 		ru->ru_maxrss = ru2->ru_maxrss;
4008031Sroot 	ip = &ru->ru_first; ip2 = &ru2->ru_first;
40153644Sbostic 	for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
4028031Sroot 		*ip++ += *ip2++;
4038031Sroot }
40447541Skarels 
40547541Skarels /*
40647541Skarels  * Make a copy of the plimit structure.
40747541Skarels  * We share these structures copy-on-write after fork,
40847541Skarels  * and copy when a limit is changed.
40947541Skarels  */
41047541Skarels struct plimit *
41147541Skarels limcopy(lim)
41247541Skarels 	struct plimit *lim;
41347541Skarels {
41447541Skarels 	register struct plimit *copy;
41547541Skarels 
41647541Skarels 	MALLOC(copy, struct plimit *, sizeof(struct plimit),
41747541Skarels 	    M_SUBPROC, M_WAITOK);
41847541Skarels 	bcopy(lim->pl_rlimit, copy->pl_rlimit,
41947541Skarels 	    sizeof(struct rlimit) * RLIM_NLIMITS);
42047541Skarels 	copy->p_lflags = 0;
42147541Skarels 	copy->p_refcnt = 1;
42247541Skarels 	return (copy);
42347541Skarels }
424