The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_resource.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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$
   40  */
   41 
   42 #include "opt_compat.h"
   43 #include "opt_rlimit.h"
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/sysproto.h>
   48 #include <sys/kernel.h>
   49 #include <sys/file.h>
   50 #include <sys/resourcevar.h>
   51 #include <sys/malloc.h>
   52 #include <sys/proc.h>
   53 
   54 #include <vm/vm.h>
   55 #include <vm/vm_param.h>
   56 #include <vm/vm_prot.h>
   57 #include <sys/lock.h>
   58 #include <vm/pmap.h>
   59 #include <vm/vm_map.h>
   60 
   61 static int donice __P((struct proc *curp, struct proc *chgp, int n));
   62 static int dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
   63 
   64 /*
   65  * Resource controls and accounting.
   66  */
   67 
   68 #ifndef _SYS_SYSPROTO_H_
   69 struct getpriority_args {
   70         int     which;
   71         int     who;
   72 };
   73 #endif
   74 int
   75 getpriority(curp, uap)
   76         struct proc *curp;
   77         register struct getpriority_args *uap;
   78 {
   79         register struct proc *p;
   80         register int low = PRIO_MAX + 1;
   81 
   82         switch (uap->which) {
   83 
   84         case PRIO_PROCESS:
   85                 if (uap->who == 0)
   86                         p = curp;
   87                 else
   88                         p = pfind(uap->who);
   89                 if (p == 0)
   90                         break;
   91                 low = p->p_nice;
   92                 break;
   93 
   94         case PRIO_PGRP: {
   95                 register struct pgrp *pg;
   96 
   97                 if (uap->who == 0)
   98                         pg = curp->p_pgrp;
   99                 else if ((pg = pgfind(uap->who)) == NULL)
  100                         break;
  101                 for (p = pg->pg_members.lh_first; p != 0;
  102                      p = p->p_pglist.le_next) {
  103                         if (p->p_nice < low)
  104                                 low = p->p_nice;
  105                 }
  106                 break;
  107         }
  108 
  109         case PRIO_USER:
  110                 if (uap->who == 0)
  111                         uap->who = curp->p_ucred->cr_uid;
  112                 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
  113                         if (p->p_ucred->cr_uid == uap->who &&
  114                             p->p_nice < low)
  115                                 low = p->p_nice;
  116                 break;
  117 
  118         default:
  119                 return (EINVAL);
  120         }
  121         if (low == PRIO_MAX + 1)
  122                 return (ESRCH);
  123         curp->p_retval[0] = low;
  124         return (0);
  125 }
  126 
  127 #ifndef _SYS_SYSPROTO_H_
  128 struct setpriority_args {
  129         int     which;
  130         int     who;
  131         int     prio;
  132 };
  133 #endif
  134 /* ARGSUSED */
  135 int
  136 setpriority(curp, uap)
  137         struct proc *curp;
  138         register struct setpriority_args *uap;
  139 {
  140         register struct proc *p;
  141         int found = 0, error = 0;
  142 
  143         switch (uap->which) {
  144 
  145         case PRIO_PROCESS:
  146                 if (uap->who == 0)
  147                         p = curp;
  148                 else
  149                         p = pfind(uap->who);
  150                 if (p == 0)
  151                         break;
  152                 error = donice(curp, p, uap->prio);
  153                 found++;
  154                 break;
  155 
  156         case PRIO_PGRP: {
  157                 register struct pgrp *pg;
  158 
  159                 if (uap->who == 0)
  160                         pg = curp->p_pgrp;
  161                 else if ((pg = pgfind(uap->who)) == NULL)
  162                         break;
  163                 for (p = pg->pg_members.lh_first; p != 0;
  164                     p = p->p_pglist.le_next) {
  165                         error = donice(curp, p, uap->prio);
  166                         found++;
  167                 }
  168                 break;
  169         }
  170 
  171         case PRIO_USER:
  172                 if (uap->who == 0)
  173                         uap->who = curp->p_ucred->cr_uid;
  174                 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
  175                         if (p->p_ucred->cr_uid == uap->who) {
  176                                 error = donice(curp, p, uap->prio);
  177                                 found++;
  178                         }
  179                 break;
  180 
  181         default:
  182                 return (EINVAL);
  183         }
  184         if (found == 0)
  185                 return (ESRCH);
  186         return (error);
  187 }
  188 
  189 static int
  190 donice(curp, chgp, n)
  191         register struct proc *curp, *chgp;
  192         register int n;
  193 {
  194         register struct pcred *pcred = curp->p_cred;
  195 
  196         if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
  197             pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
  198             pcred->p_ruid != chgp->p_ucred->cr_uid)
  199                 return (EPERM);
  200         if (n > PRIO_MAX)
  201                 n = PRIO_MAX;
  202         if (n < PRIO_MIN)
  203                 n = PRIO_MIN;
  204         if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
  205                 return (EACCES);
  206         chgp->p_nice = n;
  207         (void)resetpriority(chgp);
  208         return (0);
  209 }
  210 
  211 /* rtprio system call */
  212 #ifndef _SYS_SYSPROTO_H_
  213 struct rtprio_args {
  214         int             function;
  215         pid_t           pid;
  216         struct rtprio   *rtp;
  217 };
  218 #endif
  219 
  220 /*
  221  * Set realtime priority
  222  */
  223 
  224 /* ARGSUSED */
  225 int
  226 rtprio(curp, uap)
  227         struct proc *curp;
  228         register struct rtprio_args *uap;
  229 {
  230         register struct proc *p;
  231         register struct pcred *pcred = curp->p_cred;
  232         struct rtprio rtp;
  233         int error;
  234 
  235         error = copyin(uap->rtp, &rtp, sizeof(struct rtprio));
  236         if (error)
  237                 return (error);
  238 
  239         if (uap->pid == 0)
  240                 p = curp;
  241         else
  242                 p = pfind(uap->pid);
  243 
  244         if (p == 0)
  245                 return (ESRCH);
  246 
  247         switch (uap->function) {
  248         case RTP_LOOKUP:
  249                 return (copyout(&p->p_rtprio, uap->rtp, sizeof(struct rtprio)));
  250         case RTP_SET:
  251                 if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
  252                     pcred->pc_ucred->cr_uid != p->p_ucred->cr_uid &&
  253                     pcred->p_ruid != p->p_ucred->cr_uid)
  254                         return (EPERM);
  255                 /* disallow setting rtprio in most cases if not superuser */
  256                 if (suser(pcred->pc_ucred, &curp->p_acflag)) {
  257                         /* can't set someone else's */
  258                         if (uap->pid)
  259                                 return (EPERM);
  260                         /* can't set realtime priority */
  261 /*
  262  * Realtime priority has to be restricted for reasons which should be
  263  * obvious. However, for idle priority, there is a potential for
  264  * system deadlock if an idleprio process gains a lock on a resource
  265  * that other processes need (and the idleprio process can't run
  266  * due to a CPU-bound normal process). Fix me! XXX
  267  */
  268 #if 0
  269                         if (RTP_PRIO_IS_REALTIME(rtp.type))
  270 #endif
  271                         if (rtp.type != RTP_PRIO_NORMAL)
  272                                 return (EPERM);
  273                 }
  274                 switch (rtp.type) {
  275 #ifdef RTP_PRIO_FIFO
  276                 case RTP_PRIO_FIFO:
  277 #endif
  278                 case RTP_PRIO_REALTIME:
  279                 case RTP_PRIO_NORMAL:
  280                 case RTP_PRIO_IDLE:
  281                         if (rtp.prio > RTP_PRIO_MAX)
  282                                 return (EINVAL);
  283                         p->p_rtprio = rtp;
  284                         return (0);
  285                 default:
  286                         return (EINVAL);
  287                 }
  288 
  289         default:
  290                 return (EINVAL);
  291         }
  292 }
  293 
  294 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
  295 #ifndef _SYS_SYSPROTO_H_
  296 struct osetrlimit_args {
  297         u_int   which;
  298         struct  orlimit *rlp;
  299 };
  300 #endif
  301 /* ARGSUSED */
  302 int
  303 osetrlimit(p, uap)
  304         struct proc *p;
  305         register struct osetrlimit_args *uap;
  306 {
  307         struct orlimit olim;
  308         struct rlimit lim;
  309         int error;
  310 
  311         if ((error =
  312             copyin((caddr_t)uap->rlp, (caddr_t)&olim, sizeof(struct orlimit))))
  313                 return (error);
  314         lim.rlim_cur = olim.rlim_cur;
  315         lim.rlim_max = olim.rlim_max;
  316         return (dosetrlimit(p, uap->which, &lim));
  317 }
  318 
  319 #ifndef _SYS_SYSPROTO_H_
  320 struct ogetrlimit_args {
  321         u_int   which;
  322         struct  orlimit *rlp;
  323 };
  324 #endif
  325 /* ARGSUSED */
  326 int
  327 ogetrlimit(p, uap)
  328         struct proc *p;
  329         register struct ogetrlimit_args *uap;
  330 {
  331         struct orlimit olim;
  332 
  333         if (uap->which >= RLIM_NLIMITS)
  334                 return (EINVAL);
  335         olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
  336         if (olim.rlim_cur == -1)
  337                 olim.rlim_cur = 0x7fffffff;
  338         olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
  339         if (olim.rlim_max == -1)
  340                 olim.rlim_max = 0x7fffffff;
  341         return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
  342 }
  343 #endif /* COMPAT_43 || COMPAT_SUNOS */
  344 
  345 #ifndef _SYS_SYSPROTO_H_
  346 struct __setrlimit_args {
  347         u_int   which;
  348         struct  rlimit *rlp;
  349 };
  350 #endif
  351 /* ARGSUSED */
  352 int
  353 setrlimit(p, uap)
  354         struct proc *p;
  355         register struct __setrlimit_args *uap;
  356 {
  357         struct rlimit alim;
  358         int error;
  359 
  360         if ((error =
  361             copyin((caddr_t)uap->rlp, (caddr_t)&alim, sizeof (struct rlimit))))
  362                 return (error);
  363         return (dosetrlimit(p, uap->which, &alim));
  364 }
  365 
  366 static int
  367 dosetrlimit(p, which, limp)
  368         struct proc *p;
  369         u_int which;
  370         struct rlimit *limp;
  371 {
  372         register 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(p->p_ucred, &p->p_acflag)))
  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                 break;
  460         }
  461         *alimp = *limp;
  462         return (0);
  463 }
  464 
  465 #ifndef _SYS_SYSPROTO_H_
  466 struct __getrlimit_args {
  467         u_int   which;
  468         struct  rlimit *rlp;
  469 };
  470 #endif
  471 /* ARGSUSED */
  472 int
  473 getrlimit(p, uap)
  474         struct proc *p;
  475         register struct __getrlimit_args *uap;
  476 {
  477 
  478         if (uap->which >= RLIM_NLIMITS)
  479                 return (EINVAL);
  480         return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
  481             sizeof (struct rlimit)));
  482 }
  483 
  484 /*
  485  * Transform the running time and tick information in proc p into user,
  486  * system, and interrupt time usage.
  487  */
  488 void
  489 calcru(p, up, sp, ip)
  490         struct proc *p;
  491         struct timeval *up;
  492         struct timeval *sp;
  493         struct timeval *ip;
  494 {
  495         int64_t totusec;
  496         u_int64_t u, st, ut, it, tot;
  497         int s;
  498         struct timeval tv;
  499 
  500         /* XXX: why spl-protect ?  worst case is an off-by-one report */
  501         s = splstatclock();
  502         st = p->p_sticks;
  503         ut = p->p_uticks;
  504         it = p->p_iticks;
  505         splx(s);
  506 
  507         tot = st + ut + it;
  508         if (tot == 0) {
  509                 st = 1;
  510                 tot = 1;
  511         }
  512 
  513         totusec = p->p_runtime;
  514 #ifdef SMP
  515         if (p->p_oncpu != (char)0xff) {
  516 #else
  517         if (p == curproc) {
  518 #endif
  519                 /*
  520                  * Adjust for the current time slice.  This is actually fairly
  521                  * important since the error here is on the order of a time
  522                  * quantum, which is much greater than the sampling error.
  523                  */
  524                 microuptime(&tv);
  525                 totusec += (tv.tv_usec - p->p_switchtime.tv_usec) +
  526                     (tv.tv_sec - p->p_switchtime.tv_sec) * (int64_t)1000000;
  527 
  528                 /*
  529                  * Copy the time that was just read to `switchtime' in case
  530                  * we are being called from exit1().  Exits don't go through
  531                  * mi_switch(), so `switchtime' doesn't get set in the normal
  532                  * way.  We set it here instead of more cleanly in exit1()
  533                  * to avoid losing track of the time between the calls to
  534                  * microuptime().  Similarly for `switchticks'.
  535                  */
  536                 switchtime = tv;
  537                 switchticks = ticks;
  538         }
  539         if (totusec < 0) {
  540                 /* XXX no %qd in kernel.  Truncate. */
  541                 printf("calcru: negative time of %ld usec for pid %d (%s)\n",
  542                        (long)totusec, p->p_pid, p->p_comm);
  543                 totusec = 0;
  544         }
  545         u = totusec;
  546         st = (u * st) / tot;
  547         sp->tv_sec = st / 1000000;
  548         sp->tv_usec = st % 1000000;
  549         ut = (u * ut) / tot;
  550         up->tv_sec = ut / 1000000;
  551         up->tv_usec = ut % 1000000;
  552         if (ip != NULL) {
  553                 it = (u * it) / tot;
  554                 ip->tv_sec = it / 1000000;
  555                 ip->tv_usec = it % 1000000;
  556         }
  557 }
  558 
  559 #ifndef _SYS_SYSPROTO_H_
  560 struct getrusage_args {
  561         int     who;
  562         struct  rusage *rusage;
  563 };
  564 #endif
  565 /* ARGSUSED */
  566 int
  567 getrusage(p, uap)
  568         register struct proc *p;
  569         register struct getrusage_args *uap;
  570 {
  571         register struct rusage *rup;
  572 
  573         switch (uap->who) {
  574 
  575         case RUSAGE_SELF:
  576                 rup = &p->p_stats->p_ru;
  577                 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
  578                 break;
  579 
  580         case RUSAGE_CHILDREN:
  581                 rup = &p->p_stats->p_cru;
  582                 break;
  583 
  584         default:
  585                 return (EINVAL);
  586         }
  587         return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
  588             sizeof (struct rusage)));
  589 }
  590 
  591 void
  592 ruadd(ru, ru2)
  593         register struct rusage *ru, *ru2;
  594 {
  595         register long *ip, *ip2;
  596         register int i;
  597 
  598         timevaladd(&ru->ru_utime, &ru2->ru_utime);
  599         timevaladd(&ru->ru_stime, &ru2->ru_stime);
  600         if (ru->ru_maxrss < ru2->ru_maxrss)
  601                 ru->ru_maxrss = ru2->ru_maxrss;
  602         ip = &ru->ru_first; ip2 = &ru2->ru_first;
  603         for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
  604                 *ip++ += *ip2++;
  605 }
  606 
  607 /*
  608  * Make a copy of the plimit structure.
  609  * We share these structures copy-on-write after fork,
  610  * and copy when a limit is changed.
  611  */
  612 struct plimit *
  613 limcopy(lim)
  614         struct plimit *lim;
  615 {
  616         register struct plimit *copy;
  617 
  618         MALLOC(copy, struct plimit *, sizeof(struct plimit),
  619             M_SUBPROC, M_WAITOK);
  620         bcopy(lim->pl_rlimit, copy->pl_rlimit, sizeof(struct plimit));
  621         copy->p_lflags = 0;
  622         copy->p_refcnt = 1;
  623         return (copy);
  624 }

Cache object: d38b544746975579b3c289b2292309eb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.