root/kern/kern_resource.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_getpriority
  2. sys_setpriority
  3. donice
  4. sys_setrlimit
  5. dosetrlimit
  6. sys_getrlimit
  7. calcru
  8. sys_getrusage
  9. ruadd
  10. limcopy
  11. limfree

    1 /*      $OpenBSD: kern_resource.c,v 1.32 2007/04/12 22:14:15 tedu Exp $ */
    2 /*      $NetBSD: kern_resource.c,v 1.38 1996/10/23 07:19:38 matthias Exp $      */
    3 
    4 /*-
    5  * Copyright (c) 1982, 1986, 1991, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  * (c) UNIX System Laboratories, Inc.
    8  * All or some portions of this file are derived from material licensed
    9  * to the University of California by American Telephone and Telegraph
   10  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   11  * the permission of UNIX System Laboratories, Inc.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  *
   37  *      @(#)kern_resource.c     8.5 (Berkeley) 1/21/94
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 #include <sys/file.h>
   44 #include <sys/resourcevar.h>
   45 #include <sys/pool.h>
   46 #include <sys/proc.h>
   47 #include <sys/sched.h>
   48 
   49 #include <sys/mount.h>
   50 #include <sys/syscallargs.h>
   51 
   52 #include <uvm/uvm_extern.h>
   53 
   54 /*
   55  * Patchable maximum data and stack limits.
   56  */
   57 rlim_t maxdmap = MAXDSIZ;
   58 rlim_t maxsmap = MAXSSIZ;
   59 
   60 /*
   61  * Resource controls and accounting.
   62  */
   63 
   64 int
   65 sys_getpriority(struct proc *curp, void *v, register_t *retval)
   66 {
   67         struct sys_getpriority_args /* {
   68                 syscallarg(int) which;
   69                 syscallarg(id_t) who;
   70         } */ *uap = v;
   71         struct proc *p;
   72         int low = NZERO + PRIO_MAX + 1;
   73 
   74         switch (SCARG(uap, which)) {
   75 
   76         case PRIO_PROCESS:
   77                 if (SCARG(uap, who) == 0)
   78                         p = curp;
   79                 else
   80                         p = pfind(SCARG(uap, who));
   81                 if (p == 0)
   82                         break;
   83                 low = p->p_nice;
   84                 break;
   85 
   86         case PRIO_PGRP: {
   87                 struct pgrp *pg;
   88 
   89                 if (SCARG(uap, who) == 0)
   90                         pg = curp->p_pgrp;
   91                 else if ((pg = pgfind(SCARG(uap, who))) == NULL)
   92                         break;
   93                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
   94                         if (p->p_nice < low)
   95                                 low = p->p_nice;
   96                 }
   97                 break;
   98         }
   99 
  100         case PRIO_USER:
  101                 if (SCARG(uap, who) == 0)
  102                         SCARG(uap, who) = curp->p_ucred->cr_uid;
  103                 for (p = LIST_FIRST(&allproc); p; p = LIST_NEXT(p, p_list))
  104                         if (p->p_ucred->cr_uid == SCARG(uap, who) &&
  105                             p->p_nice < low)
  106                                 low = p->p_nice;
  107                 break;
  108 
  109         default:
  110                 return (EINVAL);
  111         }
  112         if (low == NZERO + PRIO_MAX + 1)
  113                 return (ESRCH);
  114         *retval = low - NZERO;
  115         return (0);
  116 }
  117 
  118 /* ARGSUSED */
  119 int
  120 sys_setpriority(struct proc *curp, void *v, register_t *retval)
  121 {
  122         struct sys_setpriority_args /* {
  123                 syscallarg(int) which;
  124                 syscallarg(id_t) who;
  125                 syscallarg(int) prio;
  126         } */ *uap = v;
  127         struct proc *p;
  128         int found = 0, error = 0;
  129 
  130         switch (SCARG(uap, which)) {
  131 
  132         case PRIO_PROCESS:
  133                 if (SCARG(uap, who) == 0)
  134                         p = curp;
  135                 else
  136                         p = pfind(SCARG(uap, who));
  137                 if (p == 0)
  138                         break;
  139                 error = donice(curp, p, SCARG(uap, prio));
  140                 found++;
  141                 break;
  142 
  143         case PRIO_PGRP: {
  144                 struct pgrp *pg;
  145                  
  146                 if (SCARG(uap, who) == 0)
  147                         pg = curp->p_pgrp;
  148                 else if ((pg = pgfind(SCARG(uap, who))) == NULL)
  149                         break;
  150                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
  151                         error = donice(curp, p, SCARG(uap, prio));
  152                         found++;
  153                 }
  154                 break;
  155         }
  156 
  157         case PRIO_USER:
  158                 if (SCARG(uap, who) == 0)
  159                         SCARG(uap, who) = curp->p_ucred->cr_uid;
  160                 for (p = LIST_FIRST(&allproc); p; p = LIST_NEXT(p, p_list))
  161                         if (p->p_ucred->cr_uid == SCARG(uap, who)) {
  162                                 error = donice(curp, p, SCARG(uap, prio));
  163                                 found++;
  164                         }
  165                 break;
  166 
  167         default:
  168                 return (EINVAL);
  169         }
  170         if (found == 0)
  171                 return (ESRCH);
  172         return (error);
  173 }
  174 
  175 int
  176 donice(struct proc *curp, struct proc *chgp, int n)
  177 {
  178         struct pcred *pcred = curp->p_cred;
  179         int s;
  180 
  181         if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
  182             pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
  183             pcred->p_ruid != chgp->p_ucred->cr_uid)
  184                 return (EPERM);
  185         if (n > PRIO_MAX)
  186                 n = PRIO_MAX;
  187         if (n < PRIO_MIN)
  188                 n = PRIO_MIN;
  189         n += NZERO;
  190         if (n < chgp->p_nice && suser(curp, 0))
  191                 return (EACCES);
  192         chgp->p_nice = n;
  193         SCHED_LOCK(s);
  194         (void)resetpriority(chgp);
  195         SCHED_UNLOCK(s);
  196         return (0);
  197 }
  198 
  199 /* ARGSUSED */
  200 int
  201 sys_setrlimit(struct proc *p, void *v, register_t *retval)
  202 {
  203         struct sys_setrlimit_args /* {
  204                 syscallarg(int) which;
  205                 syscallarg(const struct rlimit *) rlp;
  206         } */ *uap = v;
  207         struct rlimit alim;
  208         int error;
  209 
  210         error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&alim,
  211                        sizeof (struct rlimit));
  212         if (error)
  213                 return (error);
  214         return (dosetrlimit(p, SCARG(uap, which), &alim));
  215 }
  216 
  217 int
  218 dosetrlimit(struct proc *p, u_int which, struct rlimit *limp)
  219 {
  220         struct rlimit *alimp;
  221         rlim_t maxlim;
  222         int error;
  223 
  224         if (which >= RLIM_NLIMITS)
  225                 return (EINVAL);
  226 
  227         alimp = &p->p_rlimit[which];
  228         if (limp->rlim_cur > alimp->rlim_max ||
  229             limp->rlim_max > alimp->rlim_max)
  230                 if ((error = suser(p, 0)) != 0)
  231                         return (error);
  232         if (p->p_p->ps_limit->p_refcnt > 1 &&
  233             (p->p_p->ps_limit->p_lflags & PL_SHAREMOD) == 0) {
  234                 p->p_p->ps_limit->p_refcnt--;
  235                 p->p_p->ps_limit = limcopy(p->p_p->ps_limit);
  236                 alimp = &p->p_rlimit[which];
  237         }
  238 
  239         switch (which) {
  240         case RLIMIT_DATA:
  241                 maxlim = maxdmap;
  242                 break;
  243         case RLIMIT_STACK:
  244                 maxlim = maxsmap;
  245                 break;
  246         case RLIMIT_NOFILE:
  247                 maxlim = maxfiles;
  248                 break;
  249         case RLIMIT_NPROC:
  250                 maxlim = maxproc;
  251                 break;
  252         default:
  253                 maxlim = RLIM_INFINITY;
  254                 break;
  255         }
  256 
  257         if (limp->rlim_max > maxlim)
  258                 limp->rlim_max = maxlim;
  259         if (limp->rlim_cur > limp->rlim_max)
  260                 limp->rlim_cur = limp->rlim_max;
  261 
  262         if (which == RLIMIT_STACK) {
  263                 /*
  264                  * Stack is allocated to the max at exec time with only
  265                  * "rlim_cur" bytes accessible.  If stack limit is going
  266                  * up make more accessible, if going down make inaccessible.
  267                  */
  268                 if (limp->rlim_cur != alimp->rlim_cur) {
  269                         vaddr_t addr;
  270                         vsize_t size;
  271                         vm_prot_t prot;
  272 
  273                         if (limp->rlim_cur > alimp->rlim_cur) {
  274                                 prot = VM_PROT_READ|VM_PROT_WRITE;
  275                                 size = limp->rlim_cur - alimp->rlim_cur;
  276 #ifdef MACHINE_STACK_GROWS_UP
  277                                 addr = USRSTACK + alimp->rlim_cur;
  278 #else
  279                                 addr = USRSTACK - limp->rlim_cur;
  280 #endif
  281                         } else {
  282                                 prot = VM_PROT_NONE;
  283                                 size = alimp->rlim_cur - limp->rlim_cur;
  284 #ifdef MACHINE_STACK_GROWS_UP
  285                                 addr = USRSTACK + limp->rlim_cur;
  286 #else
  287                                 addr = USRSTACK - alimp->rlim_cur;
  288 #endif
  289                         }
  290                         addr = trunc_page(addr);
  291                         size = round_page(size);
  292                         (void) uvm_map_protect(&p->p_vmspace->vm_map,
  293                                               addr, addr+size, prot, FALSE);
  294                 }
  295         }
  296 
  297         *alimp = *limp;
  298         return (0);
  299 }
  300 
  301 /* ARGSUSED */
  302 int
  303 sys_getrlimit(struct proc *p, void *v, register_t *retval)
  304 {
  305         struct sys_getrlimit_args /* {
  306                 syscallarg(int) which;
  307                 syscallarg(struct rlimit *) rlp;
  308         } */ *uap = v;
  309 
  310         if (SCARG(uap, which) < 0 || SCARG(uap, which) >= RLIM_NLIMITS)
  311                 return (EINVAL);
  312         return (copyout((caddr_t)&p->p_rlimit[SCARG(uap, which)],
  313             (caddr_t)SCARG(uap, rlp), sizeof (struct rlimit)));
  314 }
  315 
  316 /*
  317  * Transform the running time and tick information in proc p into user,
  318  * system, and interrupt time usage.
  319  */
  320 void
  321 calcru(struct proc *p, struct timeval *up, struct timeval *sp,
  322     struct timeval *ip)
  323 {
  324         u_quad_t st, ut, it;
  325         int freq;
  326         int s;
  327 
  328         s = splstatclock();
  329         st = p->p_sticks;
  330         ut = p->p_uticks;
  331         it = p->p_iticks;
  332         splx(s);
  333 
  334         if (st + ut + it == 0) {
  335                 timerclear(up);
  336                 timerclear(sp);
  337                 if (ip != NULL)
  338                         timerclear(ip);
  339                 return;
  340         }
  341 
  342         freq = stathz ? stathz : hz;
  343 
  344         st = st * 1000000 / freq;
  345         sp->tv_sec = st / 1000000;
  346         sp->tv_usec = st % 1000000;
  347         ut = ut * 1000000 / freq;
  348         up->tv_sec = ut / 1000000;
  349         up->tv_usec = ut % 1000000;
  350         if (ip != NULL) {
  351                 it = it * 1000000 / freq;
  352                 ip->tv_sec = it / 1000000;
  353                 ip->tv_usec = it % 1000000;
  354         }
  355 }
  356 
  357 /* ARGSUSED */
  358 int
  359 sys_getrusage(struct proc *p, void *v, register_t *retval)
  360 {
  361         struct sys_getrusage_args /* {
  362                 syscallarg(int) who;
  363                 syscallarg(struct rusage *) rusage;
  364         } */ *uap = v;
  365         struct rusage *rup;
  366 
  367         switch (SCARG(uap, who)) {
  368 
  369         case RUSAGE_SELF:
  370                 rup = &p->p_stats->p_ru;
  371                 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
  372                 break;
  373 
  374         case RUSAGE_CHILDREN:
  375                 rup = &p->p_stats->p_cru;
  376                 break;
  377 
  378         default:
  379                 return (EINVAL);
  380         }
  381         return (copyout((caddr_t)rup, (caddr_t)SCARG(uap, rusage),
  382             sizeof (struct rusage)));
  383 }
  384 
  385 void
  386 ruadd(struct rusage *ru, struct rusage *ru2)
  387 {
  388         long *ip, *ip2;
  389         int i;
  390 
  391         timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
  392         timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
  393         if (ru->ru_maxrss < ru2->ru_maxrss)
  394                 ru->ru_maxrss = ru2->ru_maxrss;
  395         ip = &ru->ru_first; ip2 = &ru2->ru_first;
  396         for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
  397                 *ip++ += *ip2++;
  398 }
  399 
  400 struct pool plimit_pool;
  401 
  402 /*
  403  * Make a copy of the plimit structure.
  404  * We share these structures copy-on-write after fork,
  405  * and copy when a limit is changed.
  406  */
  407 struct plimit *
  408 limcopy(struct plimit *lim)
  409 {
  410         struct plimit *newlim;
  411         static int initialized;
  412 
  413         if (!initialized) {
  414                 pool_init(&plimit_pool, sizeof(struct plimit), 0, 0, 0,
  415                     "plimitpl", &pool_allocator_nointr);
  416                 initialized = 1;
  417         }
  418 
  419         newlim = pool_get(&plimit_pool, PR_WAITOK);
  420         bcopy(lim->pl_rlimit, newlim->pl_rlimit,
  421             sizeof(struct rlimit) * RLIM_NLIMITS);
  422         newlim->p_lflags = 0;
  423         newlim->p_refcnt = 1;
  424         return (newlim);
  425 }
  426 
  427 void
  428 limfree(struct plimit *lim)
  429 {
  430         if (--lim->p_refcnt > 0)
  431                 return;
  432         pool_put(&plimit_pool, lim);
  433 }

/* [<][>][^][v][top][bottom][index][help] */