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: src/sys/kern/kern_resource.c,v 1.20.2.3 1999/09/05 08:15:02 peter Exp $
   40  */
   41 
   42 #include "opt_rlimit.h"
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/sysproto.h>
   47 #include <sys/kernel.h>
   48 #include <sys/file.h>
   49 #include <sys/resourcevar.h>
   50 #include <sys/malloc.h>
   51 #include <sys/proc.h>
   52 
   53 #include <vm/vm.h>
   54 #include <vm/vm_param.h>
   55 #include <vm/vm_prot.h>
   56 #include <vm/lock.h>
   57 #include <vm/pmap.h>
   58 #include <vm/vm_map.h>
   59 
   60 int     donice __P((struct proc *curp, struct proc *chgp, int n));
   61 int     dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
   62 
   63 /*
   64  * Resource controls and accounting.
   65  */
   66 
   67 #ifndef _SYS_SYSPROTO_H_
   68 struct getpriority_args {
   69         int     which;
   70         int     who;
   71 };
   72 #endif
   73 int
   74 getpriority(curp, uap, retval)
   75         struct proc *curp;
   76         register struct getpriority_args *uap;
   77         int *retval;
   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         *retval = 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, retval)
  137         struct proc *curp;
  138         register struct setpriority_args *uap;
  139         int *retval;
  140 {
  141         register struct proc *p;
  142         int found = 0, error = 0;
  143 
  144         switch (uap->which) {
  145 
  146         case PRIO_PROCESS:
  147                 if (uap->who == 0)
  148                         p = curp;
  149                 else
  150                         p = pfind(uap->who);
  151                 if (p == 0)
  152                         break;
  153                 error = donice(curp, p, uap->prio);
  154                 found++;
  155                 break;
  156 
  157         case PRIO_PGRP: {
  158                 register struct pgrp *pg;
  159 
  160                 if (uap->who == 0)
  161                         pg = curp->p_pgrp;
  162                 else if ((pg = pgfind(uap->who)) == NULL)
  163                         break;
  164                 for (p = pg->pg_members.lh_first; p != 0;
  165                     p = p->p_pglist.le_next) {
  166                         error = donice(curp, p, uap->prio);
  167                         found++;
  168                 }
  169                 break;
  170         }
  171 
  172         case PRIO_USER:
  173                 if (uap->who == 0)
  174                         uap->who = curp->p_ucred->cr_uid;
  175                 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
  176                         if (p->p_ucred->cr_uid == uap->who) {
  177                                 error = donice(curp, p, uap->prio);
  178                                 found++;
  179                         }
  180                 break;
  181 
  182         default:
  183                 return (EINVAL);
  184         }
  185         if (found == 0)
  186                 return (ESRCH);
  187         return (error);
  188 }
  189 
  190 int
  191 donice(curp, chgp, n)
  192         register struct proc *curp, *chgp;
  193         register int n;
  194 {
  195         register struct pcred *pcred = curp->p_cred;
  196 
  197         if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
  198             pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
  199             pcred->p_ruid != chgp->p_ucred->cr_uid)
  200                 return (EPERM);
  201         if (n > PRIO_MAX)
  202                 n = PRIO_MAX;
  203         if (n < PRIO_MIN)
  204                 n = PRIO_MIN;
  205         if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
  206                 return (EACCES);
  207         chgp->p_nice = n;
  208         (void)resetpriority(chgp);
  209         return (0);
  210 }
  211 
  212 /* rtprio system call */
  213 #ifndef _SYS_SYSPROTO_H_
  214 struct rtprio_args {
  215         int             function;
  216         pid_t           pid;
  217         struct rtprio   *rtp;
  218 };
  219 #endif
  220 
  221 /*
  222  * Set realtime priority
  223  */
  224 
  225 /* ARGSUSED */
  226 int
  227 rtprio(curp, uap, retval)
  228         struct proc *curp;
  229         register struct rtprio_args *uap;
  230         int *retval;
  231 {
  232         register struct proc *p;
  233         register struct pcred *pcred = curp->p_cred;
  234         struct rtprio rtp;
  235         int error;
  236 
  237         error = copyin(uap->rtp, &rtp, sizeof(struct rtprio));
  238         if (error)
  239                 return (error);
  240 
  241         if (uap->pid == 0)
  242                 p = curp;
  243         else
  244                 p = pfind(uap->pid);
  245 
  246         if (p == 0)
  247                 return (ESRCH);
  248 
  249         switch (uap->function) {
  250         case RTP_LOOKUP:
  251                 return (copyout(&p->p_rtprio, uap->rtp, sizeof(struct rtprio)));
  252         case RTP_SET:
  253                 if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
  254                     pcred->pc_ucred->cr_uid != p->p_ucred->cr_uid &&
  255                     pcred->p_ruid != p->p_ucred->cr_uid)
  256                         return (EPERM);
  257                 /* disallow setting rtprio in most cases if not superuser */
  258                 if (suser(pcred->pc_ucred, &curp->p_acflag)) {
  259                         /* can't set someone else's */
  260                         if (uap->pid)
  261                                 return (EPERM);
  262                         /* can't set realtime priority */
  263 /*
  264  * Realtime priority has to be restricted for reasons which should be
  265  * obvious. However, for idle priority, there is a potential for
  266  * system deadlock if an idleprio process gains a lock on a resource
  267  * that other processes need (and the idleprio process can't run
  268  * due to a CPU-bound normal process). Fix me! XXX
  269  */
  270 #if 0
  271                         if (rtp.type == RTP_PRIO_REALTIME)
  272 #endif
  273                         if (rtp.type != RTP_PRIO_NORMAL)
  274                                 return (EPERM);
  275                 }
  276                 switch (rtp.type) {
  277                 case RTP_PRIO_REALTIME:
  278                 case RTP_PRIO_NORMAL:
  279                 case RTP_PRIO_IDLE:
  280                         if (rtp.prio > RTP_PRIO_MAX)
  281                                 return (EINVAL);
  282                         p->p_rtprio = rtp;
  283                         return (0);
  284                 default:
  285                         return (EINVAL);
  286                 }
  287 
  288         default:
  289                 return (EINVAL);
  290         }
  291 }
  292 
  293 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
  294 #ifndef _SYS_SYSPROTO_H_
  295 struct osetrlimit_args {
  296         u_int   which;
  297         struct  orlimit *rlp;
  298 };
  299 #endif
  300 /* ARGSUSED */
  301 int
  302 osetrlimit(p, uap, retval)
  303         struct proc *p;
  304         register struct osetrlimit_args *uap;
  305         int *retval;
  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, retval)
  328         struct proc *p;
  329         register struct ogetrlimit_args *uap;
  330         int *retval;
  331 {
  332         struct orlimit olim;
  333 
  334         if (uap->which >= RLIM_NLIMITS)
  335                 return (EINVAL);
  336         olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
  337         if (olim.rlim_cur == -1)
  338                 olim.rlim_cur = 0x7fffffff;
  339         olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
  340         if (olim.rlim_max == -1)
  341                 olim.rlim_max = 0x7fffffff;
  342         return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
  343 }
  344 #endif /* COMPAT_43 || COMPAT_SUNOS */
  345 
  346 #ifndef _SYS_SYSPROTO_H_
  347 struct __setrlimit_args {
  348         u_int   which;
  349         struct  rlimit *rlp;
  350 };
  351 #endif
  352 /* ARGSUSED */
  353 int
  354 setrlimit(p, uap, retval)
  355         struct proc *p;
  356         register struct __setrlimit_args *uap;
  357         int *retval;
  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(p, uap->which, &alim));
  366 }
  367 
  368 int
  369 dosetrlimit(p, which, limp)
  370         struct proc *p;
  371         u_int which;
  372         struct rlimit *limp;
  373 {
  374         register struct rlimit *alimp;
  375         int error;
  376 
  377         if (which >= RLIM_NLIMITS)
  378                 return (EINVAL);
  379         alimp = &p->p_rlimit[which];
  380 
  381         /*
  382          * Preserve historical bugs by treating negative limits as unsigned.
  383          */
  384         if (limp->rlim_cur < 0)
  385                 limp->rlim_cur = RLIM_INFINITY;
  386         if (limp->rlim_max < 0)
  387                 limp->rlim_max = RLIM_INFINITY;
  388 
  389         if (limp->rlim_cur > alimp->rlim_max ||
  390             limp->rlim_max > alimp->rlim_max)
  391                 if ((error = suser(p->p_ucred, &p->p_acflag)))
  392                         return (error);
  393         if (limp->rlim_cur > limp->rlim_max)
  394                 limp->rlim_cur = limp->rlim_max;
  395         if (p->p_limit->p_refcnt > 1 &&
  396             (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
  397                 p->p_limit->p_refcnt--;
  398                 p->p_limit = limcopy(p->p_limit);
  399                 alimp = &p->p_rlimit[which];
  400         }
  401 
  402         switch (which) {
  403 
  404         case RLIMIT_DATA:
  405                 if (limp->rlim_cur > MAXDSIZ)
  406                         limp->rlim_cur = MAXDSIZ;
  407                 if (limp->rlim_max > MAXDSIZ)
  408                         limp->rlim_max = MAXDSIZ;
  409                 break;
  410 
  411         case RLIMIT_STACK:
  412                 if (limp->rlim_cur > MAXSSIZ)
  413                         limp->rlim_cur = MAXSSIZ;
  414                 if (limp->rlim_max > MAXSSIZ)
  415                         limp->rlim_max = MAXSSIZ;
  416                 /*
  417                  * Stack is allocated to the max at exec time with only
  418                  * "rlim_cur" bytes accessible.  If stack limit is going
  419                  * up make more accessible, if going down make inaccessible.
  420                  */
  421                 if (limp->rlim_cur != alimp->rlim_cur) {
  422                         vm_offset_t addr;
  423                         vm_size_t size;
  424                         vm_prot_t prot;
  425 
  426                         if (limp->rlim_cur > alimp->rlim_cur) {
  427                                 prot = VM_PROT_ALL;
  428                                 size = limp->rlim_cur - alimp->rlim_cur;
  429                                 addr = USRSTACK - limp->rlim_cur;
  430                         } else {
  431                                 prot = VM_PROT_NONE;
  432                                 size = alimp->rlim_cur - limp->rlim_cur;
  433                                 addr = USRSTACK - alimp->rlim_cur;
  434                         }
  435                         addr = trunc_page(addr);
  436                         size = round_page(size);
  437                         (void) vm_map_protect(&p->p_vmspace->vm_map,
  438                                               addr, addr+size, prot, FALSE);
  439                 }
  440                 break;
  441 
  442         case RLIMIT_NOFILE:
  443                 if (limp->rlim_cur > maxfilesperproc)
  444                         limp->rlim_cur = maxfilesperproc;
  445                 if (limp->rlim_max > maxfilesperproc)
  446                         limp->rlim_max = maxfilesperproc;
  447                 break;
  448 
  449         case RLIMIT_NPROC:
  450                 if (limp->rlim_cur > maxprocperuid)
  451                         limp->rlim_cur = maxprocperuid;
  452                 if (limp->rlim_max > maxprocperuid)
  453                         limp->rlim_max = maxprocperuid;
  454                 break;
  455         }
  456         *alimp = *limp;
  457         return (0);
  458 }
  459 
  460 #ifndef _SYS_SYSPROTO_H_
  461 struct __getrlimit_args {
  462         u_int   which;
  463         struct  rlimit *rlp;
  464 };
  465 #endif
  466 /* ARGSUSED */
  467 int
  468 getrlimit(p, uap, retval)
  469         struct proc *p;
  470         register struct __getrlimit_args *uap;
  471         int *retval;
  472 {
  473 
  474         if (uap->which >= RLIM_NLIMITS)
  475                 return (EINVAL);
  476         return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
  477             sizeof (struct rlimit)));
  478 }
  479 
  480 /*
  481  * Transform the running time and tick information in proc p into user,
  482  * system, and interrupt time usage.
  483  */
  484 void
  485 calcru(p, up, sp, ip)
  486         struct proc *p;
  487         struct timeval *up;
  488         struct timeval *sp;
  489         struct timeval *ip;
  490 {
  491         quad_t totusec;
  492         u_quad_t u, st, ut, it, tot;
  493         long sec, usec;
  494         int s;
  495         struct timeval tv;
  496 
  497         s = splstatclock();
  498         st = p->p_sticks;
  499         ut = p->p_uticks;
  500         it = p->p_iticks;
  501         splx(s);
  502 
  503         tot = st + ut + it;
  504         if (tot == 0) {
  505                 st = 1;
  506                 tot = 1;
  507         }
  508 
  509         sec = p->p_rtime.tv_sec;
  510         usec = p->p_rtime.tv_usec;
  511         if (p == curproc) {
  512                 /*
  513                  * Adjust for the current time slice.  This is actually fairly
  514                  * important since the error here is on the order of a time
  515                  * quantum, which is much greater than the sampling error.
  516                  */
  517                 microtime(&tv);
  518                 sec += tv.tv_sec - runtime.tv_sec;
  519                 usec += tv.tv_usec - runtime.tv_usec;
  520         }
  521         totusec = (quad_t)sec * 1000000 + usec;
  522         if (totusec < 0) {
  523                 /* XXX no %qd in kernel.  Truncate. */
  524                 printf("calcru: negative time: %ld usec\n", (long)totusec);
  525                 totusec = 0;
  526         }
  527         u = totusec;
  528         st = (u * st) / tot;
  529         sp->tv_sec = st / 1000000;
  530         sp->tv_usec = st % 1000000;
  531         ut = (u * ut) / tot;
  532         up->tv_sec = ut / 1000000;
  533         up->tv_usec = ut % 1000000;
  534         if (ip != NULL) {
  535                 it = (u * it) / tot;
  536                 ip->tv_sec = it / 1000000;
  537                 ip->tv_usec = it % 1000000;
  538         }
  539 }
  540 
  541 #ifndef _SYS_SYSPROTO_H_
  542 struct getrusage_args {
  543         int     who;
  544         struct  rusage *rusage;
  545 };
  546 #endif
  547 /* ARGSUSED */
  548 int
  549 getrusage(p, uap, retval)
  550         register struct proc *p;
  551         register struct getrusage_args *uap;
  552         int *retval;
  553 {
  554         register struct rusage *rup;
  555 
  556         switch (uap->who) {
  557 
  558         case RUSAGE_SELF:
  559                 rup = &p->p_stats->p_ru;
  560                 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
  561                 break;
  562 
  563         case RUSAGE_CHILDREN:
  564                 rup = &p->p_stats->p_cru;
  565                 break;
  566 
  567         default:
  568                 return (EINVAL);
  569         }
  570         return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
  571             sizeof (struct rusage)));
  572 }
  573 
  574 void
  575 ruadd(ru, ru2)
  576         register struct rusage *ru, *ru2;
  577 {
  578         register long *ip, *ip2;
  579         register int i;
  580 
  581         timevaladd(&ru->ru_utime, &ru2->ru_utime);
  582         timevaladd(&ru->ru_stime, &ru2->ru_stime);
  583         if (ru->ru_maxrss < ru2->ru_maxrss)
  584                 ru->ru_maxrss = ru2->ru_maxrss;
  585         ip = &ru->ru_first; ip2 = &ru2->ru_first;
  586         for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
  587                 *ip++ += *ip2++;
  588 }
  589 
  590 /*
  591  * Make a copy of the plimit structure.
  592  * We share these structures copy-on-write after fork,
  593  * and copy when a limit is changed.
  594  */
  595 struct plimit *
  596 limcopy(lim)
  597         struct plimit *lim;
  598 {
  599         register struct plimit *copy;
  600 
  601         MALLOC(copy, struct plimit *, sizeof(struct plimit),
  602             M_SUBPROC, M_WAITOK);
  603         bcopy(lim->pl_rlimit, copy->pl_rlimit,
  604             sizeof(struct rlimit) * RLIM_NLIMITS);
  605         copy->p_lflags = 0;
  606         copy->p_refcnt = 1;
  607         return (copy);
  608 }

Cache object: e53d9316797db622201eb5b7ed8a10fe


[ 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.