xref: /freebsd/sys/kern/kern_resource.c (revision 817420dc8eac7df799c78f5309b75092b7f7cd40)
1 /*-
2  * Copyright (c) 1982, 1986, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)kern_resource.c	8.5 (Berkeley) 1/21/94
39  * $FreeBSD$
40  */
41 
42 #include "opt_compat.h"
43 #include "opt_rlimit.h"
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/sysproto.h>
48 #include <sys/file.h>
49 #include <sys/kernel.h>
50 #include <sys/resourcevar.h>
51 #include <sys/malloc.h>
52 #include <sys/proc.h>
53 #include <sys/time.h>
54 
55 #include <vm/vm.h>
56 #include <vm/vm_param.h>
57 #include <sys/lock.h>
58 #include <vm/pmap.h>
59 #include <vm/vm_map.h>
60 
61 static int donice __P((struct proc *curp, struct proc *chgp, int n));
62 /* dosetrlimit non-static:  Needed by SysVR4 emulator */
63 int dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
64 
65 static MALLOC_DEFINE(M_UIDINFO, "uidinfo", "uidinfo structures");
66 #define	UIHASH(uid)	(&uihashtbl[(uid) & uihash])
67 static LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
68 static u_long uihash;		/* size of hash table - 1 */
69 
70 static struct uidinfo	*uicreate __P((uid_t uid));
71 static struct uidinfo	*uilookup __P((uid_t uid));
72 
73 /*
74  * Resource controls and accounting.
75  */
76 
77 #ifndef _SYS_SYSPROTO_H_
78 struct getpriority_args {
79 	int	which;
80 	int	who;
81 };
82 #endif
83 int
84 getpriority(curp, uap)
85 	struct proc *curp;
86 	register struct getpriority_args *uap;
87 {
88 	register struct proc *p;
89 	register int low = PRIO_MAX + 1;
90 
91 	switch (uap->which) {
92 
93 	case PRIO_PROCESS:
94 		if (uap->who == 0)
95 			p = curp;
96 		else
97 			p = pfind(uap->who);
98 		if (p == 0)
99 			break;
100 		if (p_can(curp, p, P_CAN_SEE, NULL))
101 			break;
102 		low = p->p_nice;
103 		break;
104 
105 	case PRIO_PGRP: {
106 		register struct pgrp *pg;
107 
108 		if (uap->who == 0)
109 			pg = curp->p_pgrp;
110 		else if ((pg = pgfind(uap->who)) == NULL)
111 			break;
112 		LIST_FOREACH(p, &pg->pg_members, p_pglist) {
113 			if (!p_can(curp, p, P_CAN_SEE, NULL) && p->p_nice < low)
114 				low = p->p_nice;
115 		}
116 		break;
117 	}
118 
119 	case PRIO_USER:
120 		if (uap->who == 0)
121 			uap->who = curp->p_ucred->cr_uid;
122 		lockmgr(&allproc_lock, LK_SHARED, NULL, CURPROC);
123 		LIST_FOREACH(p, &allproc, p_list)
124 			if (!p_can(curp, p, P_CAN_SEE, NULL) &&
125 			    p->p_ucred->cr_uid == uap->who &&
126 			    p->p_nice < low)
127 				low = p->p_nice;
128 		lockmgr(&allproc_lock, LK_RELEASE, NULL, CURPROC);
129 		break;
130 
131 	default:
132 		return (EINVAL);
133 	}
134 	if (low == PRIO_MAX + 1)
135 		return (ESRCH);
136 	curp->p_retval[0] = low;
137 	return (0);
138 }
139 
140 #ifndef _SYS_SYSPROTO_H_
141 struct setpriority_args {
142 	int	which;
143 	int	who;
144 	int	prio;
145 };
146 #endif
147 /* ARGSUSED */
148 int
149 setpriority(curp, uap)
150 	struct proc *curp;
151 	register struct setpriority_args *uap;
152 {
153 	register struct proc *p;
154 	int found = 0, error = 0;
155 
156 	switch (uap->which) {
157 
158 	case PRIO_PROCESS:
159 		if (uap->who == 0)
160 			p = curp;
161 		else
162 			p = pfind(uap->who);
163 		if (p == 0)
164 			break;
165 		if (p_can(curp, p, P_CAN_SEE, NULL))
166 			break;
167 		error = donice(curp, p, uap->prio);
168 		found++;
169 		break;
170 
171 	case PRIO_PGRP: {
172 		register struct pgrp *pg;
173 
174 		if (uap->who == 0)
175 			pg = curp->p_pgrp;
176 		else if ((pg = pgfind(uap->who)) == NULL)
177 			break;
178 		LIST_FOREACH(p, &pg->pg_members, p_pglist) {
179 			if (!p_can(curp, p, P_CAN_SEE, NULL)) {
180 				error = donice(curp, p, uap->prio);
181 				found++;
182 			}
183 		}
184 		break;
185 	}
186 
187 	case PRIO_USER:
188 		if (uap->who == 0)
189 			uap->who = curp->p_ucred->cr_uid;
190 		lockmgr(&allproc_lock, LK_SHARED, NULL, CURPROC);
191 		LIST_FOREACH(p, &allproc, p_list)
192 			if (p->p_ucred->cr_uid == uap->who &&
193 			    !p_can(curp, p, P_CAN_SEE, NULL)) {
194 				error = donice(curp, p, uap->prio);
195 				found++;
196 			}
197 		lockmgr(&allproc_lock, LK_RELEASE, NULL, CURPROC);
198 		break;
199 
200 	default:
201 		return (EINVAL);
202 	}
203 	if (found == 0)
204 		return (ESRCH);
205 	return (error);
206 }
207 
208 static int
209 donice(curp, chgp, n)
210 	register struct proc *curp, *chgp;
211 	register int n;
212 {
213 	int	error;
214 
215 	if ((error = p_can(curp, chgp, P_CAN_SCHED, NULL)))
216 		return (error);
217 	if (n > PRIO_MAX)
218 		n = PRIO_MAX;
219 	if (n < PRIO_MIN)
220 		n = PRIO_MIN;
221 	if (n < chgp->p_nice && suser(curp))
222 		return (EACCES);
223 	chgp->p_nice = n;
224 	(void)resetpriority(chgp);
225 	return (0);
226 }
227 
228 /* rtprio system call */
229 #ifndef _SYS_SYSPROTO_H_
230 struct rtprio_args {
231 	int		function;
232 	pid_t		pid;
233 	struct rtprio	*rtp;
234 };
235 #endif
236 
237 /*
238  * Set realtime priority
239  */
240 
241 /* ARGSUSED */
242 int
243 rtprio(curp, uap)
244 	struct proc *curp;
245 	register struct rtprio_args *uap;
246 {
247 	register struct proc *p;
248 	struct rtprio rtp;
249 	int error;
250 
251 	error = copyin(uap->rtp, &rtp, sizeof(struct rtprio));
252 	if (error)
253 		return (error);
254 
255 	if (uap->pid == 0)
256 		p = curp;
257 	else
258 		p = pfind(uap->pid);
259 
260 	if (p == 0)
261 		return (ESRCH);
262 
263 	switch (uap->function) {
264 	case RTP_LOOKUP:
265 		return (copyout(&p->p_rtprio, uap->rtp, sizeof(struct rtprio)));
266 	case RTP_SET:
267 		if ((error = p_can(curp, p, P_CAN_SCHED, NULL)))
268 		        return (error);
269 		/* disallow setting rtprio in most cases if not superuser */
270 		if (suser(curp) != 0) {
271 			/* can't set someone else's */
272 			if (uap->pid)
273 				return (EPERM);
274 			/* can't set realtime priority */
275 /*
276  * Realtime priority has to be restricted for reasons which should be
277  * obvious. However, for idle priority, there is a potential for
278  * system deadlock if an idleprio process gains a lock on a resource
279  * that other processes need (and the idleprio process can't run
280  * due to a CPU-bound normal process). Fix me! XXX
281  */
282 #if 0
283  			if (RTP_PRIO_IS_REALTIME(rtp.type))
284 #endif
285 			if (rtp.type != RTP_PRIO_NORMAL)
286 				return (EPERM);
287 		}
288 		switch (rtp.type) {
289 #ifdef RTP_PRIO_FIFO
290 		case RTP_PRIO_FIFO:
291 #endif
292 		case RTP_PRIO_REALTIME:
293 		case RTP_PRIO_NORMAL:
294 		case RTP_PRIO_IDLE:
295 			if (rtp.prio > RTP_PRIO_MAX)
296 				return (EINVAL);
297 			p->p_rtprio = rtp;
298 			return (0);
299 		default:
300 			return (EINVAL);
301 		}
302 
303 	default:
304 		return (EINVAL);
305 	}
306 }
307 
308 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
309 #ifndef _SYS_SYSPROTO_H_
310 struct osetrlimit_args {
311 	u_int	which;
312 	struct	orlimit *rlp;
313 };
314 #endif
315 /* ARGSUSED */
316 int
317 osetrlimit(p, uap)
318 	struct proc *p;
319 	register struct osetrlimit_args *uap;
320 {
321 	struct orlimit olim;
322 	struct rlimit lim;
323 	int error;
324 
325 	if ((error =
326 	    copyin((caddr_t)uap->rlp, (caddr_t)&olim, sizeof(struct orlimit))))
327 		return (error);
328 	lim.rlim_cur = olim.rlim_cur;
329 	lim.rlim_max = olim.rlim_max;
330 	return (dosetrlimit(p, uap->which, &lim));
331 }
332 
333 #ifndef _SYS_SYSPROTO_H_
334 struct ogetrlimit_args {
335 	u_int	which;
336 	struct	orlimit *rlp;
337 };
338 #endif
339 /* ARGSUSED */
340 int
341 ogetrlimit(p, uap)
342 	struct proc *p;
343 	register struct ogetrlimit_args *uap;
344 {
345 	struct orlimit olim;
346 
347 	if (uap->which >= RLIM_NLIMITS)
348 		return (EINVAL);
349 	olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
350 	if (olim.rlim_cur == -1)
351 		olim.rlim_cur = 0x7fffffff;
352 	olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
353 	if (olim.rlim_max == -1)
354 		olim.rlim_max = 0x7fffffff;
355 	return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
356 }
357 #endif /* COMPAT_43 || COMPAT_SUNOS */
358 
359 #ifndef _SYS_SYSPROTO_H_
360 struct __setrlimit_args {
361 	u_int	which;
362 	struct	rlimit *rlp;
363 };
364 #endif
365 /* ARGSUSED */
366 int
367 setrlimit(p, uap)
368 	struct proc *p;
369 	register struct __setrlimit_args *uap;
370 {
371 	struct rlimit alim;
372 	int error;
373 
374 	if ((error =
375 	    copyin((caddr_t)uap->rlp, (caddr_t)&alim, sizeof (struct rlimit))))
376 		return (error);
377 	return (dosetrlimit(p, uap->which, &alim));
378 }
379 
380 int
381 dosetrlimit(p, which, limp)
382 	struct proc *p;
383 	u_int which;
384 	struct rlimit *limp;
385 {
386 	register struct rlimit *alimp;
387 	int error;
388 
389 	if (which >= RLIM_NLIMITS)
390 		return (EINVAL);
391 	alimp = &p->p_rlimit[which];
392 
393 	/*
394 	 * Preserve historical bugs by treating negative limits as unsigned.
395 	 */
396 	if (limp->rlim_cur < 0)
397 		limp->rlim_cur = RLIM_INFINITY;
398 	if (limp->rlim_max < 0)
399 		limp->rlim_max = RLIM_INFINITY;
400 
401 	if (limp->rlim_cur > alimp->rlim_max ||
402 	    limp->rlim_max > alimp->rlim_max)
403 		if ((error = suser_xxx(0, p, PRISON_ROOT)))
404 			return (error);
405 	if (limp->rlim_cur > limp->rlim_max)
406 		limp->rlim_cur = limp->rlim_max;
407 	if (p->p_limit->p_refcnt > 1 &&
408 	    (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
409 		p->p_limit->p_refcnt--;
410 		p->p_limit = limcopy(p->p_limit);
411 		alimp = &p->p_rlimit[which];
412 	}
413 
414 	switch (which) {
415 
416 	case RLIMIT_CPU:
417 		if (limp->rlim_cur > RLIM_INFINITY / (rlim_t)1000000)
418 			p->p_limit->p_cpulimit = RLIM_INFINITY;
419 		else
420 			p->p_limit->p_cpulimit =
421 			    (rlim_t)1000000 * limp->rlim_cur;
422 		break;
423 	case RLIMIT_DATA:
424 		if (limp->rlim_cur > MAXDSIZ)
425 			limp->rlim_cur = MAXDSIZ;
426 		if (limp->rlim_max > MAXDSIZ)
427 			limp->rlim_max = MAXDSIZ;
428 		break;
429 
430 	case RLIMIT_STACK:
431 		if (limp->rlim_cur > MAXSSIZ)
432 			limp->rlim_cur = MAXSSIZ;
433 		if (limp->rlim_max > MAXSSIZ)
434 			limp->rlim_max = MAXSSIZ;
435 		/*
436 		 * Stack is allocated to the max at exec time with only
437 		 * "rlim_cur" bytes accessible.  If stack limit is going
438 		 * up make more accessible, if going down make inaccessible.
439 		 */
440 		if (limp->rlim_cur != alimp->rlim_cur) {
441 			vm_offset_t addr;
442 			vm_size_t size;
443 			vm_prot_t prot;
444 
445 			if (limp->rlim_cur > alimp->rlim_cur) {
446 				prot = VM_PROT_ALL;
447 				size = limp->rlim_cur - alimp->rlim_cur;
448 				addr = USRSTACK - limp->rlim_cur;
449 			} else {
450 				prot = VM_PROT_NONE;
451 				size = alimp->rlim_cur - limp->rlim_cur;
452 				addr = USRSTACK - alimp->rlim_cur;
453 			}
454 			addr = trunc_page(addr);
455 			size = round_page(size);
456 			(void) vm_map_protect(&p->p_vmspace->vm_map,
457 					      addr, addr+size, prot, FALSE);
458 		}
459 		break;
460 
461 	case RLIMIT_NOFILE:
462 		if (limp->rlim_cur > maxfilesperproc)
463 			limp->rlim_cur = maxfilesperproc;
464 		if (limp->rlim_max > maxfilesperproc)
465 			limp->rlim_max = maxfilesperproc;
466 		break;
467 
468 	case RLIMIT_NPROC:
469 		if (limp->rlim_cur > maxprocperuid)
470 			limp->rlim_cur = maxprocperuid;
471 		if (limp->rlim_max > maxprocperuid)
472 			limp->rlim_max = maxprocperuid;
473 		break;
474 	}
475 	*alimp = *limp;
476 	return (0);
477 }
478 
479 #ifndef _SYS_SYSPROTO_H_
480 struct __getrlimit_args {
481 	u_int	which;
482 	struct	rlimit *rlp;
483 };
484 #endif
485 /* ARGSUSED */
486 int
487 getrlimit(p, uap)
488 	struct proc *p;
489 	register struct __getrlimit_args *uap;
490 {
491 
492 	if (uap->which >= RLIM_NLIMITS)
493 		return (EINVAL);
494 	return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
495 	    sizeof (struct rlimit)));
496 }
497 
498 /*
499  * Transform the running time and tick information in proc p into user,
500  * system, and interrupt time usage.
501  */
502 void
503 calcru(p, up, sp, ip)
504 	struct proc *p;
505 	struct timeval *up;
506 	struct timeval *sp;
507 	struct timeval *ip;
508 {
509 	/* {user, system, interrupt, total} {ticks, usec}; previous tu: */
510 	u_int64_t ut, uu, st, su, it, iu, tt, tu, ptu;
511 	int s;
512 	struct timeval tv;
513 
514 	/* XXX: why spl-protect ?  worst case is an off-by-one report */
515 	s = splstatclock();
516 	ut = p->p_uticks;
517 	st = p->p_sticks;
518 	it = p->p_iticks;
519 	splx(s);
520 
521 	tt = ut + st + it;
522 	if (tt == 0) {
523 		st = 1;
524 		tt = 1;
525 	}
526 
527 	tu = p->p_runtime;
528 	if (p == curproc) {
529 		/*
530 		 * Adjust for the current time slice.  This is actually fairly
531 		 * important since the error here is on the order of a time
532 		 * quantum, which is much greater than the sampling error.
533 		 */
534 		microuptime(&tv);
535 		if (timevalcmp(&tv, &switchtime, <))
536 			printf("microuptime() went backwards (%ld.%06ld -> %ld.%06ld)\n",
537 			    switchtime.tv_sec, switchtime.tv_usec,
538 			    tv.tv_sec, tv.tv_usec);
539 		else
540 			tu += (tv.tv_usec - switchtime.tv_usec) +
541 			    (tv.tv_sec - switchtime.tv_sec) * (int64_t)1000000;
542 	}
543 	ptu = p->p_uu + p->p_su + p->p_iu;
544 	if (tu < ptu || (int64_t)tu < 0) {
545 		/* XXX no %qd in kernel.  Truncate. */
546 		printf("calcru: negative time of %ld usec for pid %d (%s)\n",
547 		       (long)tu, p->p_pid, p->p_comm);
548 		tu = ptu;
549 	}
550 
551 	/* Subdivide tu. */
552 	uu = (tu * ut) / tt;
553 	su = (tu * st) / tt;
554 	iu = tu - uu - su;
555 
556 	/* Enforce monotonicity. */
557 	if (uu < p->p_uu || su < p->p_su || iu < p->p_iu) {
558 		if (uu < p->p_uu)
559 			uu = p->p_uu;
560 		else if (uu + p->p_su + p->p_iu > tu)
561 			uu = tu - p->p_su - p->p_iu;
562 		if (st == 0)
563 			su = p->p_su;
564 		else {
565 			su = ((tu - uu) * st) / (st + it);
566 			if (su < p->p_su)
567 				su = p->p_su;
568 			else if (uu + su + p->p_iu > tu)
569 				su = tu - uu - p->p_iu;
570 		}
571 		KASSERT(uu + su + p->p_iu <= tu,
572 		    ("calcru: monotonisation botch 1"));
573 		iu = tu - uu - su;
574 		KASSERT(iu >= p->p_iu,
575 		    ("calcru: monotonisation botch 2"));
576 	}
577 	p->p_uu = uu;
578 	p->p_su = su;
579 	p->p_iu = iu;
580 
581 	up->tv_sec = uu / 1000000;
582 	up->tv_usec = uu % 1000000;
583 	sp->tv_sec = su / 1000000;
584 	sp->tv_usec = su % 1000000;
585 	if (ip != NULL) {
586 		ip->tv_sec = iu / 1000000;
587 		ip->tv_usec = iu % 1000000;
588 	}
589 }
590 
591 #ifndef _SYS_SYSPROTO_H_
592 struct getrusage_args {
593 	int	who;
594 	struct	rusage *rusage;
595 };
596 #endif
597 /* ARGSUSED */
598 int
599 getrusage(p, uap)
600 	register struct proc *p;
601 	register struct getrusage_args *uap;
602 {
603 	register struct rusage *rup;
604 
605 	switch (uap->who) {
606 
607 	case RUSAGE_SELF:
608 		rup = &p->p_stats->p_ru;
609 		calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
610 		break;
611 
612 	case RUSAGE_CHILDREN:
613 		rup = &p->p_stats->p_cru;
614 		break;
615 
616 	default:
617 		return (EINVAL);
618 	}
619 	return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
620 	    sizeof (struct rusage)));
621 }
622 
623 void
624 ruadd(ru, ru2)
625 	register struct rusage *ru, *ru2;
626 {
627 	register long *ip, *ip2;
628 	register int i;
629 
630 	timevaladd(&ru->ru_utime, &ru2->ru_utime);
631 	timevaladd(&ru->ru_stime, &ru2->ru_stime);
632 	if (ru->ru_maxrss < ru2->ru_maxrss)
633 		ru->ru_maxrss = ru2->ru_maxrss;
634 	ip = &ru->ru_first; ip2 = &ru2->ru_first;
635 	for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
636 		*ip++ += *ip2++;
637 }
638 
639 /*
640  * Make a copy of the plimit structure.
641  * We share these structures copy-on-write after fork,
642  * and copy when a limit is changed.
643  */
644 struct plimit *
645 limcopy(lim)
646 	struct plimit *lim;
647 {
648 	register struct plimit *copy;
649 
650 	MALLOC(copy, struct plimit *, sizeof(struct plimit),
651 	    M_SUBPROC, M_WAITOK);
652 	bcopy(lim->pl_rlimit, copy->pl_rlimit, sizeof(struct plimit));
653 	copy->p_lflags = 0;
654 	copy->p_refcnt = 1;
655 	return (copy);
656 }
657 
658 /*
659  * Find the uidinfo structure for a uid.  This structure is used to
660  * track the total resource consumption (process count, socket buffer
661  * size, etc.) for the uid and impose limits.
662  */
663 void
664 uihashinit()
665 {
666 	uihashtbl = hashinit(maxproc / 16, M_UIDINFO, &uihash);
667 }
668 
669 static struct uidinfo *
670 uilookup(uid)
671 	uid_t uid;
672 {
673 	struct	uihashhead *uipp;
674 	struct	uidinfo *uip;
675 
676 	uipp = UIHASH(uid);
677 	LIST_FOREACH(uip, uipp, ui_hash)
678 		if (uip->ui_uid == uid)
679 			break;
680 
681 	return (uip);
682 }
683 
684 static struct uidinfo *
685 uicreate(uid)
686 	uid_t uid;
687 {
688 	struct	uidinfo *uip, *norace;
689 
690 	MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_NOWAIT);
691 	if (uip == NULL) {
692 		MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_WAITOK);
693 		/*
694 		 * if we M_WAITOK we must look afterwards or risk
695 		 * redundant entries
696 		 */
697 		norace = uilookup(uid);
698 		if (norace != NULL) {
699 			FREE(uip, M_UIDINFO);
700 			return (norace);
701 		}
702 	}
703 	LIST_INSERT_HEAD(UIHASH(uid), uip, ui_hash);
704 	uip->ui_uid = uid;
705 	uip->ui_proccnt = 0;
706 	uip->ui_sbsize = 0;
707 	uip->ui_ref = 0;
708 	return (uip);
709 }
710 
711 struct uidinfo *
712 uifind(uid)
713 	uid_t uid;
714 {
715 	struct	uidinfo *uip;
716 
717 	uip = uilookup(uid);
718 	if (uip == NULL)
719 		uip = uicreate(uid);
720 	uip->ui_ref++;
721 	return (uip);
722 }
723 
724 int
725 uifree(uip)
726 	struct	uidinfo *uip;
727 {
728 
729 	if (--uip->ui_ref == 0) {
730 		if (uip->ui_sbsize != 0)
731 			/* XXX no %qd in kernel.  Truncate. */
732 			printf("freeing uidinfo: uid = %d, sbsize = %ld\n",
733 			    uip->ui_uid, (long)uip->ui_sbsize);
734 		if (uip->ui_proccnt != 0)
735 			printf("freeing uidinfo: uid = %d, proccnt = %ld\n",
736 			    uip->ui_uid, uip->ui_proccnt);
737 		LIST_REMOVE(uip, ui_hash);
738 		FREE(uip, M_UIDINFO);
739 		return (1);
740 	}
741 	return (0);
742 }
743 
744 /*
745  * Change the count associated with number of processes
746  * a given user is using.  When 'max' is 0, don't enforce a limit
747  */
748 int
749 chgproccnt(uip, diff, max)
750 	struct	uidinfo	*uip;
751 	int	diff;
752 	int	max;
753 {
754 	/* don't allow them to exceed max, but allow subtraction */
755 	if (diff > 0 && uip->ui_proccnt + diff > max && max != 0)
756 		return (0);
757 	uip->ui_proccnt += diff;
758 	if (uip->ui_proccnt < 0)
759 		printf("negative proccnt for uid = %d\n", uip->ui_uid);
760 	return (1);
761 }
762 
763 /*
764  * Change the total socket buffer size a user has used.
765  */
766 int
767 chgsbsize(uip, hiwat, to, max)
768 	struct	uidinfo	*uip;
769 	u_long *hiwat;
770 	u_long	to;
771 	rlim_t	max;
772 {
773 	rlim_t new;
774 	int s;
775 
776 	s = splnet();
777 	new = uip->ui_sbsize + to - *hiwat;
778 	/* don't allow them to exceed max, but allow subtraction */
779 	if (to > *hiwat && new > max) {
780 		splx(s);
781 		return (0);
782 	}
783 	uip->ui_sbsize = new;
784 	*hiwat = to;
785 	if (uip->ui_sbsize < 0)
786 		printf("negative sbsize for uid = %d\n", uip->ui_uid);
787 	splx(s);
788 	return (1);
789 }
790