Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / kern / kern_resource.c
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  */
41
42 #include "opt_compat.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/sysproto.h>
47 #include <sys/file.h>
48 #include <sys/kernel.h>
49 #include <sys/resourcevar.h>
50 #include <sys/malloc.h>
51 #include <sys/proc.h>
52 #include <sys/time.h>
53
54 #include <vm/vm.h>
55 #include <vm/vm_param.h>
56 #include <sys/lock.h>
57 #include <vm/pmap.h>
58 #include <vm/vm_map.h>
59
60 static int donice __P((struct proc *curp, struct proc *chgp, int n));
61 /* dosetrlimit non-static:  Needed by SysVR4 emulator */
62 int dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
63
64 static MALLOC_DEFINE(M_UIDINFO, "uidinfo", "uidinfo structures");
65 #define UIHASH(uid)     (&uihashtbl[(uid) & uihash])
66 static LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
67 static u_long uihash;           /* size of hash table - 1 */
68
69 static struct uidinfo   *uicreate __P((uid_t uid));
70 static struct uidinfo   *uilookup __P((uid_t uid));
71
72 /*
73  * Resource controls and accounting.
74  */
75
76 #ifndef _SYS_SYSPROTO_H_
77 struct getpriority_args {
78         int     which;
79         int     who;
80 };
81 #endif
82 int
83 getpriority(curp, uap)
84         struct proc *curp;
85         register struct getpriority_args *uap;
86 {
87         register struct proc *p;
88         register int low = PRIO_MAX + 1;
89
90         switch (uap->which) {
91
92         case PRIO_PROCESS:
93                 if (uap->who == 0)
94                         p = curp;
95                 else
96                         p = pfind(uap->who);
97                 if (p == 0)
98                         break;
99                 if (!PRISON_CHECK(curp, p))
100                         break;
101                 low = p->p_nice;
102                 break;
103
104         case PRIO_PGRP: {
105                 register struct pgrp *pg;
106
107                 if (uap->who == 0)
108                         pg = curp->p_pgrp;
109                 else if ((pg = pgfind(uap->who)) == NULL)
110                         break;
111                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
112                         if ((PRISON_CHECK(curp, p) && p->p_nice < low))
113                                 low = p->p_nice;
114                 }
115                 break;
116         }
117
118         case PRIO_USER:
119                 if (uap->who == 0)
120                         uap->who = curp->p_ucred->cr_uid;
121                 LIST_FOREACH(p, &allproc, p_list)
122                         if (PRISON_CHECK(curp, p) &&
123                             p->p_ucred->cr_uid == uap->who &&
124                             p->p_nice < low)
125                                 low = p->p_nice;
126                 break;
127
128         default:
129                 return (EINVAL);
130         }
131         if (low == PRIO_MAX + 1)
132                 return (ESRCH);
133         curp->p_retval[0] = low;
134         return (0);
135 }
136
137 #ifndef _SYS_SYSPROTO_H_
138 struct setpriority_args {
139         int     which;
140         int     who;
141         int     prio;
142 };
143 #endif
144 /* ARGSUSED */
145 int
146 setpriority(curp, uap)
147         struct proc *curp;
148         register struct setpriority_args *uap;
149 {
150         register struct proc *p;
151         int found = 0, error = 0;
152
153         switch (uap->which) {
154
155         case PRIO_PROCESS:
156                 if (uap->who == 0)
157                         p = curp;
158                 else
159                         p = pfind(uap->who);
160                 if (p == 0)
161                         break;
162                 if (!PRISON_CHECK(curp, p))
163                         break;
164                 error = donice(curp, p, uap->prio);
165                 found++;
166                 break;
167
168         case PRIO_PGRP: {
169                 register struct pgrp *pg;
170
171                 if (uap->who == 0)
172                         pg = curp->p_pgrp;
173                 else if ((pg = pgfind(uap->who)) == NULL)
174                         break;
175                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
176                         if (PRISON_CHECK(curp, p)) {
177                                 error = donice(curp, p, uap->prio);
178                                 found++;
179                         }
180                 }
181                 break;
182         }
183
184         case PRIO_USER:
185                 if (uap->who == 0)
186                         uap->who = curp->p_ucred->cr_uid;
187                 LIST_FOREACH(p, &allproc, p_list)
188                         if (p->p_ucred->cr_uid == uap->who &&
189                             PRISON_CHECK(curp, p)) {
190                                 error = donice(curp, p, uap->prio);
191                                 found++;
192                         }
193                 break;
194
195         default:
196                 return (EINVAL);
197         }
198         if (found == 0)
199                 return (ESRCH);
200         return (error);
201 }
202
203 static int
204 donice(curp, chgp, n)
205         register struct proc *curp, *chgp;
206         register int n;
207 {
208         register struct pcred *pcred = curp->p_cred;
209
210         if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
211             pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
212             pcred->p_ruid != chgp->p_ucred->cr_uid)
213                 return (EPERM);
214         if (n > PRIO_MAX)
215                 n = PRIO_MAX;
216         if (n < PRIO_MIN)
217                 n = PRIO_MIN;
218         if (n < chgp->p_nice && suser(curp))
219                 return (EACCES);
220         chgp->p_nice = n;
221         (void)resetpriority(chgp);
222         return (0);
223 }
224
225 /* rtprio system call */
226 #ifndef _SYS_SYSPROTO_H_
227 struct rtprio_args {
228         int             function;
229         pid_t           pid;
230         struct rtprio   *rtp;
231 };
232 #endif
233
234 /*
235  * Set realtime priority
236  */
237
238 /* ARGSUSED */
239 int
240 rtprio(curp, uap)
241         struct proc *curp;
242         register struct rtprio_args *uap;
243 {
244         register struct proc *p;
245         register struct pcred *pcred = curp->p_cred;
246         struct rtprio rtp;
247         int error;
248
249         error = copyin(uap->rtp, &rtp, sizeof(struct rtprio));
250         if (error)
251                 return (error);
252
253         if (uap->pid == 0)
254                 p = curp;
255         else
256                 p = pfind(uap->pid);
257
258         if (p == 0)
259                 return (ESRCH);
260
261         switch (uap->function) {
262         case RTP_LOOKUP:
263                 return (copyout(&p->p_rtprio, uap->rtp, sizeof(struct rtprio)));
264         case RTP_SET:
265                 if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
266                     pcred->pc_ucred->cr_uid != p->p_ucred->cr_uid &&
267                     pcred->p_ruid != p->p_ucred->cr_uid)
268                         return (EPERM);
269                 /* disallow setting rtprio in most cases if not superuser */
270                 if (suser(curp)) {
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                 if (limp->rlim_cur < 1)
474                         limp->rlim_cur = 1;
475                 if (limp->rlim_max < 1)
476                         limp->rlim_max = 1;
477                 break;
478         }
479         *alimp = *limp;
480         return (0);
481 }
482
483 #ifndef _SYS_SYSPROTO_H_
484 struct __getrlimit_args {
485         u_int   which;
486         struct  rlimit *rlp;
487 };
488 #endif
489 /* ARGSUSED */
490 int
491 getrlimit(p, uap)
492         struct proc *p;
493         register struct __getrlimit_args *uap;
494 {
495
496         if (uap->which >= RLIM_NLIMITS)
497                 return (EINVAL);
498         return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
499             sizeof (struct rlimit)));
500 }
501
502 /*
503  * Transform the running time and tick information in proc p into user,
504  * system, and interrupt time usage.
505  */
506 void
507 calcru(p, up, sp, ip)
508         struct proc *p;
509         struct timeval *up;
510         struct timeval *sp;
511         struct timeval *ip;
512 {
513         /* {user, system, interrupt, total} {ticks, usec}; previous tu: */
514         u_int64_t ut, uu, st, su, it, iu, tt, tu, ptu;
515         int s;
516         struct timeval tv;
517
518         /* XXX: why spl-protect ?  worst case is an off-by-one report */
519         s = splstatclock();
520         ut = p->p_uticks;
521         st = p->p_sticks;
522         it = p->p_iticks;
523         splx(s);
524
525         tt = ut + st + it;
526         if (tt == 0) {
527                 st = 1;
528                 tt = 1;
529         }
530
531         tu = p->p_runtime;
532         if (p == curproc) {
533                 /*
534                  * Adjust for the current time slice.  This is actually fairly
535                  * important since the error here is on the order of a time
536                  * quantum, which is much greater than the sampling error.
537                  */
538                 microuptime(&tv);
539                 if (timevalcmp(&tv, &switchtime, <))
540                         printf("microuptime() went backwards (%ld.%06ld -> %ld.%06ld)\n",
541                             switchtime.tv_sec, switchtime.tv_usec, 
542                             tv.tv_sec, tv.tv_usec);
543                 else
544                         tu += (tv.tv_usec - switchtime.tv_usec) +
545                             (tv.tv_sec - switchtime.tv_sec) * (int64_t)1000000;
546         }
547         ptu = p->p_uu + p->p_su + p->p_iu;
548         if (tu < ptu || (int64_t)tu < 0) {
549                 /* XXX no %qd in kernel.  Truncate. */
550                 printf("calcru: negative time of %ld usec for pid %d (%s)\n",
551                        (long)tu, p->p_pid, p->p_comm);
552                 tu = ptu;
553         }
554
555         /* Subdivide tu. */
556         uu = (tu * ut) / tt;
557         su = (tu * st) / tt;
558         iu = tu - uu - su;
559
560         /* Enforce monotonicity. */
561         if (uu < p->p_uu || su < p->p_su || iu < p->p_iu) {
562                 if (uu < p->p_uu)
563                         uu = p->p_uu;
564                 else if (uu + p->p_su + p->p_iu > tu)
565                         uu = tu - p->p_su - p->p_iu;
566                 if (st == 0)
567                         su = p->p_su;
568                 else {
569                         su = ((tu - uu) * st) / (st + it);
570                         if (su < p->p_su)
571                                 su = p->p_su;
572                         else if (uu + su + p->p_iu > tu)
573                                 su = tu - uu - p->p_iu;
574                 }
575                 KASSERT(uu + su + p->p_iu <= tu,
576                     ("calcru: monotonisation botch 1"));
577                 iu = tu - uu - su;
578                 KASSERT(iu >= p->p_iu,
579                     ("calcru: monotonisation botch 2"));
580         }
581         p->p_uu = uu;
582         p->p_su = su;
583         p->p_iu = iu;
584
585         up->tv_sec = uu / 1000000;
586         up->tv_usec = uu % 1000000;
587         sp->tv_sec = su / 1000000;
588         sp->tv_usec = su % 1000000;
589         if (ip != NULL) {
590                 ip->tv_sec = iu / 1000000;
591                 ip->tv_usec = iu % 1000000;
592         }
593 }
594
595 #ifndef _SYS_SYSPROTO_H_
596 struct getrusage_args {
597         int     who;
598         struct  rusage *rusage;
599 };
600 #endif
601 /* ARGSUSED */
602 int
603 getrusage(p, uap)
604         register struct proc *p;
605         register struct getrusage_args *uap;
606 {
607         register struct rusage *rup;
608
609         switch (uap->who) {
610
611         case RUSAGE_SELF:
612                 rup = &p->p_stats->p_ru;
613                 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
614                 break;
615
616         case RUSAGE_CHILDREN:
617                 rup = &p->p_stats->p_cru;
618                 break;
619
620         default:
621                 return (EINVAL);
622         }
623         return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
624             sizeof (struct rusage)));
625 }
626
627 void
628 ruadd(ru, ru2)
629         register struct rusage *ru, *ru2;
630 {
631         register long *ip, *ip2;
632         register int i;
633
634         timevaladd(&ru->ru_utime, &ru2->ru_utime);
635         timevaladd(&ru->ru_stime, &ru2->ru_stime);
636         if (ru->ru_maxrss < ru2->ru_maxrss)
637                 ru->ru_maxrss = ru2->ru_maxrss;
638         ip = &ru->ru_first; ip2 = &ru2->ru_first;
639         for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
640                 *ip++ += *ip2++;
641 }
642
643 /*
644  * Make a copy of the plimit structure.
645  * We share these structures copy-on-write after fork,
646  * and copy when a limit is changed.
647  */
648 struct plimit *
649 limcopy(lim)
650         struct plimit *lim;
651 {
652         register struct plimit *copy;
653
654         MALLOC(copy, struct plimit *, sizeof(struct plimit),
655             M_SUBPROC, M_WAITOK);
656         bcopy(lim->pl_rlimit, copy->pl_rlimit, sizeof(struct plimit));
657         copy->p_lflags = 0;
658         copy->p_refcnt = 1;
659         return (copy);
660 }
661
662 /*
663  * Find the uidinfo structure for a uid.  This structure is used to
664  * track the total resource consumption (process count, socket buffer
665  * size, etc.) for the uid and impose limits.
666  */
667 void
668 uihashinit()
669 {
670         uihashtbl = hashinit(maxproc / 16, M_UIDINFO, &uihash);
671 }
672
673 static struct uidinfo *
674 uilookup(uid)
675         uid_t uid;
676 {
677         struct  uihashhead *uipp;
678         struct  uidinfo *uip;
679
680         uipp = UIHASH(uid);
681         LIST_FOREACH(uip, uipp, ui_hash)
682                 if (uip->ui_uid == uid)
683                         break;
684
685         return (uip);
686 }
687
688 static struct uidinfo *
689 uicreate(uid)
690         uid_t uid;
691 {
692         struct  uidinfo *uip, *norace;
693
694         MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_NOWAIT);
695         if (uip == NULL) {
696                 MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_WAITOK);
697                 /*
698                  * if we M_WAITOK we must look afterwards or risk
699                  * redundant entries
700                  */
701                 norace = uilookup(uid);
702                 if (norace != NULL) {
703                         FREE(uip, M_UIDINFO);
704                         return (norace);
705                 }
706         }
707         LIST_INSERT_HEAD(UIHASH(uid), uip, ui_hash);
708         uip->ui_uid = uid;
709         uip->ui_proccnt = 0;
710         uip->ui_sbsize = 0;
711         uip->ui_ref = 0;
712         return (uip);
713 }
714
715 struct uidinfo *
716 uifind(uid)
717         uid_t uid;
718 {
719         struct  uidinfo *uip;
720
721         uip = uilookup(uid);
722         if (uip == NULL)
723                 uip = uicreate(uid);
724         uip->ui_ref++;
725         return (uip);
726 }
727
728 int
729 uifree(uip)
730         struct  uidinfo *uip;
731 {
732
733         if (--uip->ui_ref == 0) {
734                 if (uip->ui_sbsize != 0)
735                         /* XXX no %qd in kernel.  Truncate. */
736                         printf("freeing uidinfo: uid = %d, sbsize = %ld\n",
737                             uip->ui_uid, (long)uip->ui_sbsize);
738                 if (uip->ui_proccnt != 0)
739                         printf("freeing uidinfo: uid = %d, proccnt = %ld\n",
740                             uip->ui_uid, uip->ui_proccnt);
741                 LIST_REMOVE(uip, ui_hash);
742                 FREE(uip, M_UIDINFO);
743                 return (1);
744         }
745         return (0);
746 }
747
748 /*
749  * Change the count associated with number of processes
750  * a given user is using.  When 'max' is 0, don't enforce a limit
751  */
752 int
753 chgproccnt(uip, diff, max)
754         struct  uidinfo *uip;
755         int     diff;
756         int     max;
757 {
758         /* don't allow them to exceed max, but allow subtraction */
759         if (diff > 0 && uip->ui_proccnt + diff > max && max != 0)
760                 return (0);
761         uip->ui_proccnt += diff;
762         if (uip->ui_proccnt < 0)
763                 printf("negative proccnt for uid = %d\n", uip->ui_uid);
764         return (1);
765 }
766
767 /*
768  * Change the total socket buffer size a user has used.
769  */
770 int
771 chgsbsize(uip, hiwat, to, max)
772         struct  uidinfo *uip;
773         u_long *hiwat;
774         u_long  to;
775         rlim_t  max;
776 {
777         rlim_t new;
778         int s;
779
780         s = splnet();
781         new = uip->ui_sbsize + to - *hiwat;
782         /* don't allow them to exceed max, but allow subtraction */
783         if (to > *hiwat && new > max) {
784                 splx(s);
785                 return (0);
786         }
787         uip->ui_sbsize = new;
788         *hiwat = to;
789         if (uip->ui_sbsize < 0)
790                 printf("negative sbsize for uid = %d\n", uip->ui_uid);
791         splx(s);
792         return (1);
793 }