xref: /csrg-svn/sys/kern/kern_resource.c (revision 65081)
149594Sbostic /*-
263176Sbostic  * Copyright (c) 1982, 1986, 1991, 1993
363176Sbostic  *	The Regents of the University of California.  All rights reserved.
423373Smckusick  *
549594Sbostic  * %sccs.include.redist.c%
649594Sbostic  *
7*65081Smckusick  *	@(#)kern_resource.c	8.4 (Berkeley) 12/10/93
823373Smckusick  */
97Sbill 
1056517Sbostic #include <sys/param.h>
1156517Sbostic #include <sys/kernel.h>
1258775Smckusick #include <sys/file.h>
1356517Sbostic #include <sys/resourcevar.h>
1456517Sbostic #include <sys/malloc.h>
1556517Sbostic #include <sys/proc.h>
167Sbill 
1756517Sbostic #include <vm/vm.h>
1849282Shibler 
198176Sroot /*
208176Sroot  * Resource controls and accounting.
218176Sroot  */
228176Sroot 
2354935Storek struct getpriority_args {
2454935Storek 	int	which;
2554935Storek 	int	who;
2654935Storek };
2743365Smckusick getpriority(curp, uap, retval)
2843365Smckusick 	struct proc *curp;
2954935Storek 	register struct getpriority_args *uap;
3043365Smckusick 	int *retval;
3143365Smckusick {
328031Sroot 	register struct proc *p;
3335810Smarc 	register int low = PRIO_MAX + 1;
348031Sroot 
358031Sroot 	switch (uap->which) {
368031Sroot 
378031Sroot 	case PRIO_PROCESS:
388031Sroot 		if (uap->who == 0)
3943365Smckusick 			p = curp;
408031Sroot 		else
418031Sroot 			p = pfind(uap->who);
428031Sroot 		if (p == 0)
4328149Skarels 			break;
4417400Skarels 		low = p->p_nice;
458031Sroot 		break;
468031Sroot 
4735810Smarc 	case PRIO_PGRP: {
4835810Smarc 		register struct pgrp *pg;
4935810Smarc 
508031Sroot 		if (uap->who == 0)
5143365Smckusick 			pg = curp->p_pgrp;
5235810Smarc 		else if ((pg = pgfind(uap->who)) == NULL)
5335810Smarc 			break;
5435810Smarc 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
5535810Smarc 			if (p->p_nice < low)
5617400Skarels 				low = p->p_nice;
578176Sroot 		}
588031Sroot 		break;
5935810Smarc 	}
608031Sroot 
618176Sroot 	case PRIO_USER:
628176Sroot 		if (uap->who == 0)
6347541Skarels 			uap->who = curp->p_ucred->cr_uid;
6464577Sbostic 		for (p = (struct proc *)allproc; p != NULL; p = p->p_next) {
6547541Skarels 			if (p->p_ucred->cr_uid == uap->who &&
6617400Skarels 			    p->p_nice < low)
6717400Skarels 				low = p->p_nice;
688176Sroot 		}
698176Sroot 		break;
708176Sroot 
718031Sroot 	default:
7244405Skarels 		return (EINVAL);
738031Sroot 	}
7443365Smckusick 	if (low == PRIO_MAX + 1)
7544405Skarels 		return (ESRCH);
7643365Smckusick 	*retval = low;
7744405Skarels 	return (0);
788031Sroot }
798031Sroot 
8054935Storek struct setpriority_args {
8154935Storek 	int	which;
8254935Storek 	int	who;
8354935Storek 	int	prio;
8454935Storek };
8543365Smckusick /* ARGSUSED */
8643365Smckusick setpriority(curp, uap, retval)
8743365Smckusick 	struct proc *curp;
8854935Storek 	register struct setpriority_args *uap;
8943365Smckusick 	int *retval;
9043365Smckusick {
918031Sroot 	register struct proc *p;
9243365Smckusick 	int found = 0, error = 0;
938031Sroot 
948031Sroot 	switch (uap->which) {
958031Sroot 
968031Sroot 	case PRIO_PROCESS:
978176Sroot 		if (uap->who == 0)
9843365Smckusick 			p = curp;
998176Sroot 		else
1008176Sroot 			p = pfind(uap->who);
1018031Sroot 		if (p == 0)
10228149Skarels 			break;
10343365Smckusick 		error = donice(curp, p, uap->prio);
10417400Skarels 		found++;
1058031Sroot 		break;
1068031Sroot 
10735810Smarc 	case PRIO_PGRP: {
10835810Smarc 		register struct pgrp *pg;
10935810Smarc 
1108176Sroot 		if (uap->who == 0)
11143365Smckusick 			pg = curp->p_pgrp;
11235810Smarc 		else if ((pg = pgfind(uap->who)) == NULL)
11335810Smarc 			break;
11435810Smarc 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
11543365Smckusick 			error = donice(curp, p, uap->prio);
11635810Smarc 			found++;
11735810Smarc 		}
1188031Sroot 		break;
11935810Smarc 	}
1208031Sroot 
1218176Sroot 	case PRIO_USER:
1228176Sroot 		if (uap->who == 0)
12347541Skarels 			uap->who = curp->p_ucred->cr_uid;
12464577Sbostic 		for (p = (struct proc *)allproc; p != NULL; p = p->p_next)
12547541Skarels 			if (p->p_ucred->cr_uid == uap->who) {
12643365Smckusick 				error = donice(curp, p, uap->prio);
12717400Skarels 				found++;
12817400Skarels 			}
1298176Sroot 		break;
1308176Sroot 
1318031Sroot 	default:
13244405Skarels 		return (EINVAL);
1338031Sroot 	}
13417400Skarels 	if (found == 0)
13544405Skarels 		return (ESRCH);
136*65081Smckusick 	return (error);
1378031Sroot }
1388031Sroot 
13943365Smckusick donice(curp, chgp, n)
14043365Smckusick 	register struct proc *curp, *chgp;
1418031Sroot 	register int n;
1428031Sroot {
14347541Skarels 	register struct pcred *pcred = curp->p_cred;
1448031Sroot 
14547541Skarels 	if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
14647541Skarels 	    pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
14747541Skarels 	    pcred->p_ruid != chgp->p_ucred->cr_uid)
14843365Smckusick 		return (EPERM);
14917400Skarels 	if (n > PRIO_MAX)
15017400Skarels 		n = PRIO_MAX;
15117400Skarels 	if (n < PRIO_MIN)
15217400Skarels 		n = PRIO_MIN;
15347541Skarels 	if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
15443365Smckusick 		return (EACCES);
15543365Smckusick 	chgp->p_nice = n;
15664407Sbostic 	(void)resetpriority(chgp);
15743365Smckusick 	return (0);
1588031Sroot }
1598031Sroot 
16054345Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
16154935Storek struct setrlimit_args {
16254935Storek 	u_int	which;
16354935Storek 	struct	orlimit *lim;
16454935Storek };
16543365Smckusick /* ARGSUSED */
16660105Smckusick osetrlimit(p, uap, retval)
16743365Smckusick 	struct proc *p;
16854935Storek 	register struct setrlimit_args *uap;
16953761Smckusick 	int *retval;
17053761Smckusick {
17153761Smckusick 	struct orlimit olim;
17253761Smckusick 	struct rlimit lim;
17353761Smckusick 	int error;
17453761Smckusick 
17553761Smckusick 	if (error =
17653761Smckusick 	    copyin((caddr_t)uap->lim, (caddr_t)&olim, sizeof (struct orlimit)))
17753761Smckusick 		return (error);
17853761Smckusick 	lim.rlim_cur = olim.rlim_cur;
17953761Smckusick 	lim.rlim_max = olim.rlim_max;
18053761Smckusick 	return (dosetrlimit(p, uap->which, &lim));
18153761Smckusick }
18253761Smckusick 
18354935Storek struct getrlimit_args {
18454935Storek 	u_int	which;
18554935Storek 	struct	orlimit *rlp;
18654935Storek };
18753761Smckusick /* ARGSUSED */
18860105Smckusick ogetrlimit(p, uap, retval)
18953761Smckusick 	struct proc *p;
19054935Storek 	register struct getrlimit_args *uap;
19153761Smckusick 	int *retval;
19253761Smckusick {
19353761Smckusick 	struct orlimit olim;
19453761Smckusick 
19553761Smckusick 	if (uap->which >= RLIM_NLIMITS)
19653761Smckusick 		return (EINVAL);
19753761Smckusick 	olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
19853761Smckusick 	if (olim.rlim_cur == -1)
19953761Smckusick 		olim.rlim_cur = 0x7fffffff;
20053761Smckusick 	olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
20153761Smckusick 	if (olim.rlim_max == -1)
20253761Smckusick 		olim.rlim_max = 0x7fffffff;
20353761Smckusick 	return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
20453761Smckusick }
20554345Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
20653761Smckusick 
20754935Storek struct __setrlimit_args {
20854935Storek 	u_int	which;
20954935Storek 	struct	rlimit *lim;
21054935Storek };
21153761Smckusick /* ARGSUSED */
21260411Smckusick setrlimit(p, uap, retval)
21353761Smckusick 	struct proc *p;
21454935Storek 	register struct __setrlimit_args *uap;
21543365Smckusick 	int *retval;
21643365Smckusick {
2178031Sroot 	struct rlimit alim;
21853761Smckusick 	int error;
21953761Smckusick 
22053761Smckusick 	if (error =
22153761Smckusick 	    copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit)))
22253761Smckusick 		return (error);
22353761Smckusick 	return (dosetrlimit(p, uap->which, &alim));
22453761Smckusick }
22553761Smckusick 
22653761Smckusick dosetrlimit(p, which, limp)
22753761Smckusick 	struct proc *p;
22853761Smckusick 	u_int which;
22953761Smckusick 	struct rlimit *limp;
23053761Smckusick {
2318031Sroot 	register struct rlimit *alimp;
23225257Skarels 	extern unsigned maxdmap;
23343365Smckusick 	int error;
2348031Sroot 
23553761Smckusick 	if (which >= RLIM_NLIMITS)
23644405Skarels 		return (EINVAL);
23753761Smckusick 	alimp = &p->p_rlimit[which];
23853761Smckusick 	if (limp->rlim_cur > alimp->rlim_max ||
23953761Smckusick 	    limp->rlim_max > alimp->rlim_max)
24047541Skarels 		if (error = suser(p->p_ucred, &p->p_acflag))
24144405Skarels 			return (error);
24253761Smckusick 	if (limp->rlim_cur > limp->rlim_max)
24353761Smckusick 		limp->rlim_cur = limp->rlim_max;
24447541Skarels 	if (p->p_limit->p_refcnt > 1 &&
24547541Skarels 	    (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
24647541Skarels 		p->p_limit->p_refcnt--;
24747541Skarels 		p->p_limit = limcopy(p->p_limit);
24853761Smckusick 		alimp = &p->p_rlimit[which];
24947541Skarels 	}
25047541Skarels 
25153761Smckusick 	switch (which) {
2528031Sroot 
2538031Sroot 	case RLIMIT_DATA:
25453761Smckusick 		if (limp->rlim_cur > maxdmap)
25553761Smckusick 			limp->rlim_cur = maxdmap;
25653761Smckusick 		if (limp->rlim_max > maxdmap)
25753761Smckusick 			limp->rlim_max = maxdmap;
2588031Sroot 		break;
2598031Sroot 
2608031Sroot 	case RLIMIT_STACK:
26153761Smckusick 		if (limp->rlim_cur > maxdmap)
26253761Smckusick 			limp->rlim_cur = maxdmap;
26353761Smckusick 		if (limp->rlim_max > maxdmap)
26453761Smckusick 			limp->rlim_max = maxdmap;
26549282Shibler 		/*
26649282Shibler 		 * Stack is allocated to the max at exec time with only
26749282Shibler 		 * "rlim_cur" bytes accessible.  If stack limit is going
26849282Shibler 		 * up make more accessible, if going down make inaccessible.
26949282Shibler 		 */
27053761Smckusick 		if (limp->rlim_cur != alimp->rlim_cur) {
27149282Shibler 			vm_offset_t addr;
27249282Shibler 			vm_size_t size;
27349282Shibler 			vm_prot_t prot;
27449282Shibler 
27553761Smckusick 			if (limp->rlim_cur > alimp->rlim_cur) {
27649282Shibler 				prot = VM_PROT_ALL;
27753761Smckusick 				size = limp->rlim_cur - alimp->rlim_cur;
27853761Smckusick 				addr = USRSTACK - limp->rlim_cur;
27949282Shibler 			} else {
28049282Shibler 				prot = VM_PROT_NONE;
28153761Smckusick 				size = alimp->rlim_cur - limp->rlim_cur;
28249282Shibler 				addr = USRSTACK - alimp->rlim_cur;
28349282Shibler 			}
28449282Shibler 			addr = trunc_page(addr);
28549282Shibler 			size = round_page(size);
28649282Shibler 			(void) vm_map_protect(&p->p_vmspace->vm_map,
28749282Shibler 					      addr, addr+size, prot, FALSE);
28849282Shibler 		}
2898031Sroot 		break;
29058775Smckusick 
29158775Smckusick 	case RLIMIT_NOFILE:
29258775Smckusick 		if (limp->rlim_cur > maxfiles)
29358775Smckusick 			limp->rlim_cur = maxfiles;
29458775Smckusick 		if (limp->rlim_max > maxfiles)
29558775Smckusick 			limp->rlim_max = maxfiles;
29658775Smckusick 		break;
29759614Smckusick 
29859614Smckusick 	case RLIMIT_NPROC:
29959614Smckusick 		if (limp->rlim_cur > maxproc)
30059614Smckusick 			limp->rlim_cur = maxproc;
30159614Smckusick 		if (limp->rlim_max > maxproc)
30259614Smckusick 			limp->rlim_max = maxproc;
30359614Smckusick 		break;
3048031Sroot 	}
30553761Smckusick 	*alimp = *limp;
30644405Skarels 	return (0);
3078031Sroot }
3088031Sroot 
30954935Storek struct __getrlimit_args {
31054935Storek 	u_int	which;
31154935Storek 	struct	rlimit *rlp;
31254935Storek };
31343365Smckusick /* ARGSUSED */
31460411Smckusick getrlimit(p, uap, retval)
31543365Smckusick 	struct proc *p;
31654935Storek 	register struct __getrlimit_args *uap;
31743365Smckusick 	int *retval;
31843365Smckusick {
3198031Sroot 
32043365Smckusick 	if (uap->which >= RLIM_NLIMITS)
32144405Skarels 		return (EINVAL);
32247541Skarels 	return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
32343365Smckusick 	    sizeof (struct rlimit)));
3248031Sroot }
3258031Sroot 
32654783Storek /*
32754783Storek  * Transform the running time and tick information in proc p into user,
32854783Storek  * system, and interrupt time usage.
32954783Storek  */
33054783Storek calcru(p, up, sp, ip)
33154783Storek 	register struct proc *p;
33254783Storek 	register struct timeval *up;
33354783Storek 	register struct timeval *sp;
33454783Storek 	register struct timeval *ip;
33554783Storek {
33654815Storek 	register u_quad_t u, st, ut, it, tot;
33754815Storek 	register u_long sec, usec;
33854815Storek 	register int s;
33954815Storek 	struct timeval tv;
34054783Storek 
34154783Storek 	s = splstatclock();
34254783Storek 	st = p->p_sticks;
34354783Storek 	ut = p->p_uticks;
34454783Storek 	it = p->p_iticks;
34554783Storek 	splx(s);
34654783Storek 
34754783Storek 	tot = st + ut + it;
34854783Storek 	if (tot == 0) {
34954783Storek 		up->tv_sec = up->tv_usec = 0;
35054783Storek 		sp->tv_sec = sp->tv_usec = 0;
35154783Storek 		if (ip != NULL)
35254783Storek 			ip->tv_sec = ip->tv_usec = 0;
35354783Storek 		return;
35454783Storek 	}
35554815Storek 
35654815Storek 	sec = p->p_rtime.tv_sec;
35754815Storek 	usec = p->p_rtime.tv_usec;
35854815Storek 	if (p == curproc) {
35954815Storek 		/*
36054815Storek 		 * Adjust for the current time slice.  This is actually fairly
36154815Storek 		 * important since the error here is on the order of a time
36254815Storek 		 * quantum, which is much greater than the sampling error.
36354815Storek 		 */
36454815Storek 		microtime(&tv);
36554815Storek 		sec += tv.tv_sec - runtime.tv_sec;
36654815Storek 		usec += tv.tv_usec - runtime.tv_usec;
36754815Storek 	}
36854815Storek 	u = sec * 1000000 + usec;
36954815Storek 	st = (u * st) / tot;
37054783Storek 	sp->tv_sec = st / 1000000;
37154783Storek 	sp->tv_usec = st % 1000000;
37254815Storek 	ut = (u * ut) / tot;
37354783Storek 	up->tv_sec = ut / 1000000;
37454783Storek 	up->tv_usec = ut % 1000000;
37554783Storek 	if (ip != NULL) {
37654815Storek 		it = (u * it) / tot;
37754783Storek 		ip->tv_sec = it / 1000000;
37854783Storek 		ip->tv_usec = it % 1000000;
37954783Storek 	}
38054783Storek }
38154783Storek 
38254935Storek struct getrusage_args {
38354935Storek 	int	who;
38454935Storek 	struct	rusage *rusage;
38554935Storek };
38643365Smckusick /* ARGSUSED */
38743365Smckusick getrusage(p, uap, retval)
38843365Smckusick 	register struct proc *p;
38954935Storek 	register struct getrusage_args *uap;
39043365Smckusick 	int *retval;
39143365Smckusick {
3928031Sroot 	register struct rusage *rup;
3938031Sroot 
3948031Sroot 	switch (uap->who) {
3958031Sroot 
39654815Storek 	case RUSAGE_SELF:
39747541Skarels 		rup = &p->p_stats->p_ru;
39854815Storek 		calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
3998031Sroot 		break;
4008031Sroot 
4018031Sroot 	case RUSAGE_CHILDREN:
40247541Skarels 		rup = &p->p_stats->p_cru;
4038031Sroot 		break;
4048031Sroot 
4058031Sroot 	default:
40644405Skarels 		return (EINVAL);
4078031Sroot 	}
40844405Skarels 	return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
40943365Smckusick 	    sizeof (struct rusage)));
4108031Sroot }
4118031Sroot 
4128031Sroot ruadd(ru, ru2)
4138031Sroot 	register struct rusage *ru, *ru2;
4148031Sroot {
4158666Sroot 	register long *ip, *ip2;
4168031Sroot 	register int i;
4178031Sroot 
4188031Sroot 	timevaladd(&ru->ru_utime, &ru2->ru_utime);
4198031Sroot 	timevaladd(&ru->ru_stime, &ru2->ru_stime);
4208031Sroot 	if (ru->ru_maxrss < ru2->ru_maxrss)
4218031Sroot 		ru->ru_maxrss = ru2->ru_maxrss;
4228031Sroot 	ip = &ru->ru_first; ip2 = &ru2->ru_first;
42353644Sbostic 	for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
4248031Sroot 		*ip++ += *ip2++;
4258031Sroot }
42647541Skarels 
42747541Skarels /*
42847541Skarels  * Make a copy of the plimit structure.
42947541Skarels  * We share these structures copy-on-write after fork,
43047541Skarels  * and copy when a limit is changed.
43147541Skarels  */
43247541Skarels struct plimit *
43347541Skarels limcopy(lim)
43447541Skarels 	struct plimit *lim;
43547541Skarels {
43647541Skarels 	register struct plimit *copy;
43747541Skarels 
43847541Skarels 	MALLOC(copy, struct plimit *, sizeof(struct plimit),
43947541Skarels 	    M_SUBPROC, M_WAITOK);
44047541Skarels 	bcopy(lim->pl_rlimit, copy->pl_rlimit,
44147541Skarels 	    sizeof(struct rlimit) * RLIM_NLIMITS);
44247541Skarels 	copy->p_lflags = 0;
44347541Skarels 	copy->p_refcnt = 1;
44447541Skarels 	return (copy);
44547541Skarels }
446