xref: /dragonfly/sys/kern/kern_resource.c (revision 1de703da)
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: src/sys/kern/kern_resource.c,v 1.55.2.5 2001/11/03 01:41:08 ps Exp $
40  * $DragonFly: src/sys/kern/kern_resource.c,v 1.2 2003/06/17 04:28:41 dillon Exp $
41  */
42 
43 #include "opt_compat.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 (!PRISON_CHECK(curp, p))
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 ((PRISON_CHECK(curp, p) && 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 		LIST_FOREACH(p, &allproc, p_list)
123 			if (PRISON_CHECK(curp, p) &&
124 			    p->p_ucred->cr_uid == uap->who &&
125 			    p->p_nice < low)
126 				low = p->p_nice;
127 		break;
128 
129 	default:
130 		return (EINVAL);
131 	}
132 	if (low == PRIO_MAX + 1)
133 		return (ESRCH);
134 	curp->p_retval[0] = low;
135 	return (0);
136 }
137 
138 #ifndef _SYS_SYSPROTO_H_
139 struct setpriority_args {
140 	int	which;
141 	int	who;
142 	int	prio;
143 };
144 #endif
145 /* ARGSUSED */
146 int
147 setpriority(curp, uap)
148 	struct proc *curp;
149 	register struct setpriority_args *uap;
150 {
151 	register struct proc *p;
152 	int found = 0, error = 0;
153 
154 	switch (uap->which) {
155 
156 	case PRIO_PROCESS:
157 		if (uap->who == 0)
158 			p = curp;
159 		else
160 			p = pfind(uap->who);
161 		if (p == 0)
162 			break;
163 		if (!PRISON_CHECK(curp, p))
164 			break;
165 		error = donice(curp, p, uap->prio);
166 		found++;
167 		break;
168 
169 	case PRIO_PGRP: {
170 		register struct pgrp *pg;
171 
172 		if (uap->who == 0)
173 			pg = curp->p_pgrp;
174 		else if ((pg = pgfind(uap->who)) == NULL)
175 			break;
176 		LIST_FOREACH(p, &pg->pg_members, p_pglist) {
177 			if (PRISON_CHECK(curp, p)) {
178 				error = donice(curp, p, uap->prio);
179 				found++;
180 			}
181 		}
182 		break;
183 	}
184 
185 	case PRIO_USER:
186 		if (uap->who == 0)
187 			uap->who = curp->p_ucred->cr_uid;
188 		LIST_FOREACH(p, &allproc, p_list)
189 			if (p->p_ucred->cr_uid == uap->who &&
190 			    PRISON_CHECK(curp, p)) {
191 				error = donice(curp, p, uap->prio);
192 				found++;
193 			}
194 		break;
195 
196 	default:
197 		return (EINVAL);
198 	}
199 	if (found == 0)
200 		return (ESRCH);
201 	return (error);
202 }
203 
204 static int
205 donice(curp, chgp, n)
206 	register struct proc *curp, *chgp;
207 	register int n;
208 {
209 	register struct pcred *pcred = curp->p_cred;
210 
211 	if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
212 	    pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
213 	    pcred->p_ruid != chgp->p_ucred->cr_uid)
214 		return (EPERM);
215 	if (n > PRIO_MAX)
216 		n = PRIO_MAX;
217 	if (n < PRIO_MIN)
218 		n = PRIO_MIN;
219 	if (n < chgp->p_nice && suser(curp))
220 		return (EACCES);
221 	chgp->p_nice = n;
222 	(void)resetpriority(chgp);
223 	return (0);
224 }
225 
226 /* rtprio system call */
227 #ifndef _SYS_SYSPROTO_H_
228 struct rtprio_args {
229 	int		function;
230 	pid_t		pid;
231 	struct rtprio	*rtp;
232 };
233 #endif
234 
235 /*
236  * Set realtime priority
237  */
238 
239 /* ARGSUSED */
240 int
241 rtprio(curp, uap)
242 	struct proc *curp;
243 	register struct rtprio_args *uap;
244 {
245 	register struct proc *p;
246 	register struct pcred *pcred = curp->p_cred;
247 	struct rtprio rtp;
248 	int error;
249 
250 	error = copyin(uap->rtp, &rtp, sizeof(struct rtprio));
251 	if (error)
252 		return (error);
253 
254 	if (uap->pid == 0)
255 		p = curp;
256 	else
257 		p = pfind(uap->pid);
258 
259 	if (p == 0)
260 		return (ESRCH);
261 
262 	switch (uap->function) {
263 	case RTP_LOOKUP:
264 		return (copyout(&p->p_rtprio, uap->rtp, sizeof(struct rtprio)));
265 	case RTP_SET:
266 		if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
267 		    pcred->pc_ucred->cr_uid != p->p_ucred->cr_uid &&
268 		    pcred->p_ruid != p->p_ucred->cr_uid)
269 		        return (EPERM);
270 		/* disallow setting rtprio in most cases if not superuser */
271 		if (suser(curp)) {
272 			/* can't set someone else's */
273 			if (uap->pid)
274 				return (EPERM);
275 			/* can't set realtime priority */
276 /*
277  * Realtime priority has to be restricted for reasons which should be
278  * obvious. However, for idle priority, there is a potential for
279  * system deadlock if an idleprio process gains a lock on a resource
280  * that other processes need (and the idleprio process can't run
281  * due to a CPU-bound normal process). Fix me! XXX
282  */
283 #if 0
284  			if (RTP_PRIO_IS_REALTIME(rtp.type))
285 #endif
286 			if (rtp.type != RTP_PRIO_NORMAL)
287 				return (EPERM);
288 		}
289 		switch (rtp.type) {
290 #ifdef RTP_PRIO_FIFO
291 		case RTP_PRIO_FIFO:
292 #endif
293 		case RTP_PRIO_REALTIME:
294 		case RTP_PRIO_NORMAL:
295 		case RTP_PRIO_IDLE:
296 			if (rtp.prio > RTP_PRIO_MAX)
297 				return (EINVAL);
298 			p->p_rtprio = rtp;
299 			return (0);
300 		default:
301 			return (EINVAL);
302 		}
303 
304 	default:
305 		return (EINVAL);
306 	}
307 }
308 
309 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
310 #ifndef _SYS_SYSPROTO_H_
311 struct osetrlimit_args {
312 	u_int	which;
313 	struct	orlimit *rlp;
314 };
315 #endif
316 /* ARGSUSED */
317 int
318 osetrlimit(p, uap)
319 	struct proc *p;
320 	register struct osetrlimit_args *uap;
321 {
322 	struct orlimit olim;
323 	struct rlimit lim;
324 	int error;
325 
326 	if ((error =
327 	    copyin((caddr_t)uap->rlp, (caddr_t)&olim, sizeof(struct orlimit))))
328 		return (error);
329 	lim.rlim_cur = olim.rlim_cur;
330 	lim.rlim_max = olim.rlim_max;
331 	return (dosetrlimit(p, uap->which, &lim));
332 }
333 
334 #ifndef _SYS_SYSPROTO_H_
335 struct ogetrlimit_args {
336 	u_int	which;
337 	struct	orlimit *rlp;
338 };
339 #endif
340 /* ARGSUSED */
341 int
342 ogetrlimit(p, uap)
343 	struct proc *p;
344 	register struct ogetrlimit_args *uap;
345 {
346 	struct orlimit olim;
347 
348 	if (uap->which >= RLIM_NLIMITS)
349 		return (EINVAL);
350 	olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
351 	if (olim.rlim_cur == -1)
352 		olim.rlim_cur = 0x7fffffff;
353 	olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
354 	if (olim.rlim_max == -1)
355 		olim.rlim_max = 0x7fffffff;
356 	return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
357 }
358 #endif /* COMPAT_43 || COMPAT_SUNOS */
359 
360 #ifndef _SYS_SYSPROTO_H_
361 struct __setrlimit_args {
362 	u_int	which;
363 	struct	rlimit *rlp;
364 };
365 #endif
366 /* ARGSUSED */
367 int
368 setrlimit(p, uap)
369 	struct proc *p;
370 	register struct __setrlimit_args *uap;
371 {
372 	struct rlimit alim;
373 	int error;
374 
375 	if ((error =
376 	    copyin((caddr_t)uap->rlp, (caddr_t)&alim, sizeof (struct rlimit))))
377 		return (error);
378 	return (dosetrlimit(p, uap->which, &alim));
379 }
380 
381 int
382 dosetrlimit(p, which, limp)
383 	struct proc *p;
384 	u_int which;
385 	struct rlimit *limp;
386 {
387 	register struct rlimit *alimp;
388 	int error;
389 
390 	if (which >= RLIM_NLIMITS)
391 		return (EINVAL);
392 	alimp = &p->p_rlimit[which];
393 
394 	/*
395 	 * Preserve historical bugs by treating negative limits as unsigned.
396 	 */
397 	if (limp->rlim_cur < 0)
398 		limp->rlim_cur = RLIM_INFINITY;
399 	if (limp->rlim_max < 0)
400 		limp->rlim_max = RLIM_INFINITY;
401 
402 	if (limp->rlim_cur > alimp->rlim_max ||
403 	    limp->rlim_max > alimp->rlim_max)
404 		if ((error = suser_xxx(0, p, PRISON_ROOT)))
405 			return (error);
406 	if (limp->rlim_cur > limp->rlim_max)
407 		limp->rlim_cur = limp->rlim_max;
408 	if (p->p_limit->p_refcnt > 1 &&
409 	    (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
410 		p->p_limit->p_refcnt--;
411 		p->p_limit = limcopy(p->p_limit);
412 		alimp = &p->p_rlimit[which];
413 	}
414 
415 	switch (which) {
416 
417 	case RLIMIT_CPU:
418 		if (limp->rlim_cur > RLIM_INFINITY / (rlim_t)1000000)
419 			p->p_limit->p_cpulimit = RLIM_INFINITY;
420 		else
421 			p->p_limit->p_cpulimit =
422 			    (rlim_t)1000000 * limp->rlim_cur;
423 		break;
424 	case RLIMIT_DATA:
425 		if (limp->rlim_cur > maxdsiz)
426 			limp->rlim_cur = maxdsiz;
427 		if (limp->rlim_max > maxdsiz)
428 			limp->rlim_max = maxdsiz;
429 		break;
430 
431 	case RLIMIT_STACK:
432 		if (limp->rlim_cur > maxssiz)
433 			limp->rlim_cur = maxssiz;
434 		if (limp->rlim_max > maxssiz)
435 			limp->rlim_max = maxssiz;
436 		/*
437 		 * Stack is allocated to the max at exec time with only
438 		 * "rlim_cur" bytes accessible.  If stack limit is going
439 		 * up make more accessible, if going down make inaccessible.
440 		 */
441 		if (limp->rlim_cur != alimp->rlim_cur) {
442 			vm_offset_t addr;
443 			vm_size_t size;
444 			vm_prot_t prot;
445 
446 			if (limp->rlim_cur > alimp->rlim_cur) {
447 				prot = VM_PROT_ALL;
448 				size = limp->rlim_cur - alimp->rlim_cur;
449 				addr = USRSTACK - limp->rlim_cur;
450 			} else {
451 				prot = VM_PROT_NONE;
452 				size = alimp->rlim_cur - limp->rlim_cur;
453 				addr = USRSTACK - alimp->rlim_cur;
454 			}
455 			addr = trunc_page(addr);
456 			size = round_page(size);
457 			(void) vm_map_protect(&p->p_vmspace->vm_map,
458 					      addr, addr+size, prot, FALSE);
459 		}
460 		break;
461 
462 	case RLIMIT_NOFILE:
463 		if (limp->rlim_cur > maxfilesperproc)
464 			limp->rlim_cur = maxfilesperproc;
465 		if (limp->rlim_max > maxfilesperproc)
466 			limp->rlim_max = maxfilesperproc;
467 		break;
468 
469 	case RLIMIT_NPROC:
470 		if (limp->rlim_cur > maxprocperuid)
471 			limp->rlim_cur = maxprocperuid;
472 		if (limp->rlim_max > maxprocperuid)
473 			limp->rlim_max = maxprocperuid;
474 		if (limp->rlim_cur < 1)
475 			limp->rlim_cur = 1;
476 		if (limp->rlim_max < 1)
477 			limp->rlim_max = 1;
478 		break;
479 	}
480 	*alimp = *limp;
481 	return (0);
482 }
483 
484 #ifndef _SYS_SYSPROTO_H_
485 struct __getrlimit_args {
486 	u_int	which;
487 	struct	rlimit *rlp;
488 };
489 #endif
490 /* ARGSUSED */
491 int
492 getrlimit(p, uap)
493 	struct proc *p;
494 	register struct __getrlimit_args *uap;
495 {
496 
497 	if (uap->which >= RLIM_NLIMITS)
498 		return (EINVAL);
499 	return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
500 	    sizeof (struct rlimit)));
501 }
502 
503 /*
504  * Transform the running time and tick information in proc p into user,
505  * system, and interrupt time usage.
506  */
507 void
508 calcru(p, up, sp, ip)
509 	struct proc *p;
510 	struct timeval *up;
511 	struct timeval *sp;
512 	struct timeval *ip;
513 {
514 	/* {user, system, interrupt, total} {ticks, usec}; previous tu: */
515 	u_int64_t ut, uu, st, su, it, iu, tt, tu, ptu;
516 	int s;
517 	struct timeval tv;
518 
519 	/* XXX: why spl-protect ?  worst case is an off-by-one report */
520 	s = splstatclock();
521 	ut = p->p_uticks;
522 	st = p->p_sticks;
523 	it = p->p_iticks;
524 	splx(s);
525 
526 	tt = ut + st + it;
527 	if (tt == 0) {
528 		st = 1;
529 		tt = 1;
530 	}
531 
532 	tu = p->p_runtime;
533 	if (p == curproc) {
534 		/*
535 		 * Adjust for the current time slice.  This is actually fairly
536 		 * important since the error here is on the order of a time
537 		 * quantum, which is much greater than the sampling error.
538 		 */
539 		microuptime(&tv);
540 		if (timevalcmp(&tv, &switchtime, <))
541 			printf("microuptime() went backwards (%ld.%06ld -> %ld.%06ld)\n",
542 			    switchtime.tv_sec, switchtime.tv_usec,
543 			    tv.tv_sec, tv.tv_usec);
544 		else
545 			tu += (tv.tv_usec - switchtime.tv_usec) +
546 			    (tv.tv_sec - switchtime.tv_sec) * (int64_t)1000000;
547 	}
548 	ptu = p->p_uu + p->p_su + p->p_iu;
549 	if (tu < ptu || (int64_t)tu < 0) {
550 		/* XXX no %qd in kernel.  Truncate. */
551 		printf("calcru: negative time of %ld usec for pid %d (%s)\n",
552 		       (long)tu, p->p_pid, p->p_comm);
553 		tu = ptu;
554 	}
555 
556 	/* Subdivide tu. */
557 	uu = (tu * ut) / tt;
558 	su = (tu * st) / tt;
559 	iu = tu - uu - su;
560 
561 	/* Enforce monotonicity. */
562 	if (uu < p->p_uu || su < p->p_su || iu < p->p_iu) {
563 		if (uu < p->p_uu)
564 			uu = p->p_uu;
565 		else if (uu + p->p_su + p->p_iu > tu)
566 			uu = tu - p->p_su - p->p_iu;
567 		if (st == 0)
568 			su = p->p_su;
569 		else {
570 			su = ((tu - uu) * st) / (st + it);
571 			if (su < p->p_su)
572 				su = p->p_su;
573 			else if (uu + su + p->p_iu > tu)
574 				su = tu - uu - p->p_iu;
575 		}
576 		KASSERT(uu + su + p->p_iu <= tu,
577 		    ("calcru: monotonisation botch 1"));
578 		iu = tu - uu - su;
579 		KASSERT(iu >= p->p_iu,
580 		    ("calcru: monotonisation botch 2"));
581 	}
582 	p->p_uu = uu;
583 	p->p_su = su;
584 	p->p_iu = iu;
585 
586 	up->tv_sec = uu / 1000000;
587 	up->tv_usec = uu % 1000000;
588 	sp->tv_sec = su / 1000000;
589 	sp->tv_usec = su % 1000000;
590 	if (ip != NULL) {
591 		ip->tv_sec = iu / 1000000;
592 		ip->tv_usec = iu % 1000000;
593 	}
594 }
595 
596 #ifndef _SYS_SYSPROTO_H_
597 struct getrusage_args {
598 	int	who;
599 	struct	rusage *rusage;
600 };
601 #endif
602 /* ARGSUSED */
603 int
604 getrusage(p, uap)
605 	register struct proc *p;
606 	register struct getrusage_args *uap;
607 {
608 	register struct rusage *rup;
609 
610 	switch (uap->who) {
611 
612 	case RUSAGE_SELF:
613 		rup = &p->p_stats->p_ru;
614 		calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
615 		break;
616 
617 	case RUSAGE_CHILDREN:
618 		rup = &p->p_stats->p_cru;
619 		break;
620 
621 	default:
622 		return (EINVAL);
623 	}
624 	return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
625 	    sizeof (struct rusage)));
626 }
627 
628 void
629 ruadd(ru, ru2)
630 	register struct rusage *ru, *ru2;
631 {
632 	register long *ip, *ip2;
633 	register int i;
634 
635 	timevaladd(&ru->ru_utime, &ru2->ru_utime);
636 	timevaladd(&ru->ru_stime, &ru2->ru_stime);
637 	if (ru->ru_maxrss < ru2->ru_maxrss)
638 		ru->ru_maxrss = ru2->ru_maxrss;
639 	ip = &ru->ru_first; ip2 = &ru2->ru_first;
640 	for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
641 		*ip++ += *ip2++;
642 }
643 
644 /*
645  * Make a copy of the plimit structure.
646  * We share these structures copy-on-write after fork,
647  * and copy when a limit is changed.
648  */
649 struct plimit *
650 limcopy(lim)
651 	struct plimit *lim;
652 {
653 	register struct plimit *copy;
654 
655 	MALLOC(copy, struct plimit *, sizeof(struct plimit),
656 	    M_SUBPROC, M_WAITOK);
657 	bcopy(lim->pl_rlimit, copy->pl_rlimit, sizeof(struct plimit));
658 	copy->p_lflags = 0;
659 	copy->p_refcnt = 1;
660 	return (copy);
661 }
662 
663 /*
664  * Find the uidinfo structure for a uid.  This structure is used to
665  * track the total resource consumption (process count, socket buffer
666  * size, etc.) for the uid and impose limits.
667  */
668 void
669 uihashinit()
670 {
671 	uihashtbl = hashinit(maxproc / 16, M_UIDINFO, &uihash);
672 }
673 
674 static struct uidinfo *
675 uilookup(uid)
676 	uid_t uid;
677 {
678 	struct	uihashhead *uipp;
679 	struct	uidinfo *uip;
680 
681 	uipp = UIHASH(uid);
682 	LIST_FOREACH(uip, uipp, ui_hash)
683 		if (uip->ui_uid == uid)
684 			break;
685 
686 	return (uip);
687 }
688 
689 static struct uidinfo *
690 uicreate(uid)
691 	uid_t uid;
692 {
693 	struct	uidinfo *uip, *norace;
694 
695 	MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_NOWAIT);
696 	if (uip == NULL) {
697 		MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_WAITOK);
698 		/*
699 		 * if we M_WAITOK we must look afterwards or risk
700 		 * redundant entries
701 		 */
702 		norace = uilookup(uid);
703 		if (norace != NULL) {
704 			FREE(uip, M_UIDINFO);
705 			return (norace);
706 		}
707 	}
708 	LIST_INSERT_HEAD(UIHASH(uid), uip, ui_hash);
709 	uip->ui_uid = uid;
710 	uip->ui_proccnt = 0;
711 	uip->ui_sbsize = 0;
712 	uip->ui_ref = 0;
713 	return (uip);
714 }
715 
716 struct uidinfo *
717 uifind(uid)
718 	uid_t uid;
719 {
720 	struct	uidinfo *uip;
721 
722 	uip = uilookup(uid);
723 	if (uip == NULL)
724 		uip = uicreate(uid);
725 	uip->ui_ref++;
726 	return (uip);
727 }
728 
729 int
730 uifree(uip)
731 	struct	uidinfo *uip;
732 {
733 
734 	if (--uip->ui_ref == 0) {
735 		if (uip->ui_sbsize != 0)
736 			/* XXX no %qd in kernel.  Truncate. */
737 			printf("freeing uidinfo: uid = %d, sbsize = %ld\n",
738 			    uip->ui_uid, (long)uip->ui_sbsize);
739 		if (uip->ui_proccnt != 0)
740 			printf("freeing uidinfo: uid = %d, proccnt = %ld\n",
741 			    uip->ui_uid, uip->ui_proccnt);
742 		LIST_REMOVE(uip, ui_hash);
743 		FREE(uip, M_UIDINFO);
744 		return (1);
745 	}
746 	return (0);
747 }
748 
749 /*
750  * Change the count associated with number of processes
751  * a given user is using.  When 'max' is 0, don't enforce a limit
752  */
753 int
754 chgproccnt(uip, diff, max)
755 	struct	uidinfo	*uip;
756 	int	diff;
757 	int	max;
758 {
759 	/* don't allow them to exceed max, but allow subtraction */
760 	if (diff > 0 && uip->ui_proccnt + diff > max && max != 0)
761 		return (0);
762 	uip->ui_proccnt += diff;
763 	if (uip->ui_proccnt < 0)
764 		printf("negative proccnt for uid = %d\n", uip->ui_uid);
765 	return (1);
766 }
767 
768 /*
769  * Change the total socket buffer size a user has used.
770  */
771 int
772 chgsbsize(uip, hiwat, to, max)
773 	struct	uidinfo	*uip;
774 	u_long *hiwat;
775 	u_long	to;
776 	rlim_t	max;
777 {
778 	rlim_t new;
779 	int s;
780 
781 	s = splnet();
782 	new = uip->ui_sbsize + to - *hiwat;
783 	/* don't allow them to exceed max, but allow subtraction */
784 	if (to > *hiwat && new > max) {
785 		splx(s);
786 		return (0);
787 	}
788 	uip->ui_sbsize = new;
789 	*hiwat = to;
790 	if (uip->ui_sbsize < 0)
791 		printf("negative sbsize for uid = %d\n", uip->ui_uid);
792 	splx(s);
793 	return (1);
794 }
795