Misc interrupts/LWKT 1/2: threaded interrupts 2: Major work on the
[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  * $DragonFly: src/sys/kern/kern_resource.c,v 1.7 2003/06/30 19:50:31 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 *chgp, int n));
62 /* dosetrlimit non-static:  Needed by SysVR4 emulator */
63 int dosetrlimit __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(struct getpriority_args *uap)
85 {
86         struct proc *curp = curproc;
87         struct proc *p;
88         int low = PRIO_MAX + 1;
89
90         switch (uap->which) {
91         case PRIO_PROCESS:
92                 if (uap->who == 0)
93                         p = curp;
94                 else
95                         p = pfind(uap->who);
96                 if (p == 0)
97                         break;
98                 if (!PRISON_CHECK(curp->p_ucred, p->p_ucred))
99                         break;
100                 low = p->p_nice;
101                 break;
102
103         case PRIO_PGRP: 
104         {
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_ucred, p->p_ucred) && p->p_nice < low))
113                                 low = p->p_nice;
114                 }
115                 break;
116         }
117         case PRIO_USER:
118                 if (uap->who == 0)
119                         uap->who = curp->p_ucred->cr_uid;
120                 LIST_FOREACH(p, &allproc, p_list)
121                         if (PRISON_CHECK(curp->p_ucred, p->p_ucred) &&
122                             p->p_ucred->cr_uid == uap->who &&
123                             p->p_nice < low)
124                                 low = p->p_nice;
125                 break;
126
127         default:
128                 return (EINVAL);
129         }
130         if (low == PRIO_MAX + 1)
131                 return (ESRCH);
132         curp->p_retval[0] = low;
133         return (0);
134 }
135
136 #ifndef _SYS_SYSPROTO_H_
137 struct setpriority_args {
138         int     which;
139         int     who;
140         int     prio;
141 };
142 #endif
143 /* ARGSUSED */
144 int
145 setpriority(struct setpriority_args *uap)
146 {
147         struct proc *curp = curproc;
148         struct proc *p;
149         int found = 0, error = 0;
150
151         switch (uap->which) {
152
153         case PRIO_PROCESS:
154                 if (uap->who == 0)
155                         p = curp;
156                 else
157                         p = pfind(uap->who);
158                 if (p == 0)
159                         break;
160                 if (!PRISON_CHECK(curp->p_ucred, p->p_ucred))
161                         break;
162                 error = donice(p, uap->prio);
163                 found++;
164                 break;
165
166         case PRIO_PGRP: 
167         {
168                 register struct pgrp *pg;
169
170                 if (uap->who == 0)
171                         pg = curp->p_pgrp;
172                 else if ((pg = pgfind(uap->who)) == NULL)
173                         break;
174                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
175                         if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) {
176                                 error = donice(p, uap->prio);
177                                 found++;
178                         }
179                 }
180                 break;
181         }
182         case PRIO_USER:
183                 if (uap->who == 0)
184                         uap->who = curp->p_ucred->cr_uid;
185                 LIST_FOREACH(p, &allproc, p_list)
186                         if (p->p_ucred->cr_uid == uap->who &&
187                             PRISON_CHECK(curp->p_ucred, p->p_ucred)) {
188                                 error = donice(p, uap->prio);
189                                 found++;
190                         }
191                 break;
192
193         default:
194                 return (EINVAL);
195         }
196         if (found == 0)
197                 return (ESRCH);
198         return (error);
199 }
200
201 static int
202 donice(struct proc *chgp, int n)
203 {
204         struct proc *curp = curproc;
205         struct ucred *cr = curp->p_ucred;
206
207         if (cr->cr_uid && cr->cr_ruid &&
208             cr->cr_uid != chgp->p_ucred->cr_uid &&
209             cr->cr_ruid != chgp->p_ucred->cr_uid)
210                 return (EPERM);
211         if (n > PRIO_MAX)
212                 n = PRIO_MAX;
213         if (n < PRIO_MIN)
214                 n = PRIO_MIN;
215         if (n < chgp->p_nice && suser_cred(cr, 0))
216                 return (EACCES);
217         chgp->p_nice = n;
218         (void)resetpriority(chgp);
219         return (0);
220 }
221
222 /* rtprio system call */
223 #ifndef _SYS_SYSPROTO_H_
224 struct rtprio_args {
225         int             function;
226         pid_t           pid;
227         struct rtprio   *rtp;
228 };
229 #endif
230
231 /*
232  * Set realtime priority
233  */
234
235 /* ARGSUSED */
236 int
237 rtprio(register struct rtprio_args *uap)
238 {
239         struct proc *curp = curproc;
240         struct proc *p;
241         struct ucred *cr = curp->p_ucred;
242         struct rtprio rtp;
243         int error;
244
245         error = copyin(uap->rtp, &rtp, sizeof(struct rtprio));
246         if (error)
247                 return (error);
248
249         if (uap->pid == 0)
250                 p = curp;
251         else
252                 p = pfind(uap->pid);
253
254         if (p == 0)
255                 return (ESRCH);
256
257         switch (uap->function) {
258         case RTP_LOOKUP:
259                 return (copyout(&p->p_rtprio, uap->rtp, sizeof(struct rtprio)));
260         case RTP_SET:
261                 if (cr->cr_uid && cr->cr_ruid &&
262                     cr->cr_uid != p->p_ucred->cr_uid &&
263                     cr->cr_ruid != p->p_ucred->cr_uid)
264                         return (EPERM);
265                 /* disallow setting rtprio in most cases if not superuser */
266                 if (suser_cred(cr, 0)) {
267                         /* can't set someone else's */
268                         if (uap->pid)
269                                 return (EPERM);
270                         /* can't set realtime priority */
271 /*
272  * Realtime priority has to be restricted for reasons which should be
273  * obvious. However, for idle priority, there is a potential for
274  * system deadlock if an idleprio process gains a lock on a resource
275  * that other processes need (and the idleprio process can't run
276  * due to a CPU-bound normal process). Fix me! XXX
277  */
278                         if (RTP_PRIO_IS_REALTIME(rtp.type))
279                                 return (EPERM);
280                 }
281                 switch (rtp.type) {
282 #ifdef RTP_PRIO_FIFO
283                 case RTP_PRIO_FIFO:
284 #endif
285                 case RTP_PRIO_REALTIME:
286                 case RTP_PRIO_NORMAL:
287                 case RTP_PRIO_IDLE:
288                         if (rtp.prio > RTP_PRIO_MAX)
289                                 return (EINVAL);
290                         p->p_rtprio = rtp;
291                         return (0);
292                 default:
293                         return (EINVAL);
294                 }
295
296         default:
297                 return (EINVAL);
298         }
299 }
300
301 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
302 #ifndef _SYS_SYSPROTO_H_
303 struct osetrlimit_args {
304         u_int   which;
305         struct  orlimit *rlp;
306 };
307 #endif
308 /* ARGSUSED */
309 int
310 osetrlimit(struct osetrlimit_args *uap)
311 {
312         struct orlimit olim;
313         struct rlimit lim;
314         int error;
315
316         if ((error =
317             copyin((caddr_t)uap->rlp, (caddr_t)&olim, sizeof(struct orlimit))))
318                 return (error);
319         lim.rlim_cur = olim.rlim_cur;
320         lim.rlim_max = olim.rlim_max;
321         return (dosetrlimit(uap->which, &lim));
322 }
323
324 #ifndef _SYS_SYSPROTO_H_
325 struct ogetrlimit_args {
326         u_int   which;
327         struct  orlimit *rlp;
328 };
329 #endif
330 /* ARGSUSED */
331 int
332 ogetrlimit(struct ogetrlimit_args *uap)
333 {
334         struct proc *p = curproc;
335         struct orlimit olim;
336
337         if (uap->which >= RLIM_NLIMITS)
338                 return (EINVAL);
339         olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
340         if (olim.rlim_cur == -1)
341                 olim.rlim_cur = 0x7fffffff;
342         olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
343         if (olim.rlim_max == -1)
344                 olim.rlim_max = 0x7fffffff;
345         return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
346 }
347 #endif /* COMPAT_43 || COMPAT_SUNOS */
348
349 #ifndef _SYS_SYSPROTO_H_
350 struct __setrlimit_args {
351         u_int   which;
352         struct  rlimit *rlp;
353 };
354 #endif
355 /* ARGSUSED */
356 int
357 setrlimit(struct __setrlimit_args *uap)
358 {
359         struct rlimit alim;
360         int error;
361
362         if ((error =
363             copyin((caddr_t)uap->rlp, (caddr_t)&alim, sizeof (struct rlimit))))
364                 return (error);
365         return (dosetrlimit(uap->which, &alim));
366 }
367
368 int
369 dosetrlimit(u_int which, struct rlimit *limp)
370 {
371         struct proc *p = curproc;
372         struct rlimit *alimp;
373         int error;
374
375         if (which >= RLIM_NLIMITS)
376                 return (EINVAL);
377         alimp = &p->p_rlimit[which];
378
379         /*
380          * Preserve historical bugs by treating negative limits as unsigned.
381          */
382         if (limp->rlim_cur < 0)
383                 limp->rlim_cur = RLIM_INFINITY;
384         if (limp->rlim_max < 0)
385                 limp->rlim_max = RLIM_INFINITY;
386
387         if (limp->rlim_cur > alimp->rlim_max ||
388             limp->rlim_max > alimp->rlim_max)
389                 if ((error = suser_cred(p->p_ucred, PRISON_ROOT)))
390                         return (error);
391         if (limp->rlim_cur > limp->rlim_max)
392                 limp->rlim_cur = limp->rlim_max;
393         if (p->p_limit->p_refcnt > 1 &&
394             (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
395                 p->p_limit->p_refcnt--;
396                 p->p_limit = limcopy(p->p_limit);
397                 alimp = &p->p_rlimit[which];
398         }
399
400         switch (which) {
401
402         case RLIMIT_CPU:
403                 if (limp->rlim_cur > RLIM_INFINITY / (rlim_t)1000000)
404                         p->p_limit->p_cpulimit = RLIM_INFINITY;
405                 else
406                         p->p_limit->p_cpulimit = 
407                             (rlim_t)1000000 * limp->rlim_cur;
408                 break;
409         case RLIMIT_DATA:
410                 if (limp->rlim_cur > maxdsiz)
411                         limp->rlim_cur = maxdsiz;
412                 if (limp->rlim_max > maxdsiz)
413                         limp->rlim_max = maxdsiz;
414                 break;
415
416         case RLIMIT_STACK:
417                 if (limp->rlim_cur > maxssiz)
418                         limp->rlim_cur = maxssiz;
419                 if (limp->rlim_max > maxssiz)
420                         limp->rlim_max = maxssiz;
421                 /*
422                  * Stack is allocated to the max at exec time with only
423                  * "rlim_cur" bytes accessible.  If stack limit is going
424                  * up make more accessible, if going down make inaccessible.
425                  */
426                 if (limp->rlim_cur != alimp->rlim_cur) {
427                         vm_offset_t addr;
428                         vm_size_t size;
429                         vm_prot_t prot;
430
431                         if (limp->rlim_cur > alimp->rlim_cur) {
432                                 prot = VM_PROT_ALL;
433                                 size = limp->rlim_cur - alimp->rlim_cur;
434                                 addr = USRSTACK - limp->rlim_cur;
435                         } else {
436                                 prot = VM_PROT_NONE;
437                                 size = alimp->rlim_cur - limp->rlim_cur;
438                                 addr = USRSTACK - alimp->rlim_cur;
439                         }
440                         addr = trunc_page(addr);
441                         size = round_page(size);
442                         (void) vm_map_protect(&p->p_vmspace->vm_map,
443                                               addr, addr+size, prot, FALSE);
444                 }
445                 break;
446
447         case RLIMIT_NOFILE:
448                 if (limp->rlim_cur > maxfilesperproc)
449                         limp->rlim_cur = maxfilesperproc;
450                 if (limp->rlim_max > maxfilesperproc)
451                         limp->rlim_max = maxfilesperproc;
452                 break;
453
454         case RLIMIT_NPROC:
455                 if (limp->rlim_cur > maxprocperuid)
456                         limp->rlim_cur = maxprocperuid;
457                 if (limp->rlim_max > maxprocperuid)
458                         limp->rlim_max = maxprocperuid;
459                 if (limp->rlim_cur < 1)
460                         limp->rlim_cur = 1;
461                 if (limp->rlim_max < 1)
462                         limp->rlim_max = 1;
463                 break;
464         }
465         *alimp = *limp;
466         return (0);
467 }
468
469 #ifndef _SYS_SYSPROTO_H_
470 struct __getrlimit_args {
471         u_int   which;
472         struct  rlimit *rlp;
473 };
474 #endif
475 /* ARGSUSED */
476 int
477 getrlimit(struct __getrlimit_args *uap)
478 {
479         struct proc *p = curproc;
480
481         if (uap->which >= RLIM_NLIMITS)
482                 return (EINVAL);
483         return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
484             sizeof (struct rlimit)));
485 }
486
487 /*
488  * Transform the running time and tick information in proc p into user,
489  * system, and interrupt time usage.
490  *
491  * Since we are limited to statclock tick granularity this is a statisical
492  * calculation which will be correct over the long haul, but should not be
493  * expected to measure fine grained deltas.
494  */
495 void
496 calcru(p, up, sp, ip)
497         struct proc *p;
498         struct timeval *up;
499         struct timeval *sp;
500         struct timeval *ip;
501 {
502         struct thread *td = p->p_thread;
503         int s;
504
505         /*
506          * Calculate at the statclock level.  YYY if the thread is owned by
507          * another cpu we need to forward the request to the other cpu, or
508          * have a token to interlock the information.
509          */
510         s = splstatclock();
511         up->tv_sec = td->td_uticks / 1000000;
512         up->tv_usec = td->td_uticks % 1000000;
513         sp->tv_sec = td->td_sticks / 1000000;
514         sp->tv_usec = td->td_sticks % 1000000;
515         if (ip != NULL) {
516                 ip->tv_sec = td->td_iticks / 1000000;
517                 ip->tv_usec = td->td_iticks % 1000000;
518         }
519         splx(s);
520 }
521
522 #ifndef _SYS_SYSPROTO_H_
523 struct getrusage_args {
524         int     who;
525         struct  rusage *rusage;
526 };
527 #endif
528 /* ARGSUSED */
529 int
530 getrusage(struct getrusage_args *uap)
531 {
532         struct proc *p = curproc;
533         struct rusage *rup;
534
535         switch (uap->who) {
536
537         case RUSAGE_SELF:
538                 rup = &p->p_stats->p_ru;
539                 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
540                 break;
541
542         case RUSAGE_CHILDREN:
543                 rup = &p->p_stats->p_cru;
544                 break;
545
546         default:
547                 return (EINVAL);
548         }
549         return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
550             sizeof (struct rusage)));
551 }
552
553 void
554 ruadd(ru, ru2)
555         register struct rusage *ru, *ru2;
556 {
557         register long *ip, *ip2;
558         register int i;
559
560         timevaladd(&ru->ru_utime, &ru2->ru_utime);
561         timevaladd(&ru->ru_stime, &ru2->ru_stime);
562         if (ru->ru_maxrss < ru2->ru_maxrss)
563                 ru->ru_maxrss = ru2->ru_maxrss;
564         ip = &ru->ru_first; ip2 = &ru2->ru_first;
565         for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
566                 *ip++ += *ip2++;
567 }
568
569 /*
570  * Make a copy of the plimit structure.
571  * We share these structures copy-on-write after fork,
572  * and copy when a limit is changed.
573  */
574 struct plimit *
575 limcopy(lim)
576         struct plimit *lim;
577 {
578         register struct plimit *copy;
579
580         MALLOC(copy, struct plimit *, sizeof(struct plimit),
581             M_SUBPROC, M_WAITOK);
582         bcopy(lim->pl_rlimit, copy->pl_rlimit, sizeof(struct plimit));
583         copy->p_lflags = 0;
584         copy->p_refcnt = 1;
585         return (copy);
586 }
587
588 /*
589  * Find the uidinfo structure for a uid.  This structure is used to
590  * track the total resource consumption (process count, socket buffer
591  * size, etc.) for the uid and impose limits.
592  */
593 void
594 uihashinit()
595 {
596         uihashtbl = hashinit(maxproc / 16, M_UIDINFO, &uihash);
597 }
598
599 static struct uidinfo *
600 uilookup(uid)
601         uid_t uid;
602 {
603         struct  uihashhead *uipp;
604         struct  uidinfo *uip;
605
606         uipp = UIHASH(uid);
607         LIST_FOREACH(uip, uipp, ui_hash)
608                 if (uip->ui_uid == uid)
609                         break;
610
611         return (uip);
612 }
613
614 static struct uidinfo *
615 uicreate(uid)
616         uid_t uid;
617 {
618         struct  uidinfo *uip, *norace;
619
620         MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_NOWAIT);
621         if (uip == NULL) {
622                 MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_WAITOK);
623                 /*
624                  * if we M_WAITOK we must look afterwards or risk
625                  * redundant entries
626                  */
627                 norace = uilookup(uid);
628                 if (norace != NULL) {
629                         FREE(uip, M_UIDINFO);
630                         return (norace);
631                 }
632         }
633         LIST_INSERT_HEAD(UIHASH(uid), uip, ui_hash);
634         uip->ui_uid = uid;
635         uip->ui_proccnt = 0;
636         uip->ui_sbsize = 0;
637         uip->ui_ref = 0;
638         return (uip);
639 }
640
641 struct uidinfo *
642 uifind(uid)
643         uid_t uid;
644 {
645         struct  uidinfo *uip;
646
647         uip = uilookup(uid);
648         if (uip == NULL)
649                 uip = uicreate(uid);
650         uip->ui_ref++;
651         return (uip);
652 }
653
654 int
655 uifree(uip)
656         struct  uidinfo *uip;
657 {
658
659         if (--uip->ui_ref == 0) {
660                 if (uip->ui_sbsize != 0)
661                         /* XXX no %qd in kernel.  Truncate. */
662                         printf("freeing uidinfo: uid = %d, sbsize = %ld\n",
663                             uip->ui_uid, (long)uip->ui_sbsize);
664                 if (uip->ui_proccnt != 0)
665                         printf("freeing uidinfo: uid = %d, proccnt = %ld\n",
666                             uip->ui_uid, uip->ui_proccnt);
667                 LIST_REMOVE(uip, ui_hash);
668                 FREE(uip, M_UIDINFO);
669                 return (1);
670         }
671         return (0);
672 }
673
674 /*
675  * Change the count associated with number of processes
676  * a given user is using.  When 'max' is 0, don't enforce a limit
677  */
678 int
679 chgproccnt(uip, diff, max)
680         struct  uidinfo *uip;
681         int     diff;
682         int     max;
683 {
684         /* don't allow them to exceed max, but allow subtraction */
685         if (diff > 0 && uip->ui_proccnt + diff > max && max != 0)
686                 return (0);
687         uip->ui_proccnt += diff;
688         if (uip->ui_proccnt < 0)
689                 printf("negative proccnt for uid = %d\n", uip->ui_uid);
690         return (1);
691 }
692
693 /*
694  * Change the total socket buffer size a user has used.
695  */
696 int
697 chgsbsize(uip, hiwat, to, max)
698         struct  uidinfo *uip;
699         u_long *hiwat;
700         u_long  to;
701         rlim_t  max;
702 {
703         rlim_t new;
704         int s;
705
706         s = splnet();
707         new = uip->ui_sbsize + to - *hiwat;
708         /* don't allow them to exceed max, but allow subtraction */
709         if (to > *hiwat && new > max) {
710                 splx(s);
711                 return (0);
712         }
713         uip->ui_sbsize = new;
714         *hiwat = to;
715         if (uip->ui_sbsize < 0)
716                 printf("negative sbsize for uid = %d\n", uip->ui_uid);
717         splx(s);
718         return (1);
719 }