Home | History | Annotate | Line # | Download | only in kern
kern_resource.c revision 1.20
      1 /*	$NetBSD: kern_resource.c,v 1.20 1994/06/29 06:32:39 cgd Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1982, 1986, 1991, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  * (c) UNIX System Laboratories, Inc.
      7  * All or some portions of this file are derived from material licensed
      8  * to the University of California by American Telephone and Telegraph
      9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     10  * the permission of UNIX System Laboratories, Inc.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. All advertising materials mentioning features or use of this software
     21  *    must display the following acknowledgement:
     22  *	This product includes software developed by the University of
     23  *	California, Berkeley and its contributors.
     24  * 4. Neither the name of the University nor the names of its contributors
     25  *    may be used to endorse or promote products derived from this software
     26  *    without specific prior written permission.
     27  *
     28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     38  * SUCH DAMAGE.
     39  *
     40  *	@(#)kern_resource.c	8.5 (Berkeley) 1/21/94
     41  */
     42 
     43 #include <sys/param.h>
     44 #include <sys/kernel.h>
     45 #include <sys/file.h>
     46 #include <sys/resourcevar.h>
     47 #include <sys/malloc.h>
     48 #include <sys/proc.h>
     49 
     50 #include <vm/vm.h>
     51 
     52 /*
     53  * Resource controls and accounting.
     54  */
     55 
     56 struct getpriority_args {
     57 	int	which;
     58 	int	who;
     59 };
     60 getpriority(curp, uap, retval)
     61 	struct proc *curp;
     62 	register struct getpriority_args *uap;
     63 	int *retval;
     64 {
     65 	register struct proc *p;
     66 	register int low = PRIO_MAX + 1;
     67 
     68 	switch (uap->which) {
     69 
     70 	case PRIO_PROCESS:
     71 		if (uap->who == 0)
     72 			p = curp;
     73 		else
     74 			p = pfind(uap->who);
     75 		if (p == 0)
     76 			break;
     77 		low = p->p_nice;
     78 		break;
     79 
     80 	case PRIO_PGRP: {
     81 		register struct pgrp *pg;
     82 
     83 		if (uap->who == 0)
     84 			pg = curp->p_pgrp;
     85 		else if ((pg = pgfind(uap->who)) == NULL)
     86 			break;
     87 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
     88 			if (p->p_nice < low)
     89 				low = p->p_nice;
     90 		}
     91 		break;
     92 	}
     93 
     94 	case PRIO_USER:
     95 		if (uap->who == 0)
     96 			uap->who = curp->p_ucred->cr_uid;
     97 		for (p = (struct proc *)allproc; p != NULL; p = p->p_next) {
     98 			if (p->p_ucred->cr_uid == uap->who &&
     99 			    p->p_nice < low)
    100 				low = p->p_nice;
    101 		}
    102 		break;
    103 
    104 	default:
    105 		return (EINVAL);
    106 	}
    107 	if (low == PRIO_MAX + 1)
    108 		return (ESRCH);
    109 	*retval = low;
    110 	return (0);
    111 }
    112 
    113 struct setpriority_args {
    114 	int	which;
    115 	int	who;
    116 	int	prio;
    117 };
    118 /* ARGSUSED */
    119 setpriority(curp, uap, retval)
    120 	struct proc *curp;
    121 	register struct setpriority_args *uap;
    122 	int *retval;
    123 {
    124 	register struct proc *p;
    125 	int found = 0, error = 0;
    126 
    127 	switch (uap->which) {
    128 
    129 	case PRIO_PROCESS:
    130 		if (uap->who == 0)
    131 			p = curp;
    132 		else
    133 			p = pfind(uap->who);
    134 		if (p == 0)
    135 			break;
    136 		error = donice(curp, p, uap->prio);
    137 		found++;
    138 		break;
    139 
    140 	case PRIO_PGRP: {
    141 		register struct pgrp *pg;
    142 
    143 		if (uap->who == 0)
    144 			pg = curp->p_pgrp;
    145 		else if ((pg = pgfind(uap->who)) == NULL)
    146 			break;
    147 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
    148 			error = donice(curp, p, uap->prio);
    149 			found++;
    150 		}
    151 		break;
    152 	}
    153 
    154 	case PRIO_USER:
    155 		if (uap->who == 0)
    156 			uap->who = curp->p_ucred->cr_uid;
    157 		for (p = (struct proc *)allproc; p != NULL; p = p->p_next)
    158 			if (p->p_ucred->cr_uid == uap->who) {
    159 				error = donice(curp, p, uap->prio);
    160 				found++;
    161 			}
    162 		break;
    163 
    164 	default:
    165 		return (EINVAL);
    166 	}
    167 	if (found == 0)
    168 		return (ESRCH);
    169 	return (error);
    170 }
    171 
    172 donice(curp, chgp, n)
    173 	register struct proc *curp, *chgp;
    174 	register int n;
    175 {
    176 	register struct pcred *pcred = curp->p_cred;
    177 
    178 	if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
    179 	    pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
    180 	    pcred->p_ruid != chgp->p_ucred->cr_uid)
    181 		return (EPERM);
    182 	if (n > PRIO_MAX)
    183 		n = PRIO_MAX;
    184 	if (n < PRIO_MIN)
    185 		n = PRIO_MIN;
    186 	if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
    187 		return (EACCES);
    188 	chgp->p_nice = n;
    189 	(void)resetpriority(chgp);
    190 	return (0);
    191 }
    192 
    193 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
    194 struct osetrlimit_args {
    195 	u_int	which;
    196 	struct	orlimit *lim;
    197 };
    198 /* ARGSUSED */
    199 osetrlimit(p, uap, retval)
    200 	struct proc *p;
    201 	struct osetrlimit_args *uap;
    202 	int *retval;
    203 {
    204 	struct orlimit olim;
    205 	struct rlimit lim;
    206 	int error;
    207 
    208 	if (error =
    209 	    copyin((caddr_t)uap->lim, (caddr_t)&olim, sizeof (struct orlimit)))
    210 		return (error);
    211 	lim.rlim_cur = olim.rlim_cur;
    212 	lim.rlim_max = olim.rlim_max;
    213 	return (dosetrlimit(p, uap->which, &lim));
    214 }
    215 
    216 struct ogetrlimit_args {
    217 	u_int	which;
    218 	struct	orlimit *rlp;
    219 };
    220 /* ARGSUSED */
    221 ogetrlimit(p, uap, retval)
    222 	struct proc *p;
    223 	register struct ogetrlimit_args *uap;
    224 	int *retval;
    225 {
    226 	struct orlimit olim;
    227 
    228 	if (uap->which >= RLIM_NLIMITS)
    229 		return (EINVAL);
    230 	olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
    231 	if (olim.rlim_cur == -1)
    232 		olim.rlim_cur = 0x7fffffff;
    233 	olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
    234 	if (olim.rlim_max == -1)
    235 		olim.rlim_max = 0x7fffffff;
    236 	return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
    237 }
    238 #endif /* COMPAT_43 || COMPAT_SUNOS */
    239 
    240 struct setrlimit_args {
    241 	u_int	which;
    242 	struct	rlimit *lim;
    243 };
    244 /* ARGSUSED */
    245 setrlimit(p, uap, retval)
    246 	struct proc *p;
    247 	register struct setrlimit_args *uap;
    248 	int *retval;
    249 {
    250 	struct rlimit alim;
    251 	int error;
    252 
    253 	if (error =
    254 	    copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit)))
    255 		return (error);
    256 	return (dosetrlimit(p, uap->which, &alim));
    257 }
    258 
    259 int
    260 dosetrlimit(p, which, limp)
    261 	struct proc *p;
    262 	u_int which;
    263 	struct rlimit *limp;
    264 {
    265 	register struct rlimit *alimp;
    266 	extern unsigned maxdmap, maxsmap;
    267 	int error;
    268 
    269 	if (which >= RLIM_NLIMITS)
    270 		return (EINVAL);
    271 	alimp = &p->p_rlimit[which];
    272 	if (limp->rlim_cur > alimp->rlim_max ||
    273 	    limp->rlim_max > alimp->rlim_max)
    274 		if (error = suser(p->p_ucred, &p->p_acflag))
    275 			return (error);
    276 	if (limp->rlim_cur > limp->rlim_max)
    277 		limp->rlim_cur = limp->rlim_max;
    278 	if (p->p_limit->p_refcnt > 1 &&
    279 	    (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
    280 		p->p_limit->p_refcnt--;
    281 		p->p_limit = limcopy(p->p_limit);
    282 		alimp = &p->p_rlimit[which];
    283 	}
    284 
    285 	switch (which) {
    286 
    287 	case RLIMIT_DATA:
    288 		if (limp->rlim_cur > maxdmap)
    289 			limp->rlim_cur = maxdmap;
    290 		if (limp->rlim_max > maxdmap)
    291 			limp->rlim_max = maxdmap;
    292 		break;
    293 
    294 	case RLIMIT_STACK:
    295 		if (limp->rlim_cur > maxsmap)
    296 			limp->rlim_cur = maxsmap;
    297 		if (limp->rlim_max > maxsmap)
    298 			limp->rlim_max = maxsmap;
    299 		/*
    300 		 * Stack is allocated to the max at exec time with only
    301 		 * "rlim_cur" bytes accessible.  If stack limit is going
    302 		 * up make more accessible, if going down make inaccessible.
    303 		 */
    304 		if (limp->rlim_cur != alimp->rlim_cur) {
    305 			vm_offset_t addr;
    306 			vm_size_t size;
    307 			vm_prot_t prot;
    308 
    309 			if (limp->rlim_cur > alimp->rlim_cur) {
    310 				prot = VM_PROT_ALL;
    311 				size = limp->rlim_cur - alimp->rlim_cur;
    312 				addr = USRSTACK - limp->rlim_cur;
    313 			} else {
    314 				prot = VM_PROT_NONE;
    315 				size = alimp->rlim_cur - limp->rlim_cur;
    316 				addr = USRSTACK - alimp->rlim_cur;
    317 			}
    318 			addr = trunc_page(addr);
    319 			size = round_page(size);
    320 			(void) vm_map_protect(&p->p_vmspace->vm_map,
    321 					      addr, addr+size, prot, FALSE);
    322 		}
    323 		break;
    324 
    325 	case RLIMIT_NOFILE:
    326 		if (limp->rlim_cur > maxfiles)
    327 			limp->rlim_cur = maxfiles;
    328 		if (limp->rlim_max > maxfiles)
    329 			limp->rlim_max = maxfiles;
    330 		break;
    331 
    332 	case RLIMIT_NPROC:
    333 		if (limp->rlim_cur > maxproc)
    334 			limp->rlim_cur = maxproc;
    335 		if (limp->rlim_max > maxproc)
    336 			limp->rlim_max = maxproc;
    337 		break;
    338 	}
    339 	*alimp = *limp;
    340 	return (0);
    341 }
    342 
    343 struct getrlimit_args {
    344 	u_int	which;
    345 	struct	rlimit *rlp;
    346 };
    347 /* ARGSUSED */
    348 getrlimit(p, uap, retval)
    349 	struct proc *p;
    350 	register struct getrlimit_args *uap;
    351 	int *retval;
    352 {
    353 
    354 	if (uap->which >= RLIM_NLIMITS)
    355 		return (EINVAL);
    356 	return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
    357 	    sizeof (struct rlimit)));
    358 }
    359 
    360 /*
    361  * Transform the running time and tick information in proc p into user,
    362  * system, and interrupt time usage.
    363  */
    364 calcru(p, up, sp, ip)
    365 	register struct proc *p;
    366 	register struct timeval *up;
    367 	register struct timeval *sp;
    368 	register struct timeval *ip;
    369 {
    370 	register u_quad_t u, st, ut, it, tot;
    371 	register u_long sec, usec;
    372 	register int s;
    373 	struct timeval tv;
    374 
    375 	s = splstatclock();
    376 	st = p->p_sticks;
    377 	ut = p->p_uticks;
    378 	it = p->p_iticks;
    379 	splx(s);
    380 
    381 	tot = st + ut + it;
    382 	if (tot == 0) {
    383 		up->tv_sec = up->tv_usec = 0;
    384 		sp->tv_sec = sp->tv_usec = 0;
    385 		if (ip != NULL)
    386 			ip->tv_sec = ip->tv_usec = 0;
    387 		return;
    388 	}
    389 
    390 	sec = p->p_rtime.tv_sec;
    391 	usec = p->p_rtime.tv_usec;
    392 	if (p == curproc) {
    393 		/*
    394 		 * Adjust for the current time slice.  This is actually fairly
    395 		 * important since the error here is on the order of a time
    396 		 * quantum, which is much greater than the sampling error.
    397 		 */
    398 		microtime(&tv);
    399 		sec += tv.tv_sec - runtime.tv_sec;
    400 		usec += tv.tv_usec - runtime.tv_usec;
    401 	}
    402 	u = sec * 1000000 + usec;
    403 	st = (u * st) / tot;
    404 	sp->tv_sec = st / 1000000;
    405 	sp->tv_usec = st % 1000000;
    406 	ut = (u * ut) / tot;
    407 	up->tv_sec = ut / 1000000;
    408 	up->tv_usec = ut % 1000000;
    409 	if (ip != NULL) {
    410 		it = (u * it) / tot;
    411 		ip->tv_sec = it / 1000000;
    412 		ip->tv_usec = it % 1000000;
    413 	}
    414 }
    415 
    416 struct getrusage_args {
    417 	int	who;
    418 	struct	rusage *rusage;
    419 };
    420 /* ARGSUSED */
    421 getrusage(p, uap, retval)
    422 	register struct proc *p;
    423 	register struct getrusage_args *uap;
    424 	int *retval;
    425 {
    426 	register struct rusage *rup;
    427 
    428 	switch (uap->who) {
    429 
    430 	case RUSAGE_SELF:
    431 		rup = &p->p_stats->p_ru;
    432 		calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
    433 		break;
    434 
    435 	case RUSAGE_CHILDREN:
    436 		rup = &p->p_stats->p_cru;
    437 		break;
    438 
    439 	default:
    440 		return (EINVAL);
    441 	}
    442 	return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
    443 	    sizeof (struct rusage)));
    444 }
    445 
    446 ruadd(ru, ru2)
    447 	register struct rusage *ru, *ru2;
    448 {
    449 	register long *ip, *ip2;
    450 	register int i;
    451 
    452 	timevaladd(&ru->ru_utime, &ru2->ru_utime);
    453 	timevaladd(&ru->ru_stime, &ru2->ru_stime);
    454 	if (ru->ru_maxrss < ru2->ru_maxrss)
    455 		ru->ru_maxrss = ru2->ru_maxrss;
    456 	ip = &ru->ru_first; ip2 = &ru2->ru_first;
    457 	for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
    458 		*ip++ += *ip2++;
    459 }
    460 
    461 /*
    462  * Make a copy of the plimit structure.
    463  * We share these structures copy-on-write after fork,
    464  * and copy when a limit is changed.
    465  */
    466 struct plimit *
    467 limcopy(lim)
    468 	struct plimit *lim;
    469 {
    470 	register struct plimit *copy;
    471 
    472 	MALLOC(copy, struct plimit *, sizeof(struct plimit),
    473 	    M_SUBPROC, M_WAITOK);
    474 	bcopy(lim->pl_rlimit, copy->pl_rlimit,
    475 	    sizeof(struct rlimit) * RLIM_NLIMITS);
    476 	copy->p_lflags = 0;
    477 	copy->p_refcnt = 1;
    478 	return (copy);
    479 }
    480