1f69bbb8f4914858c4d379eb88d8e53606082fa5
[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.35 2008/05/27 05:25:34 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/kern_syscall.h>
50 #include <sys/kernel.h>
51 #include <sys/resourcevar.h>
52 #include <sys/malloc.h>
53 #include <sys/proc.h>
54 #include <sys/priv.h>
55 #include <sys/time.h>
56 #include <sys/lockf.h>
57
58 #include <vm/vm.h>
59 #include <vm/vm_param.h>
60 #include <sys/lock.h>
61 #include <vm/pmap.h>
62 #include <vm/vm_map.h>
63
64 #include <sys/thread2.h>
65 #include <sys/spinlock2.h>
66
67 static int donice (struct proc *chgp, int n);
68
69 static MALLOC_DEFINE(M_UIDINFO, "uidinfo", "uidinfo structures");
70 #define UIHASH(uid)     (&uihashtbl[(uid) & uihash])
71 static struct spinlock uihash_lock;
72 static LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
73 static u_long uihash;           /* size of hash table - 1 */
74
75 static struct uidinfo   *uicreate (uid_t uid);
76 static struct uidinfo   *uilookup (uid_t uid);
77
78 /*
79  * Resource controls and accounting.
80  */
81
82 struct getpriority_info {
83         int low;
84         int who;
85 };
86
87 static int getpriority_callback(struct proc *p, void *data);
88
89 int
90 sys_getpriority(struct getpriority_args *uap)
91 {
92         struct getpriority_info info;
93         struct proc *curp = curproc;
94         struct proc *p;
95         int low = PRIO_MAX + 1;
96
97         switch (uap->which) {
98         case PRIO_PROCESS:
99                 if (uap->who == 0)
100                         p = curp;
101                 else
102                         p = pfind(uap->who);
103                 if (p == 0)
104                         break;
105                 if (!PRISON_CHECK(curp->p_ucred, p->p_ucred))
106                         break;
107                 low = p->p_nice;
108                 break;
109
110         case PRIO_PGRP: 
111         {
112                 struct pgrp *pg;
113
114                 if (uap->who == 0)
115                         pg = curp->p_pgrp;
116                 else if ((pg = pgfind(uap->who)) == NULL)
117                         break;
118                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
119                         if ((PRISON_CHECK(curp->p_ucred, p->p_ucred) && p->p_nice < low))
120                                 low = p->p_nice;
121                 }
122                 break;
123         }
124         case PRIO_USER:
125                 if (uap->who == 0)
126                         uap->who = curp->p_ucred->cr_uid;
127                 info.low = low;
128                 info.who = uap->who;
129                 allproc_scan(getpriority_callback, &info);
130                 low = info.low;
131                 break;
132
133         default:
134                 return (EINVAL);
135         }
136         if (low == PRIO_MAX + 1)
137                 return (ESRCH);
138         uap->sysmsg_result = low;
139         return (0);
140 }
141
142 /*
143  * Figure out the current lowest nice priority for processes owned
144  * by the specified user.
145  */
146 static
147 int
148 getpriority_callback(struct proc *p, void *data)
149 {
150         struct getpriority_info *info = data;
151
152         if (PRISON_CHECK(curproc->p_ucred, p->p_ucred) &&
153             p->p_ucred->cr_uid == info->who &&
154             p->p_nice < info->low) {
155                 info->low = p->p_nice;
156         }
157         return(0);
158 }
159
160 struct setpriority_info {
161         int prio;
162         int who;
163         int error;
164         int found;
165 };
166
167 static int setpriority_callback(struct proc *p, void *data);
168
169 int
170 sys_setpriority(struct setpriority_args *uap)
171 {
172         struct setpriority_info info;
173         struct proc *curp = curproc;
174         struct proc *p;
175         int found = 0, error = 0;
176
177         switch (uap->which) {
178         case PRIO_PROCESS:
179                 if (uap->who == 0)
180                         p = curp;
181                 else
182                         p = pfind(uap->who);
183                 if (p == 0)
184                         break;
185                 if (!PRISON_CHECK(curp->p_ucred, p->p_ucred))
186                         break;
187                 error = donice(p, uap->prio);
188                 found++;
189                 break;
190
191         case PRIO_PGRP: 
192         {
193                 struct pgrp *pg;
194
195                 if (uap->who == 0)
196                         pg = curp->p_pgrp;
197                 else if ((pg = pgfind(uap->who)) == NULL)
198                         break;
199                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
200                         if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) {
201                                 error = donice(p, uap->prio);
202                                 found++;
203                         }
204                 }
205                 break;
206         }
207         case PRIO_USER:
208                 if (uap->who == 0)
209                         uap->who = curp->p_ucred->cr_uid;
210                 info.prio = uap->prio;
211                 info.who = uap->who;
212                 info.error = 0;
213                 info.found = 0;
214                 allproc_scan(setpriority_callback, &info);
215                 error = info.error;
216                 found = info.found;
217                 break;
218
219         default:
220                 return (EINVAL);
221         }
222         if (found == 0)
223                 return (ESRCH);
224         return (error);
225 }
226
227 static
228 int
229 setpriority_callback(struct proc *p, void *data)
230 {
231         struct setpriority_info *info = data;
232         int error;
233
234         if (p->p_ucred->cr_uid == info->who &&
235             PRISON_CHECK(curproc->p_ucred, p->p_ucred)) {
236                 error = donice(p, info->prio);
237                 if (error)
238                         info->error = error;
239                 ++info->found;
240         }
241         return(0);
242 }
243
244 static int
245 donice(struct proc *chgp, int n)
246 {
247         struct proc *curp = curproc;
248         struct ucred *cr = curp->p_ucred;
249         struct lwp *lp;
250
251         if (cr->cr_uid && cr->cr_ruid &&
252             cr->cr_uid != chgp->p_ucred->cr_uid &&
253             cr->cr_ruid != chgp->p_ucred->cr_uid)
254                 return (EPERM);
255         if (n > PRIO_MAX)
256                 n = PRIO_MAX;
257         if (n < PRIO_MIN)
258                 n = PRIO_MIN;
259         if (n < chgp->p_nice && priv_check_cred(cr, PRIV_ROOT, 0))
260                 return (EACCES);
261         chgp->p_nice = n;
262         FOREACH_LWP_IN_PROC(lp, chgp)
263                 chgp->p_usched->resetpriority(lp);
264         return (0);
265 }
266
267 int
268 sys_lwp_rtprio(struct lwp_rtprio_args *uap)
269 {
270         struct proc *p = curproc;
271         struct lwp *lp;
272         struct rtprio rtp;
273         struct ucred *cr = p->p_ucred;
274         int error;
275
276         error = copyin(uap->rtp, &rtp, sizeof(struct rtprio));
277         if (error)
278                 return error;
279
280         if (uap->pid < 0) {
281                 return EINVAL;
282         } else if (uap->pid == 0) {
283                 /* curproc already loaded on p */
284         } else {
285                 p = pfind(uap->pid);
286         }
287
288         if (p == 0) {
289                 return ESRCH;
290         }
291
292         if (uap->tid < -1) {
293                 return EINVAL;
294         } else if (uap->tid == -1) {
295                 /*
296                  * sadly, tid can be 0 so we can't use 0 here
297                  * like sys_rtprio()
298                  */
299                 lp = curthread->td_lwp;
300         } else {
301                 lp = lwp_rb_tree_RB_LOOKUP(&p->p_lwp_tree, uap->tid);
302                 if (lp == NULL)
303                         return ESRCH;
304         }
305
306         switch (uap->function) {
307         case RTP_LOOKUP:
308                 return (copyout(&lp->lwp_rtprio, uap->rtp,
309                                 sizeof(struct rtprio)));
310         case RTP_SET:
311                 if (cr->cr_uid && cr->cr_ruid &&
312                     cr->cr_uid != p->p_ucred->cr_uid &&
313                     cr->cr_ruid != p->p_ucred->cr_uid) {
314                         return EPERM;
315                 }
316                 /* disallow setting rtprio in most cases if not superuser */
317                 if (priv_check_cred(cr, PRIV_ROOT, 0)) {
318                         /* can't set someone else's */
319                         if (uap->pid) { /* XXX */
320                                 return EPERM;
321                         }
322                         /* can't set realtime priority */
323 /*
324  * Realtime priority has to be restricted for reasons which should be
325  * obvious. However, for idle priority, there is a potential for
326  * system deadlock if an idleprio process gains a lock on a resource
327  * that other processes need (and the idleprio process can't run
328  * due to a CPU-bound normal process). Fix me! XXX
329  */
330                         if (RTP_PRIO_IS_REALTIME(rtp.type)) {
331                                 return EPERM;
332                         }
333                 }
334                 switch (rtp.type) {
335 #ifdef RTP_PRIO_FIFO
336                 case RTP_PRIO_FIFO:
337 #endif
338                 case RTP_PRIO_REALTIME:
339                 case RTP_PRIO_NORMAL:
340                 case RTP_PRIO_IDLE:
341                         if (rtp.prio > RTP_PRIO_MAX)
342                                 return EINVAL;
343                         lp->lwp_rtprio = rtp;
344                         return 0;
345                 default:
346                         return EINVAL;
347                 }
348         default:
349                 return EINVAL;
350         }
351         panic("can't get here");
352 }
353
354 /*
355  * Set realtime priority
356  */
357 /* ARGSUSED */
358 int
359 sys_rtprio(struct rtprio_args *uap)
360 {
361         struct proc *curp = curproc;
362         struct proc *p;
363         struct lwp *lp;
364         struct ucred *cr = curp->p_ucred;
365         struct rtprio rtp;
366         int error;
367
368         error = copyin(uap->rtp, &rtp, sizeof(struct rtprio));
369         if (error)
370                 return (error);
371
372         if (uap->pid == 0)
373                 p = curp;
374         else
375                 p = pfind(uap->pid);
376
377         if (p == 0)
378                 return (ESRCH);
379
380         /* XXX lwp */
381         lp = FIRST_LWP_IN_PROC(p);
382         switch (uap->function) {
383         case RTP_LOOKUP:
384                 return (copyout(&lp->lwp_rtprio, uap->rtp, sizeof(struct rtprio)));
385         case RTP_SET:
386                 if (cr->cr_uid && cr->cr_ruid &&
387                     cr->cr_uid != p->p_ucred->cr_uid &&
388                     cr->cr_ruid != p->p_ucred->cr_uid)
389                         return (EPERM);
390                 /* disallow setting rtprio in most cases if not superuser */
391                 if (priv_check_cred(cr, PRIV_ROOT, 0)) {
392                         /* can't set someone else's */
393                         if (uap->pid)
394                                 return (EPERM);
395                         /* can't set realtime priority */
396 /*
397  * Realtime priority has to be restricted for reasons which should be
398  * obvious. However, for idle priority, there is a potential for
399  * system deadlock if an idleprio process gains a lock on a resource
400  * that other processes need (and the idleprio process can't run
401  * due to a CPU-bound normal process). Fix me! XXX
402  */
403                         if (RTP_PRIO_IS_REALTIME(rtp.type))
404                                 return (EPERM);
405                 }
406                 switch (rtp.type) {
407 #ifdef RTP_PRIO_FIFO
408                 case RTP_PRIO_FIFO:
409 #endif
410                 case RTP_PRIO_REALTIME:
411                 case RTP_PRIO_NORMAL:
412                 case RTP_PRIO_IDLE:
413                         if (rtp.prio > RTP_PRIO_MAX)
414                                 return (EINVAL);
415                         lp->lwp_rtprio = rtp;
416                         return (0);
417                 default:
418                         return (EINVAL);
419                 }
420
421         default:
422                 return (EINVAL);
423         }
424 }
425
426 int
427 sys_setrlimit(struct __setrlimit_args *uap)
428 {
429         struct rlimit alim;
430         int error;
431
432         error = copyin(uap->rlp, &alim, sizeof(alim));
433         if (error)
434                 return (error);
435
436         error = kern_setrlimit(uap->which, &alim);
437
438         return (error);
439 }
440
441 int
442 sys_getrlimit(struct __getrlimit_args *uap)
443 {
444         struct rlimit lim;
445         int error;
446
447         error = kern_getrlimit(uap->which, &lim);
448
449         if (error == 0)
450                 error = copyout(&lim, uap->rlp, sizeof(*uap->rlp));
451         return error;
452 }
453
454 /*
455  * Transform the running time and tick information in lwp lp's thread into user,
456  * system, and interrupt time usage.
457  *
458  * Since we are limited to statclock tick granularity this is a statisical
459  * calculation which will be correct over the long haul, but should not be
460  * expected to measure fine grained deltas.
461  *
462  * It is possible to catch a lwp in the midst of being created, so
463  * check whether lwp_thread is NULL or not.
464  */
465 void
466 calcru(struct lwp *lp, struct timeval *up, struct timeval *sp)
467 {
468         struct thread *td;
469
470         /*
471          * Calculate at the statclock level.  YYY if the thread is owned by
472          * another cpu we need to forward the request to the other cpu, or
473          * have a token to interlock the information in order to avoid racing
474          * thread destruction.
475          */
476         if ((td = lp->lwp_thread) != NULL) {
477                 crit_enter();
478                 up->tv_sec = td->td_uticks / 1000000;
479                 up->tv_usec = td->td_uticks % 1000000;
480                 sp->tv_sec = td->td_sticks / 1000000;
481                 sp->tv_usec = td->td_sticks % 1000000;
482                 crit_exit();
483         }
484 }
485
486 /*
487  * Aggregate resource statistics of all lwps of a process.
488  *
489  * proc.p_ru keeps track of all statistics directly related to a proc.  This
490  * consists of RSS usage and nswap information and aggregate numbers for all
491  * former lwps of this proc.
492  *
493  * proc.p_cru is the sum of all stats of reaped children.
494  *
495  * lwp.lwp_ru contains the stats directly related to one specific lwp, meaning
496  * packet, scheduler switch or page fault counts, etc.  This information gets
497  * added to lwp.lwp_proc.p_ru when the lwp exits.
498  */
499 void
500 calcru_proc(struct proc *p, struct rusage *ru)
501 {
502         struct timeval upt, spt;
503         long *rip1, *rip2;
504         struct lwp *lp;
505
506         *ru = p->p_ru;
507
508         FOREACH_LWP_IN_PROC(lp, p) {
509                 calcru(lp, &upt, &spt);
510                 timevaladd(&ru->ru_utime, &upt);
511                 timevaladd(&ru->ru_stime, &spt);
512                 for (rip1 = &ru->ru_first, rip2 = &lp->lwp_ru.ru_first;
513                      rip1 <= &ru->ru_last;
514                      rip1++, rip2++)
515                         *rip1 += *rip2;
516         }
517 }
518
519
520 /* ARGSUSED */
521 int
522 sys_getrusage(struct getrusage_args *uap)
523 {
524         struct rusage ru;
525         struct rusage *rup;
526
527         switch (uap->who) {
528
529         case RUSAGE_SELF:
530                 rup = &ru;
531                 calcru_proc(curproc, rup);
532                 break;
533
534         case RUSAGE_CHILDREN:
535                 rup = &curproc->p_cru;
536                 break;
537
538         default:
539                 return (EINVAL);
540         }
541         return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
542             sizeof (struct rusage)));
543 }
544
545 void
546 ruadd(struct rusage *ru, struct rusage *ru2)
547 {
548         long *ip, *ip2;
549         int i;
550
551         timevaladd(&ru->ru_utime, &ru2->ru_utime);
552         timevaladd(&ru->ru_stime, &ru2->ru_stime);
553         if (ru->ru_maxrss < ru2->ru_maxrss)
554                 ru->ru_maxrss = ru2->ru_maxrss;
555         ip = &ru->ru_first; ip2 = &ru2->ru_first;
556         for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
557                 *ip++ += *ip2++;
558 }
559
560 /*
561  * Find the uidinfo structure for a uid.  This structure is used to
562  * track the total resource consumption (process count, socket buffer
563  * size, etc.) for the uid and impose limits.
564  */
565 void
566 uihashinit(void)
567 {
568         spin_init(&uihash_lock);
569         uihashtbl = hashinit(maxproc / 16, M_UIDINFO, &uihash);
570 }
571
572 static struct uidinfo *
573 uilookup(uid_t uid)
574 {
575         struct  uihashhead *uipp;
576         struct  uidinfo *uip;
577
578         uipp = UIHASH(uid);
579         LIST_FOREACH(uip, uipp, ui_hash) {
580                 if (uip->ui_uid == uid)
581                         break;
582         }
583         return (uip);
584 }
585
586 static struct uidinfo *
587 uicreate(uid_t uid)
588 {
589         struct  uidinfo *uip, *tmp;
590         /*
591          * Allocate space and check for a race
592          */
593         MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_WAITOK);
594         /*
595          * Initialize structure and enter it into the hash table
596          */
597         spin_init(&uip->ui_lock);
598         uip->ui_uid = uid;
599         uip->ui_proccnt = 0;
600         uip->ui_sbsize = 0;
601         uip->ui_ref = 1;        /* we're returning a ref */
602         uip->ui_posixlocks = 0;
603         varsymset_init(&uip->ui_varsymset, NULL);
604
605         /*
606          * Somebody may have already created the uidinfo for this
607          * uid. If so, return that instead.
608          */
609         spin_lock_wr(&uihash_lock);
610         tmp = uilookup(uid);
611         if (tmp != NULL) {
612                 varsymset_clean(&uip->ui_varsymset);
613                 spin_uninit(&uip->ui_lock);
614                 FREE(uip, M_UIDINFO);
615                 uip = tmp;
616         } else {
617                 LIST_INSERT_HEAD(UIHASH(uid), uip, ui_hash);
618         }
619         spin_unlock_wr(&uihash_lock);
620
621         return (uip);
622 }
623
624 struct uidinfo *
625 uifind(uid_t uid)
626 {
627         struct  uidinfo *uip;
628
629         spin_lock_rd(&uihash_lock);
630         uip = uilookup(uid);
631         if (uip == NULL) {
632                 spin_unlock_rd(&uihash_lock);
633                 uip = uicreate(uid);
634         } else {
635                 uihold(uip);
636                 spin_unlock_rd(&uihash_lock);
637         }
638         return (uip);
639 }
640
641 static __inline void
642 uifree(struct uidinfo *uip)
643 {
644         spin_lock_wr(&uihash_lock);
645
646         /*
647          * Note that we're taking a read lock even though we
648          * modify the structure because we know nobody can find
649          * it now that we've locked uihash_lock. If somebody
650          * can get to it through a stored pointer, the reference
651          * count will not be 0 and in that case we don't modify
652          * the struct.
653          */
654         spin_lock_rd(&uip->ui_lock);
655         if (uip->ui_ref != 0) {
656                 /*
657                  * Someone found the uid and got a ref when we
658                  * unlocked. No need to free any more.
659                  */
660                 spin_unlock_rd(&uip->ui_lock);
661                 return;
662         }
663         if (uip->ui_sbsize != 0)
664                 /* XXX no %qd in kernel.  Truncate. */
665                 kprintf("freeing uidinfo: uid = %d, sbsize = %ld\n",
666                     uip->ui_uid, (long)uip->ui_sbsize);
667         if (uip->ui_proccnt != 0)
668                 kprintf("freeing uidinfo: uid = %d, proccnt = %ld\n",
669                     uip->ui_uid, uip->ui_proccnt);
670         
671         LIST_REMOVE(uip, ui_hash);
672         spin_unlock_wr(&uihash_lock);
673         varsymset_clean(&uip->ui_varsymset);
674         lockuninit(&uip->ui_varsymset.vx_lock);
675         spin_unlock_rd(&uip->ui_lock);
676         spin_uninit(&uip->ui_lock);
677         FREE(uip, M_UIDINFO);
678 }
679
680 void
681 uihold(struct uidinfo *uip)
682 {
683         atomic_add_int(&uip->ui_ref, 1);
684         KKASSERT(uip->ui_ref > 0);
685 }
686
687 void
688 uidrop(struct uidinfo *uip)
689 {
690         if (atomic_fetchadd_int(&uip->ui_ref, -1) == 1) {
691                 uifree(uip);
692         } else {
693                 KKASSERT(uip->ui_ref > 0);
694         }
695 }
696
697 void
698 uireplace(struct uidinfo **puip, struct uidinfo *nuip)
699 {
700         uidrop(*puip);
701         *puip = nuip;
702 }
703
704 /*
705  * Change the count associated with number of processes
706  * a given user is using.  When 'max' is 0, don't enforce a limit
707  */
708 int
709 chgproccnt(struct uidinfo *uip, int diff, int max)
710 {
711         int ret;
712         spin_lock_wr(&uip->ui_lock);
713         /* don't allow them to exceed max, but allow subtraction */
714         if (diff > 0 && uip->ui_proccnt + diff > max && max != 0) {
715                 ret = 0;
716         } else {
717                 uip->ui_proccnt += diff;
718                 if (uip->ui_proccnt < 0)
719                         kprintf("negative proccnt for uid = %d\n", uip->ui_uid);
720                 ret = 1;
721         }
722         spin_unlock_wr(&uip->ui_lock);
723         return ret;
724 }
725
726 /*
727  * Change the total socket buffer size a user has used.
728  */
729 int
730 chgsbsize(struct uidinfo *uip, u_long *hiwat, u_long to, rlim_t max)
731 {
732         rlim_t new;
733
734         spin_lock_wr(&uip->ui_lock);
735         new = uip->ui_sbsize + to - *hiwat;
736         KKASSERT(new >= 0);
737
738         /*
739          * If we are trying to increase the socket buffer size
740          * Scale down the hi water mark when we exceed the user's
741          * allowed socket buffer space.
742          *
743          * We can't scale down too much or we will blow up atomic packet
744          * operations.
745          */
746         if (to > *hiwat && to > MCLBYTES && new > max) {
747                 to = to * max / new;
748                 if (to < MCLBYTES)
749                         to = MCLBYTES;
750         }
751         uip->ui_sbsize = new;
752         *hiwat = to;
753         spin_unlock_wr(&uip->ui_lock);
754         return (1);
755 }
756