xref: /csrg-svn/sys/kern/kern_resource.c (revision 67732)
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*67732Smckusick  *	@(#)kern_resource.c	8.6 (Berkeley) 08/22/94
1323373Smckusick  */
147Sbill 
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/kernel.h>
1758775Smckusick #include <sys/file.h>
1856517Sbostic #include <sys/resourcevar.h>
1956517Sbostic #include <sys/malloc.h>
2056517Sbostic #include <sys/proc.h>
217Sbill 
2256517Sbostic #include <vm/vm.h>
2349282Shibler 
248176Sroot /*
258176Sroot  * Resource controls and accounting.
268176Sroot  */
278176Sroot 
2854935Storek struct getpriority_args {
2954935Storek 	int	which;
3054935Storek 	int	who;
3154935Storek };
3243365Smckusick getpriority(curp, uap, retval)
3343365Smckusick 	struct proc *curp;
3454935Storek 	register struct getpriority_args *uap;
3543365Smckusick 	int *retval;
3643365Smckusick {
378031Sroot 	register struct proc *p;
3835810Smarc 	register int low = PRIO_MAX + 1;
398031Sroot 
408031Sroot 	switch (uap->which) {
418031Sroot 
428031Sroot 	case PRIO_PROCESS:
438031Sroot 		if (uap->who == 0)
4443365Smckusick 			p = curp;
458031Sroot 		else
468031Sroot 			p = pfind(uap->who);
478031Sroot 		if (p == 0)
4828149Skarels 			break;
4917400Skarels 		low = p->p_nice;
508031Sroot 		break;
518031Sroot 
5235810Smarc 	case PRIO_PGRP: {
5335810Smarc 		register struct pgrp *pg;
5435810Smarc 
558031Sroot 		if (uap->who == 0)
5643365Smckusick 			pg = curp->p_pgrp;
5735810Smarc 		else if ((pg = pgfind(uap->who)) == NULL)
5835810Smarc 			break;
59*67732Smckusick 		for (p = pg->pg_members.lh_first; p != 0;
60*67732Smckusick 		     p = p->p_pglist.le_next)
6135810Smarc 			if (p->p_nice < low)
6217400Skarels 				low = p->p_nice;
638031Sroot 		break;
6435810Smarc 	}
658031Sroot 
668176Sroot 	case PRIO_USER:
678176Sroot 		if (uap->who == 0)
6847541Skarels 			uap->who = curp->p_ucred->cr_uid;
69*67732Smckusick 		for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
70*67732Smckusick 			if (p->p_ucred->cr_uid == uap->who && p->p_nice < low)
7117400Skarels 				low = p->p_nice;
728176Sroot 		break;
738176Sroot 
748031Sroot 	default:
7544405Skarels 		return (EINVAL);
768031Sroot 	}
7743365Smckusick 	if (low == PRIO_MAX + 1)
7844405Skarels 		return (ESRCH);
7943365Smckusick 	*retval = low;
8044405Skarels 	return (0);
818031Sroot }
828031Sroot 
8354935Storek struct setpriority_args {
8454935Storek 	int	which;
8554935Storek 	int	who;
8654935Storek 	int	prio;
8754935Storek };
8843365Smckusick /* ARGSUSED */
8943365Smckusick setpriority(curp, uap, retval)
9043365Smckusick 	struct proc *curp;
9154935Storek 	register struct setpriority_args *uap;
9243365Smckusick 	int *retval;
9343365Smckusick {
948031Sroot 	register struct proc *p;
9543365Smckusick 	int found = 0, error = 0;
968031Sroot 
978031Sroot 	switch (uap->which) {
988031Sroot 
998031Sroot 	case PRIO_PROCESS:
1008176Sroot 		if (uap->who == 0)
10143365Smckusick 			p = curp;
1028176Sroot 		else
1038176Sroot 			p = pfind(uap->who);
1048031Sroot 		if (p == 0)
10528149Skarels 			break;
10643365Smckusick 		error = donice(curp, p, uap->prio);
10717400Skarels 		found++;
1088031Sroot 		break;
1098031Sroot 
11035810Smarc 	case PRIO_PGRP: {
11135810Smarc 		register struct pgrp *pg;
11235810Smarc 
1138176Sroot 		if (uap->who == 0)
11443365Smckusick 			pg = curp->p_pgrp;
11535810Smarc 		else if ((pg = pgfind(uap->who)) == NULL)
11635810Smarc 			break;
117*67732Smckusick 		for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
11843365Smckusick 			error = donice(curp, p, uap->prio);
11935810Smarc 			found++;
12035810Smarc 		}
1218031Sroot 		break;
12235810Smarc 	}
1238031Sroot 
1248176Sroot 	case PRIO_USER:
1258176Sroot 		if (uap->who == 0)
12647541Skarels 			uap->who = curp->p_ucred->cr_uid;
127*67732Smckusick 		for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
12847541Skarels 			if (p->p_ucred->cr_uid == uap->who) {
12943365Smckusick 				error = donice(curp, p, uap->prio);
13017400Skarels 				found++;
13117400Skarels 			}
1328176Sroot 		break;
1338176Sroot 
1348031Sroot 	default:
13544405Skarels 		return (EINVAL);
1368031Sroot 	}
13717400Skarels 	if (found == 0)
13844405Skarels 		return (ESRCH);
13965081Smckusick 	return (error);
1408031Sroot }
1418031Sroot 
14243365Smckusick donice(curp, chgp, n)
14343365Smckusick 	register struct proc *curp, *chgp;
1448031Sroot 	register int n;
1458031Sroot {
14647541Skarels 	register struct pcred *pcred = curp->p_cred;
1478031Sroot 
14847541Skarels 	if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
14947541Skarels 	    pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
15047541Skarels 	    pcred->p_ruid != chgp->p_ucred->cr_uid)
15143365Smckusick 		return (EPERM);
15217400Skarels 	if (n > PRIO_MAX)
15317400Skarels 		n = PRIO_MAX;
15417400Skarels 	if (n < PRIO_MIN)
15517400Skarels 		n = PRIO_MIN;
15647541Skarels 	if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
15743365Smckusick 		return (EACCES);
15843365Smckusick 	chgp->p_nice = n;
15964407Sbostic 	(void)resetpriority(chgp);
16043365Smckusick 	return (0);
1618031Sroot }
1628031Sroot 
16354345Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
16454935Storek struct setrlimit_args {
16554935Storek 	u_int	which;
16654935Storek 	struct	orlimit *lim;
16754935Storek };
16843365Smckusick /* ARGSUSED */
16960105Smckusick osetrlimit(p, uap, retval)
17043365Smckusick 	struct proc *p;
17154935Storek 	register struct setrlimit_args *uap;
17253761Smckusick 	int *retval;
17353761Smckusick {
17453761Smckusick 	struct orlimit olim;
17553761Smckusick 	struct rlimit lim;
17653761Smckusick 	int error;
17753761Smckusick 
17853761Smckusick 	if (error =
17953761Smckusick 	    copyin((caddr_t)uap->lim, (caddr_t)&olim, sizeof (struct orlimit)))
18053761Smckusick 		return (error);
18153761Smckusick 	lim.rlim_cur = olim.rlim_cur;
18253761Smckusick 	lim.rlim_max = olim.rlim_max;
18353761Smckusick 	return (dosetrlimit(p, uap->which, &lim));
18453761Smckusick }
18553761Smckusick 
18654935Storek struct getrlimit_args {
18754935Storek 	u_int	which;
18854935Storek 	struct	orlimit *rlp;
18954935Storek };
19053761Smckusick /* ARGSUSED */
19160105Smckusick ogetrlimit(p, uap, retval)
19253761Smckusick 	struct proc *p;
19354935Storek 	register struct getrlimit_args *uap;
19453761Smckusick 	int *retval;
19553761Smckusick {
19653761Smckusick 	struct orlimit olim;
19753761Smckusick 
19853761Smckusick 	if (uap->which >= RLIM_NLIMITS)
19953761Smckusick 		return (EINVAL);
20053761Smckusick 	olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
20153761Smckusick 	if (olim.rlim_cur == -1)
20253761Smckusick 		olim.rlim_cur = 0x7fffffff;
20353761Smckusick 	olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
20453761Smckusick 	if (olim.rlim_max == -1)
20553761Smckusick 		olim.rlim_max = 0x7fffffff;
20653761Smckusick 	return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
20753761Smckusick }
20854345Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
20953761Smckusick 
21054935Storek struct __setrlimit_args {
21154935Storek 	u_int	which;
21254935Storek 	struct	rlimit *lim;
21354935Storek };
21453761Smckusick /* ARGSUSED */
21560411Smckusick setrlimit(p, uap, retval)
21653761Smckusick 	struct proc *p;
21754935Storek 	register struct __setrlimit_args *uap;
21843365Smckusick 	int *retval;
21943365Smckusick {
2208031Sroot 	struct rlimit alim;
22153761Smckusick 	int error;
22253761Smckusick 
22353761Smckusick 	if (error =
22453761Smckusick 	    copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit)))
22553761Smckusick 		return (error);
22653761Smckusick 	return (dosetrlimit(p, uap->which, &alim));
22753761Smckusick }
22853761Smckusick 
22953761Smckusick dosetrlimit(p, which, limp)
23053761Smckusick 	struct proc *p;
23153761Smckusick 	u_int which;
23253761Smckusick 	struct rlimit *limp;
23353761Smckusick {
2348031Sroot 	register struct rlimit *alimp;
23525257Skarels 	extern unsigned maxdmap;
23643365Smckusick 	int error;
2378031Sroot 
23853761Smckusick 	if (which >= RLIM_NLIMITS)
23944405Skarels 		return (EINVAL);
24053761Smckusick 	alimp = &p->p_rlimit[which];
24153761Smckusick 	if (limp->rlim_cur > alimp->rlim_max ||
24253761Smckusick 	    limp->rlim_max > alimp->rlim_max)
24347541Skarels 		if (error = suser(p->p_ucred, &p->p_acflag))
24444405Skarels 			return (error);
24553761Smckusick 	if (limp->rlim_cur > limp->rlim_max)
24653761Smckusick 		limp->rlim_cur = limp->rlim_max;
24747541Skarels 	if (p->p_limit->p_refcnt > 1 &&
24847541Skarels 	    (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
24947541Skarels 		p->p_limit->p_refcnt--;
25047541Skarels 		p->p_limit = limcopy(p->p_limit);
25153761Smckusick 		alimp = &p->p_rlimit[which];
25247541Skarels 	}
25347541Skarels 
25453761Smckusick 	switch (which) {
2558031Sroot 
2568031Sroot 	case RLIMIT_DATA:
25753761Smckusick 		if (limp->rlim_cur > maxdmap)
25853761Smckusick 			limp->rlim_cur = maxdmap;
25953761Smckusick 		if (limp->rlim_max > maxdmap)
26053761Smckusick 			limp->rlim_max = maxdmap;
2618031Sroot 		break;
2628031Sroot 
2638031Sroot 	case RLIMIT_STACK:
26453761Smckusick 		if (limp->rlim_cur > maxdmap)
26553761Smckusick 			limp->rlim_cur = maxdmap;
26653761Smckusick 		if (limp->rlim_max > maxdmap)
26753761Smckusick 			limp->rlim_max = maxdmap;
26849282Shibler 		/*
26949282Shibler 		 * Stack is allocated to the max at exec time with only
27049282Shibler 		 * "rlim_cur" bytes accessible.  If stack limit is going
27149282Shibler 		 * up make more accessible, if going down make inaccessible.
27249282Shibler 		 */
27353761Smckusick 		if (limp->rlim_cur != alimp->rlim_cur) {
27449282Shibler 			vm_offset_t addr;
27549282Shibler 			vm_size_t size;
27649282Shibler 			vm_prot_t prot;
27749282Shibler 
27853761Smckusick 			if (limp->rlim_cur > alimp->rlim_cur) {
27949282Shibler 				prot = VM_PROT_ALL;
28053761Smckusick 				size = limp->rlim_cur - alimp->rlim_cur;
28153761Smckusick 				addr = USRSTACK - limp->rlim_cur;
28249282Shibler 			} else {
28349282Shibler 				prot = VM_PROT_NONE;
28453761Smckusick 				size = alimp->rlim_cur - limp->rlim_cur;
28549282Shibler 				addr = USRSTACK - alimp->rlim_cur;
28649282Shibler 			}
28749282Shibler 			addr = trunc_page(addr);
28849282Shibler 			size = round_page(size);
28949282Shibler 			(void) vm_map_protect(&p->p_vmspace->vm_map,
29049282Shibler 					      addr, addr+size, prot, FALSE);
29149282Shibler 		}
2928031Sroot 		break;
29358775Smckusick 
29458775Smckusick 	case RLIMIT_NOFILE:
29558775Smckusick 		if (limp->rlim_cur > maxfiles)
29658775Smckusick 			limp->rlim_cur = maxfiles;
29758775Smckusick 		if (limp->rlim_max > maxfiles)
29858775Smckusick 			limp->rlim_max = maxfiles;
29958775Smckusick 		break;
30059614Smckusick 
30159614Smckusick 	case RLIMIT_NPROC:
30259614Smckusick 		if (limp->rlim_cur > maxproc)
30359614Smckusick 			limp->rlim_cur = maxproc;
30459614Smckusick 		if (limp->rlim_max > maxproc)
30559614Smckusick 			limp->rlim_max = maxproc;
30659614Smckusick 		break;
3078031Sroot 	}
30853761Smckusick 	*alimp = *limp;
30944405Skarels 	return (0);
3108031Sroot }
3118031Sroot 
31254935Storek struct __getrlimit_args {
31354935Storek 	u_int	which;
31454935Storek 	struct	rlimit *rlp;
31554935Storek };
31643365Smckusick /* ARGSUSED */
31760411Smckusick getrlimit(p, uap, retval)
31843365Smckusick 	struct proc *p;
31954935Storek 	register struct __getrlimit_args *uap;
32043365Smckusick 	int *retval;
32143365Smckusick {
3228031Sroot 
32343365Smckusick 	if (uap->which >= RLIM_NLIMITS)
32444405Skarels 		return (EINVAL);
32547541Skarels 	return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
32643365Smckusick 	    sizeof (struct rlimit)));
3278031Sroot }
3288031Sroot 
32954783Storek /*
33054783Storek  * Transform the running time and tick information in proc p into user,
33154783Storek  * system, and interrupt time usage.
33254783Storek  */
33354783Storek calcru(p, up, sp, ip)
33454783Storek 	register struct proc *p;
33554783Storek 	register struct timeval *up;
33654783Storek 	register struct timeval *sp;
33754783Storek 	register struct timeval *ip;
33854783Storek {
33954815Storek 	register u_quad_t u, st, ut, it, tot;
34054815Storek 	register u_long sec, usec;
34154815Storek 	register int s;
34254815Storek 	struct timeval tv;
34354783Storek 
34454783Storek 	s = splstatclock();
34554783Storek 	st = p->p_sticks;
34654783Storek 	ut = p->p_uticks;
34754783Storek 	it = p->p_iticks;
34854783Storek 	splx(s);
34954783Storek 
35054783Storek 	tot = st + ut + it;
35154783Storek 	if (tot == 0) {
35254783Storek 		up->tv_sec = up->tv_usec = 0;
35354783Storek 		sp->tv_sec = sp->tv_usec = 0;
35454783Storek 		if (ip != NULL)
35554783Storek 			ip->tv_sec = ip->tv_usec = 0;
35654783Storek 		return;
35754783Storek 	}
35854815Storek 
35954815Storek 	sec = p->p_rtime.tv_sec;
36054815Storek 	usec = p->p_rtime.tv_usec;
36154815Storek 	if (p == curproc) {
36254815Storek 		/*
36354815Storek 		 * Adjust for the current time slice.  This is actually fairly
36454815Storek 		 * important since the error here is on the order of a time
36554815Storek 		 * quantum, which is much greater than the sampling error.
36654815Storek 		 */
36754815Storek 		microtime(&tv);
36854815Storek 		sec += tv.tv_sec - runtime.tv_sec;
36954815Storek 		usec += tv.tv_usec - runtime.tv_usec;
37054815Storek 	}
37154815Storek 	u = sec * 1000000 + usec;
37254815Storek 	st = (u * st) / tot;
37354783Storek 	sp->tv_sec = st / 1000000;
37454783Storek 	sp->tv_usec = st % 1000000;
37554815Storek 	ut = (u * ut) / tot;
37654783Storek 	up->tv_sec = ut / 1000000;
37754783Storek 	up->tv_usec = ut % 1000000;
37854783Storek 	if (ip != NULL) {
37954815Storek 		it = (u * it) / tot;
38054783Storek 		ip->tv_sec = it / 1000000;
38154783Storek 		ip->tv_usec = it % 1000000;
38254783Storek 	}
38354783Storek }
38454783Storek 
38554935Storek struct getrusage_args {
38654935Storek 	int	who;
38754935Storek 	struct	rusage *rusage;
38854935Storek };
38943365Smckusick /* ARGSUSED */
39043365Smckusick getrusage(p, uap, retval)
39143365Smckusick 	register struct proc *p;
39254935Storek 	register struct getrusage_args *uap;
39343365Smckusick 	int *retval;
39443365Smckusick {
3958031Sroot 	register struct rusage *rup;
3968031Sroot 
3978031Sroot 	switch (uap->who) {
3988031Sroot 
39954815Storek 	case RUSAGE_SELF:
40047541Skarels 		rup = &p->p_stats->p_ru;
40154815Storek 		calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
4028031Sroot 		break;
4038031Sroot 
4048031Sroot 	case RUSAGE_CHILDREN:
40547541Skarels 		rup = &p->p_stats->p_cru;
4068031Sroot 		break;
4078031Sroot 
4088031Sroot 	default:
40944405Skarels 		return (EINVAL);
4108031Sroot 	}
41144405Skarels 	return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
41243365Smckusick 	    sizeof (struct rusage)));
4138031Sroot }
4148031Sroot 
4158031Sroot ruadd(ru, ru2)
4168031Sroot 	register struct rusage *ru, *ru2;
4178031Sroot {
4188666Sroot 	register long *ip, *ip2;
4198031Sroot 	register int i;
4208031Sroot 
4218031Sroot 	timevaladd(&ru->ru_utime, &ru2->ru_utime);
4228031Sroot 	timevaladd(&ru->ru_stime, &ru2->ru_stime);
4238031Sroot 	if (ru->ru_maxrss < ru2->ru_maxrss)
4248031Sroot 		ru->ru_maxrss = ru2->ru_maxrss;
4258031Sroot 	ip = &ru->ru_first; ip2 = &ru2->ru_first;
42653644Sbostic 	for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
4278031Sroot 		*ip++ += *ip2++;
4288031Sroot }
42947541Skarels 
43047541Skarels /*
43147541Skarels  * Make a copy of the plimit structure.
43247541Skarels  * We share these structures copy-on-write after fork,
43347541Skarels  * and copy when a limit is changed.
43447541Skarels  */
43547541Skarels struct plimit *
43647541Skarels limcopy(lim)
43747541Skarels 	struct plimit *lim;
43847541Skarels {
43947541Skarels 	register struct plimit *copy;
44047541Skarels 
44147541Skarels 	MALLOC(copy, struct plimit *, sizeof(struct plimit),
44247541Skarels 	    M_SUBPROC, M_WAITOK);
44347541Skarels 	bcopy(lim->pl_rlimit, copy->pl_rlimit,
44447541Skarels 	    sizeof(struct rlimit) * RLIM_NLIMITS);
44547541Skarels 	copy->p_lflags = 0;
44647541Skarels 	copy->p_refcnt = 1;
44747541Skarels 	return (copy);
44847541Skarels }
449