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 /*      $NetBSD: kern_resource.c,v 1.189 2022/04/09 23:38:33 riastradh Exp $    */
    2 
    3 /*-
    4  * Copyright (c) 1982, 1986, 1991, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  * (c) UNIX System Laboratories, Inc.
    7  * All or some portions of this file are derived from material licensed
    8  * to the University of California by American Telephone and Telegraph
    9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   10  * the permission of UNIX System Laboratories, Inc.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)kern_resource.c     8.8 (Berkeley) 2/14/95
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __KERNEL_RCSID(0, "$NetBSD: kern_resource.c,v 1.189 2022/04/09 23:38:33 riastradh Exp $");
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/kernel.h>
   45 #include <sys/file.h>
   46 #include <sys/resourcevar.h>
   47 #include <sys/kmem.h>
   48 #include <sys/namei.h>
   49 #include <sys/pool.h>
   50 #include <sys/proc.h>
   51 #include <sys/sysctl.h>
   52 #include <sys/timevar.h>
   53 #include <sys/kauth.h>
   54 #include <sys/atomic.h>
   55 #include <sys/mount.h>
   56 #include <sys/syscallargs.h>
   57 #include <sys/atomic.h>
   58 
   59 #include <uvm/uvm_extern.h>
   60 
   61 /*
   62  * Maximum process data and stack limits.
   63  * They are variables so they are patchable.
   64  */
   65 rlim_t                  maxdmap = MAXDSIZ;
   66 rlim_t                  maxsmap = MAXSSIZ;
   67 
   68 static pool_cache_t     plimit_cache    __read_mostly;
   69 static pool_cache_t     pstats_cache    __read_mostly;
   70 
   71 static kauth_listener_t resource_listener;
   72 static struct sysctllog *proc_sysctllog;
   73 
   74 static int      donice(struct lwp *, struct proc *, int);
   75 static void     sysctl_proc_setup(void);
   76 
   77 static int
   78 resource_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
   79     void *arg0, void *arg1, void *arg2, void *arg3)
   80 {
   81         struct proc *p;
   82         int result;
   83 
   84         result = KAUTH_RESULT_DEFER;
   85         p = arg0;
   86 
   87         switch (action) {
   88         case KAUTH_PROCESS_NICE:
   89                 if (kauth_cred_geteuid(cred) != kauth_cred_geteuid(p->p_cred) &&
   90                     kauth_cred_getuid(cred) != kauth_cred_geteuid(p->p_cred)) {
   91                         break;
   92                 }
   93 
   94                 if ((u_long)arg1 >= p->p_nice)
   95                         result = KAUTH_RESULT_ALLOW;
   96 
   97                 break;
   98 
   99         case KAUTH_PROCESS_RLIMIT: {
  100                 enum kauth_process_req req;
  101 
  102                 req = (enum kauth_process_req)(uintptr_t)arg1;
  103 
  104                 switch (req) {
  105                 case KAUTH_REQ_PROCESS_RLIMIT_GET:
  106                         result = KAUTH_RESULT_ALLOW;
  107                         break;
  108 
  109                 case KAUTH_REQ_PROCESS_RLIMIT_SET: {
  110                         struct rlimit *new_rlimit;
  111                         u_long which;
  112 
  113                         if ((p != curlwp->l_proc) &&
  114                             (proc_uidmatch(cred, p->p_cred) != 0))
  115                                 break;
  116 
  117                         new_rlimit = arg2;
  118                         which = (u_long)arg3;
  119 
  120                         if (new_rlimit->rlim_max <= p->p_rlimit[which].rlim_max)
  121                                 result = KAUTH_RESULT_ALLOW;
  122 
  123                         break;
  124                         }
  125 
  126                 default:
  127                         break;
  128                 }
  129 
  130                 break;
  131         }
  132 
  133         default:
  134                 break;
  135         }
  136 
  137         return result;
  138 }
  139 
  140 void
  141 resource_init(void)
  142 {
  143 
  144         plimit_cache = pool_cache_init(sizeof(struct plimit), 0, 0, 0,
  145             "plimitpl", NULL, IPL_NONE, NULL, NULL, NULL);
  146         pstats_cache = pool_cache_init(sizeof(struct pstats), 0, 0, 0,
  147             "pstatspl", NULL, IPL_NONE, NULL, NULL, NULL);
  148 
  149         resource_listener = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
  150             resource_listener_cb, NULL);
  151 
  152         sysctl_proc_setup();
  153 }
  154 
  155 /*
  156  * Resource controls and accounting.
  157  */
  158 
  159 int
  160 sys_getpriority(struct lwp *l, const struct sys_getpriority_args *uap,
  161     register_t *retval)
  162 {
  163         /* {
  164                 syscallarg(int) which;
  165                 syscallarg(id_t) who;
  166         } */
  167         struct proc *curp = l->l_proc, *p;
  168         id_t who = SCARG(uap, who);
  169         int low = NZERO + PRIO_MAX + 1;
  170 
  171         mutex_enter(&proc_lock);
  172         switch (SCARG(uap, which)) {
  173         case PRIO_PROCESS:
  174                 p = who ? proc_find(who) : curp;
  175                 if (p != NULL)
  176                         low = p->p_nice;
  177                 break;
  178 
  179         case PRIO_PGRP: {
  180                 struct pgrp *pg;
  181 
  182                 if (who == 0)
  183                         pg = curp->p_pgrp;
  184                 else if ((pg = pgrp_find(who)) == NULL)
  185                         break;
  186                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
  187                         if (p->p_nice < low)
  188                                 low = p->p_nice;
  189                 }
  190                 break;
  191         }
  192 
  193         case PRIO_USER:
  194                 if (who == 0)
  195                         who = (int)kauth_cred_geteuid(l->l_cred);
  196                 PROCLIST_FOREACH(p, &allproc) {
  197                         mutex_enter(p->p_lock);
  198                         if (kauth_cred_geteuid(p->p_cred) ==
  199                             (uid_t)who && p->p_nice < low)
  200                                 low = p->p_nice;
  201                         mutex_exit(p->p_lock);
  202                 }
  203                 break;
  204 
  205         default:
  206                 mutex_exit(&proc_lock);
  207                 return EINVAL;
  208         }
  209         mutex_exit(&proc_lock);
  210 
  211         if (low == NZERO + PRIO_MAX + 1) {
  212                 return ESRCH;
  213         }
  214         *retval = low - NZERO;
  215         return 0;
  216 }
  217 
  218 int
  219 sys_setpriority(struct lwp *l, const struct sys_setpriority_args *uap,
  220     register_t *retval)
  221 {
  222         /* {
  223                 syscallarg(int) which;
  224                 syscallarg(id_t) who;
  225                 syscallarg(int) prio;
  226         } */
  227         struct proc *curp = l->l_proc, *p;
  228         id_t who = SCARG(uap, who);
  229         int found = 0, error = 0;
  230 
  231         mutex_enter(&proc_lock);
  232         switch (SCARG(uap, which)) {
  233         case PRIO_PROCESS:
  234                 p = who ? proc_find(who) : curp;
  235                 if (p != NULL) {
  236                         mutex_enter(p->p_lock);
  237                         found++;
  238                         error = donice(l, p, SCARG(uap, prio));
  239                         mutex_exit(p->p_lock);
  240                 }
  241                 break;
  242 
  243         case PRIO_PGRP: {
  244                 struct pgrp *pg;
  245 
  246                 if (who == 0)
  247                         pg = curp->p_pgrp;
  248                 else if ((pg = pgrp_find(who)) == NULL)
  249                         break;
  250                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
  251                         mutex_enter(p->p_lock);
  252                         found++;
  253                         error = donice(l, p, SCARG(uap, prio));
  254                         mutex_exit(p->p_lock);
  255                         if (error)
  256                                 break;
  257                 }
  258                 break;
  259         }
  260 
  261         case PRIO_USER:
  262                 if (who == 0)
  263                         who = (int)kauth_cred_geteuid(l->l_cred);
  264                 PROCLIST_FOREACH(p, &allproc) {
  265                         mutex_enter(p->p_lock);
  266                         if (kauth_cred_geteuid(p->p_cred) ==
  267                             (uid_t)SCARG(uap, who)) {
  268                                 found++;
  269                                 error = donice(l, p, SCARG(uap, prio));
  270                         }
  271                         mutex_exit(p->p_lock);
  272                         if (error)
  273                                 break;
  274                 }
  275                 break;
  276 
  277         default:
  278                 mutex_exit(&proc_lock);
  279                 return EINVAL;
  280         }
  281         mutex_exit(&proc_lock);
  282 
  283         return (found == 0) ? ESRCH : error;
  284 }
  285 
  286 /*
  287  * Renice a process.
  288  *
  289  * Call with the target process' credentials locked.
  290  */
  291 static int
  292 donice(struct lwp *l, struct proc *chgp, int n)
  293 {
  294         kauth_cred_t cred = l->l_cred;
  295 
  296         KASSERT(mutex_owned(chgp->p_lock));
  297 
  298         if (kauth_cred_geteuid(cred) && kauth_cred_getuid(cred) &&
  299             kauth_cred_geteuid(cred) != kauth_cred_geteuid(chgp->p_cred) &&
  300             kauth_cred_getuid(cred) != kauth_cred_geteuid(chgp->p_cred))
  301                 return EPERM;
  302 
  303         if (n > PRIO_MAX) {
  304                 n = PRIO_MAX;
  305         }
  306         if (n < PRIO_MIN) {
  307                 n = PRIO_MIN;
  308         }
  309         n += NZERO;
  310 
  311         if (kauth_authorize_process(cred, KAUTH_PROCESS_NICE, chgp,
  312             KAUTH_ARG(n), NULL, NULL)) {
  313                 return EACCES;
  314         }
  315 
  316         sched_nice(chgp, n);
  317         return 0;
  318 }
  319 
  320 int
  321 sys_setrlimit(struct lwp *l, const struct sys_setrlimit_args *uap,
  322     register_t *retval)
  323 {
  324         /* {
  325                 syscallarg(int) which;
  326                 syscallarg(const struct rlimit *) rlp;
  327         } */
  328         int error, which = SCARG(uap, which);
  329         struct rlimit alim;
  330 
  331         error = copyin(SCARG(uap, rlp), &alim, sizeof(struct rlimit));
  332         if (error) {
  333                 return error;
  334         }
  335         return dosetrlimit(l, l->l_proc, which, &alim);
  336 }
  337 
  338 int
  339 dosetrlimit(struct lwp *l, struct proc *p, int which, struct rlimit *limp)
  340 {
  341         struct rlimit *alimp;
  342         int error;
  343 
  344         if ((u_int)which >= RLIM_NLIMITS)
  345                 return EINVAL;
  346 
  347         if (limp->rlim_cur > limp->rlim_max) {
  348                 /*
  349                  * This is programming error. According to SUSv2, we should
  350                  * return error in this case.
  351                  */
  352                 return EINVAL;
  353         }
  354 
  355         alimp = &p->p_rlimit[which];
  356         /* if we don't change the value, no need to limcopy() */
  357         if (limp->rlim_cur == alimp->rlim_cur &&
  358             limp->rlim_max == alimp->rlim_max)
  359                 return 0;
  360 
  361         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_RLIMIT,
  362             p, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_SET), limp, KAUTH_ARG(which));
  363         if (error)
  364                 return error;
  365 
  366         lim_privatise(p);
  367         /* p->p_limit is now unchangeable */
  368         alimp = &p->p_rlimit[which];
  369 
  370         switch (which) {
  371 
  372         case RLIMIT_DATA:
  373                 if (limp->rlim_cur > maxdmap)
  374                         limp->rlim_cur = maxdmap;
  375                 if (limp->rlim_max > maxdmap)
  376                         limp->rlim_max = maxdmap;
  377                 break;
  378 
  379         case RLIMIT_STACK:
  380                 if (limp->rlim_cur > maxsmap)
  381                         limp->rlim_cur = maxsmap;
  382                 if (limp->rlim_max > maxsmap)
  383                         limp->rlim_max = maxsmap;
  384 
  385                 /*
  386                  * Return EINVAL if the new stack size limit is lower than
  387                  * current usage. Otherwise, the process would get SIGSEGV the
  388                  * moment it would try to access anything on its current stack.
  389                  * This conforms to SUSv2.
  390                  */
  391                 if (btoc(limp->rlim_cur) < p->p_vmspace->vm_ssize ||
  392                     btoc(limp->rlim_max) < p->p_vmspace->vm_ssize) {
  393                         return EINVAL;
  394                 }
  395 
  396                 /*
  397                  * Stack is allocated to the max at exec time with
  398                  * only "rlim_cur" bytes accessible (In other words,
  399                  * allocates stack dividing two contiguous regions at
  400                  * "rlim_cur" bytes boundary).
  401                  *
  402                  * Since allocation is done in terms of page, roundup
  403                  * "rlim_cur" (otherwise, contiguous regions
  404                  * overlap).  If stack limit is going up make more
  405                  * accessible, if going down make inaccessible.
  406                  */
  407                 limp->rlim_max = round_page(limp->rlim_max);
  408                 limp->rlim_cur = round_page(limp->rlim_cur);
  409                 if (limp->rlim_cur != alimp->rlim_cur) {
  410                         vaddr_t addr;
  411                         vsize_t size;
  412                         vm_prot_t prot;
  413                         char *base, *tmp;
  414 
  415                         base = p->p_vmspace->vm_minsaddr;
  416                         if (limp->rlim_cur > alimp->rlim_cur) {
  417                                 prot = VM_PROT_READ | VM_PROT_WRITE;
  418                                 size = limp->rlim_cur - alimp->rlim_cur;
  419                                 tmp = STACK_GROW(base, alimp->rlim_cur);
  420                         } else {
  421                                 prot = VM_PROT_NONE;
  422                                 size = alimp->rlim_cur - limp->rlim_cur;
  423                                 tmp = STACK_GROW(base, limp->rlim_cur);
  424                         }
  425                         addr = (vaddr_t)STACK_ALLOC(tmp, size);
  426                         (void) uvm_map_protect(&p->p_vmspace->vm_map,
  427                             addr, addr + size, prot, false);
  428                 }
  429                 break;
  430 
  431         case RLIMIT_NOFILE:
  432                 if (limp->rlim_cur > maxfiles)
  433                         limp->rlim_cur = maxfiles;
  434                 if (limp->rlim_max > maxfiles)
  435                         limp->rlim_max = maxfiles;
  436                 break;
  437 
  438         case RLIMIT_NPROC:
  439                 if (limp->rlim_cur > maxproc)
  440                         limp->rlim_cur = maxproc;
  441                 if (limp->rlim_max > maxproc)
  442                         limp->rlim_max = maxproc;
  443                 break;
  444 
  445         case RLIMIT_NTHR:
  446                 if (limp->rlim_cur > maxlwp)
  447                         limp->rlim_cur = maxlwp;
  448                 if (limp->rlim_max > maxlwp)
  449                         limp->rlim_max = maxlwp;
  450                 break;
  451         }
  452 
  453         mutex_enter(&p->p_limit->pl_lock);
  454         *alimp = *limp;
  455         mutex_exit(&p->p_limit->pl_lock);
  456         return 0;
  457 }
  458 
  459 int
  460 sys_getrlimit(struct lwp *l, const struct sys_getrlimit_args *uap,
  461     register_t *retval)
  462 {
  463         /* {
  464                 syscallarg(int) which;
  465                 syscallarg(struct rlimit *) rlp;
  466         } */
  467         struct proc *p = l->l_proc;
  468         int which = SCARG(uap, which);
  469         struct rlimit rl;
  470 
  471         if ((u_int)which >= RLIM_NLIMITS)
  472                 return EINVAL;
  473 
  474         mutex_enter(p->p_lock);
  475         memcpy(&rl, &p->p_rlimit[which], sizeof(rl));
  476         mutex_exit(p->p_lock);
  477 
  478         return copyout(&rl, SCARG(uap, rlp), sizeof(rl));
  479 }
  480 
  481 /*
  482  * Transform the running time and tick information in proc p into user,
  483  * system, and interrupt time usage.
  484  *
  485  * Should be called with p->p_lock held unless called from exit1().
  486  */
  487 void
  488 calcru(struct proc *p, struct timeval *up, struct timeval *sp,
  489     struct timeval *ip, struct timeval *rp)
  490 {
  491         uint64_t u, st, ut, it, tot, dt;
  492         struct lwp *l;
  493         struct bintime tm;
  494         struct timeval tv;
  495 
  496         KASSERT(p->p_stat == SDEAD || mutex_owned(p->p_lock));
  497 
  498         mutex_spin_enter(&p->p_stmutex);
  499         st = p->p_sticks;
  500         ut = p->p_uticks;
  501         it = p->p_iticks;
  502         mutex_spin_exit(&p->p_stmutex);
  503 
  504         tm = p->p_rtime;
  505 
  506         LIST_FOREACH(l, &p->p_lwps, l_sibling) {
  507                 lwp_lock(l);
  508                 bintime_add(&tm, &l->l_rtime);
  509                 if ((l->l_pflag & LP_RUNNING) != 0 &&
  510                     (l->l_pflag & (LP_INTR | LP_TIMEINTR)) != LP_INTR) {
  511                         struct bintime diff;
  512                         /*
  513                          * Adjust for the current time slice.  This is
  514                          * actually fairly important since the error
  515                          * here is on the order of a time quantum,
  516                          * which is much greater than the sampling
  517                          * error.
  518                          */
  519                         binuptime(&diff);
  520                         membar_consumer(); /* for softint_dispatch() */
  521                         bintime_sub(&diff, &l->l_stime);
  522                         bintime_add(&tm, &diff);
  523                 }
  524                 lwp_unlock(l);
  525         }
  526 
  527         tot = st + ut + it;
  528         bintime2timeval(&tm, &tv);
  529         u = (uint64_t)tv.tv_sec * 1000000ul + tv.tv_usec;
  530 
  531         if (tot == 0) {
  532                 /* No ticks, so can't use to share time out, split 50-50 */
  533                 st = ut = u / 2;
  534         } else {
  535                 st = (u * st) / tot;
  536                 ut = (u * ut) / tot;
  537         }
  538 
  539         /*
  540          * Try to avoid lying to the users (too much)
  541          *
  542          * Of course, user/sys time are based on sampling (ie: statistics)
  543          * so that would be impossible, but convincing the mark
  544          * that we have used less ?time this call than we had
  545          * last time, is beyond reasonable...  (the con fails!)
  546          *
  547          * Note that since actual used time cannot decrease, either
  548          * utime or stime (or both) must be greater now than last time
  549          * (or both the same) - if one seems to have decreased, hold
  550          * it constant and steal the necessary bump from the other
  551          * which must have increased.
  552          */
  553         if (p->p_xutime > ut) {
  554                 dt = p->p_xutime - ut;
  555                 st -= uimin(dt, st);
  556                 ut = p->p_xutime;
  557         } else if (p->p_xstime > st) {
  558                 dt = p->p_xstime - st;
  559                 ut -= uimin(dt, ut);
  560                 st = p->p_xstime;
  561         }
  562 
  563         if (sp != NULL) {
  564                 p->p_xstime = st;
  565                 sp->tv_sec = st / 1000000;
  566                 sp->tv_usec = st % 1000000;
  567         }
  568         if (up != NULL) {
  569                 p->p_xutime = ut;
  570                 up->tv_sec = ut / 1000000;
  571                 up->tv_usec = ut % 1000000;
  572         }
  573         if (ip != NULL) {
  574                 if (it != 0)            /* it != 0 --> tot != 0 */
  575                         it = (u * it) / tot;
  576                 ip->tv_sec = it / 1000000;
  577                 ip->tv_usec = it % 1000000;
  578         }
  579         if (rp != NULL) {
  580                 *rp = tv;
  581         }
  582 }
  583 
  584 int
  585 sys___getrusage50(struct lwp *l, const struct sys___getrusage50_args *uap,
  586     register_t *retval)
  587 {
  588         /* {
  589                 syscallarg(int) who;
  590                 syscallarg(struct rusage *) rusage;
  591         } */
  592         int error;
  593         struct rusage ru;
  594         struct proc *p = l->l_proc;
  595 
  596         error = getrusage1(p, SCARG(uap, who), &ru);
  597         if (error != 0)
  598                 return error;
  599 
  600         return copyout(&ru, SCARG(uap, rusage), sizeof(ru));
  601 }
  602 
  603 int
  604 getrusage1(struct proc *p, int who, struct rusage *ru) {
  605 
  606         switch (who) {
  607         case RUSAGE_SELF:
  608                 mutex_enter(p->p_lock);
  609                 ruspace(p);
  610                 memcpy(ru, &p->p_stats->p_ru, sizeof(*ru));
  611                 calcru(p, &ru->ru_utime, &ru->ru_stime, NULL, NULL);
  612                 rulwps(p, ru);
  613                 mutex_exit(p->p_lock);
  614                 break;
  615         case RUSAGE_CHILDREN:
  616                 mutex_enter(p->p_lock);
  617                 memcpy(ru, &p->p_stats->p_cru, sizeof(*ru));
  618                 mutex_exit(p->p_lock);
  619                 break;
  620         default:
  621                 return EINVAL;
  622         }
  623 
  624         return 0;
  625 }
  626 
  627 void
  628 ruspace(struct proc *p)
  629 {
  630         struct vmspace *vm = p->p_vmspace;
  631         struct rusage *ru = &p->p_stats->p_ru;
  632 
  633         ru->ru_ixrss = vm->vm_tsize << (PAGE_SHIFT - 10);
  634         ru->ru_idrss = vm->vm_dsize << (PAGE_SHIFT - 10);
  635         ru->ru_isrss = vm->vm_ssize << (PAGE_SHIFT - 10);
  636 #ifdef __HAVE_NO_PMAP_STATS
  637         /* We don't keep track of the max so we get the current */
  638         ru->ru_maxrss = vm_resident_count(vm) << (PAGE_SHIFT - 10);
  639 #else
  640         ru->ru_maxrss = vm->vm_rssmax << (PAGE_SHIFT - 10);
  641 #endif
  642 }
  643 
  644 void
  645 ruadd(struct rusage *ru, struct rusage *ru2)
  646 {
  647         long *ip, *ip2;
  648         int i;
  649 
  650         timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
  651         timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
  652         if (ru->ru_maxrss < ru2->ru_maxrss)
  653                 ru->ru_maxrss = ru2->ru_maxrss;
  654         ip = &ru->ru_first; ip2 = &ru2->ru_first;
  655         for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
  656                 *ip++ += *ip2++;
  657 }
  658 
  659 void
  660 rulwps(proc_t *p, struct rusage *ru)
  661 {
  662         lwp_t *l;
  663 
  664         KASSERT(mutex_owned(p->p_lock));
  665 
  666         LIST_FOREACH(l, &p->p_lwps, l_sibling) {
  667                 ruadd(ru, &l->l_ru);
  668                 ru->ru_nvcsw += (l->l_ncsw - l->l_nivcsw);
  669                 ru->ru_nivcsw += l->l_nivcsw;
  670         }
  671 }
  672 
  673 /*
  674  * lim_copy: make a copy of the plimit structure.
  675  *
  676  * We use copy-on-write after fork, and copy when a limit is changed.
  677  */
  678 struct plimit *
  679 lim_copy(struct plimit *lim)
  680 {
  681         struct plimit *newlim;
  682         char *corename;
  683         size_t alen, len;
  684 
  685         newlim = pool_cache_get(plimit_cache, PR_WAITOK);
  686         mutex_init(&newlim->pl_lock, MUTEX_DEFAULT, IPL_NONE);
  687         newlim->pl_writeable = false;
  688         newlim->pl_refcnt = 1;
  689         newlim->pl_sv_limit = NULL;
  690 
  691         mutex_enter(&lim->pl_lock);
  692         memcpy(newlim->pl_rlimit, lim->pl_rlimit,
  693             sizeof(struct rlimit) * RLIM_NLIMITS);
  694 
  695         /*
  696          * Note: the common case is a use of default core name.
  697          */
  698         alen = 0;
  699         corename = NULL;
  700         for (;;) {
  701                 if (lim->pl_corename == defcorename) {
  702                         newlim->pl_corename = defcorename;
  703                         newlim->pl_cnlen = 0;
  704                         break;
  705                 }
  706                 len = lim->pl_cnlen;
  707                 if (len == alen) {
  708                         newlim->pl_corename = corename;
  709                         newlim->pl_cnlen = len;
  710                         memcpy(corename, lim->pl_corename, len);
  711                         corename = NULL;
  712                         break;
  713                 }
  714                 mutex_exit(&lim->pl_lock);
  715                 if (corename) {
  716                         kmem_free(corename, alen);
  717                 }
  718                 alen = len;
  719                 corename = kmem_alloc(alen, KM_SLEEP);
  720                 mutex_enter(&lim->pl_lock);
  721         }
  722         mutex_exit(&lim->pl_lock);
  723 
  724         if (corename) {
  725                 kmem_free(corename, alen);
  726         }
  727         return newlim;
  728 }
  729 
  730 void
  731 lim_addref(struct plimit *lim)
  732 {
  733         atomic_inc_uint(&lim->pl_refcnt);
  734 }
  735 
  736 /*
  737  * lim_privatise: give a process its own private plimit structure.
  738  */
  739 void
  740 lim_privatise(proc_t *p)
  741 {
  742         struct plimit *lim = p->p_limit, *newlim;
  743 
  744         if (lim->pl_writeable) {
  745                 return;
  746         }
  747 
  748         newlim = lim_copy(lim);
  749 
  750         mutex_enter(p->p_lock);
  751         if (p->p_limit->pl_writeable) {
  752                 /* Other thread won the race. */
  753                 mutex_exit(p->p_lock);
  754                 lim_free(newlim);
  755                 return;
  756         }
  757 
  758         /*
  759          * Since p->p_limit can be accessed without locked held,
  760          * old limit structure must not be deleted yet.
  761          */
  762         newlim->pl_sv_limit = p->p_limit;
  763         newlim->pl_writeable = true;
  764         p->p_limit = newlim;
  765         mutex_exit(p->p_lock);
  766 }
  767 
  768 void
  769 lim_setcorename(proc_t *p, char *name, size_t len)
  770 {
  771         struct plimit *lim;
  772         char *oname;
  773         size_t olen;
  774 
  775         lim_privatise(p);
  776         lim = p->p_limit;
  777 
  778         mutex_enter(&lim->pl_lock);
  779         oname = lim->pl_corename;
  780         olen = lim->pl_cnlen;
  781         lim->pl_corename = name;
  782         lim->pl_cnlen = len;
  783         mutex_exit(&lim->pl_lock);
  784 
  785         if (oname != defcorename) {
  786                 kmem_free(oname, olen);
  787         }
  788 }
  789 
  790 void
  791 lim_free(struct plimit *lim)
  792 {
  793         struct plimit *sv_lim;
  794 
  795         do {
  796                 membar_release();
  797                 if (atomic_dec_uint_nv(&lim->pl_refcnt) > 0) {
  798                         return;
  799                 }
  800                 membar_acquire();
  801                 if (lim->pl_corename != defcorename) {
  802                         kmem_free(lim->pl_corename, lim->pl_cnlen);
  803                 }
  804                 sv_lim = lim->pl_sv_limit;
  805                 mutex_destroy(&lim->pl_lock);
  806                 pool_cache_put(plimit_cache, lim);
  807         } while ((lim = sv_lim) != NULL);
  808 }
  809 
  810 struct pstats *
  811 pstatscopy(struct pstats *ps)
  812 {
  813         struct pstats *nps;
  814         size_t len;
  815 
  816         nps = pool_cache_get(pstats_cache, PR_WAITOK);
  817 
  818         len = (char *)&nps->pstat_endzero - (char *)&nps->pstat_startzero;
  819         memset(&nps->pstat_startzero, 0, len);
  820 
  821         len = (char *)&nps->pstat_endcopy - (char *)&nps->pstat_startcopy;
  822         memcpy(&nps->pstat_startcopy, &ps->pstat_startcopy, len);
  823 
  824         return nps;
  825 }
  826 
  827 void
  828 pstatsfree(struct pstats *ps)
  829 {
  830 
  831         pool_cache_put(pstats_cache, ps);
  832 }
  833 
  834 /*
  835  * sysctl_proc_findproc: a routine for sysctl proc subtree helpers that
  836  * need to pick a valid process by PID.
  837  *
  838  * => Hold a reference on the process, on success.
  839  */
  840 static int
  841 sysctl_proc_findproc(lwp_t *l, pid_t pid, proc_t **p2)
  842 {
  843         proc_t *p;
  844         int error;
  845 
  846         if (pid == PROC_CURPROC) {
  847                 p = l->l_proc;
  848         } else {
  849                 mutex_enter(&proc_lock);
  850                 p = proc_find(pid);
  851                 if (p == NULL) {
  852                         mutex_exit(&proc_lock);
  853                         return ESRCH;
  854                 }
  855         }
  856         error = rw_tryenter(&p->p_reflock, RW_READER) ? 0 : EBUSY;
  857         if (pid != PROC_CURPROC) {
  858                 mutex_exit(&proc_lock);
  859         }
  860         *p2 = p;
  861         return error;
  862 }
  863 
  864 /*
  865  * sysctl_proc_paxflags: helper routine to get process's paxctl flags
  866  */
  867 static int
  868 sysctl_proc_paxflags(SYSCTLFN_ARGS)
  869 {
  870         struct proc *p;
  871         struct sysctlnode node;
  872         int paxflags;
  873         int error;
  874 
  875         /* First, validate the request. */
  876         if (namelen != 0 || name[-1] != PROC_PID_PAXFLAGS)
  877                 return EINVAL;
  878 
  879         /* Find the process.  Hold a reference (p_reflock), if found. */
  880         error = sysctl_proc_findproc(l, (pid_t)name[-2], &p);
  881         if (error)
  882                 return error;
  883 
  884         /* XXX-elad */
  885         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE, p,
  886             KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
  887         if (error) {
  888                 rw_exit(&p->p_reflock);
  889                 return error;
  890         }
  891 
  892         /* Retrieve the limits. */
  893         node = *rnode;
  894         paxflags = p->p_pax;
  895         node.sysctl_data = &paxflags;
  896 
  897         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  898 
  899         /* If attempting to write new value, it's an error */
  900         if (error == 0 && newp != NULL)
  901                 error = EACCES;
  902 
  903         rw_exit(&p->p_reflock);
  904         return error;
  905 }
  906 
  907 /*
  908  * sysctl_proc_corename: helper routine to get or set the core file name
  909  * for a process specified by PID.
  910  */
  911 static int
  912 sysctl_proc_corename(SYSCTLFN_ARGS)
  913 {
  914         struct proc *p;
  915         struct plimit *lim;
  916         char *cnbuf, *cname;
  917         struct sysctlnode node;
  918         size_t len;
  919         int error;
  920 
  921         /* First, validate the request. */
  922         if (namelen != 0 || name[-1] != PROC_PID_CORENAME)
  923                 return EINVAL;
  924 
  925         /* Find the process.  Hold a reference (p_reflock), if found. */
  926         error = sysctl_proc_findproc(l, (pid_t)name[-2], &p);
  927         if (error)
  928                 return error;
  929 
  930         /* XXX-elad */
  931         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE, p,
  932             KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
  933         if (error) {
  934                 rw_exit(&p->p_reflock);
  935                 return error;
  936         }
  937 
  938         cnbuf = PNBUF_GET();
  939 
  940         if (oldp) {
  941                 /* Get case: copy the core name into the buffer. */
  942                 error = kauth_authorize_process(l->l_cred,
  943                     KAUTH_PROCESS_CORENAME, p,
  944                     KAUTH_ARG(KAUTH_REQ_PROCESS_CORENAME_GET), NULL, NULL);
  945                 if (error) {
  946                         goto done;
  947                 }
  948                 lim = p->p_limit;
  949                 mutex_enter(&lim->pl_lock);
  950                 strlcpy(cnbuf, lim->pl_corename, MAXPATHLEN);
  951                 mutex_exit(&lim->pl_lock);
  952         }
  953 
  954         node = *rnode;
  955         node.sysctl_data = cnbuf;
  956         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  957 
  958         /* Return if error, or if caller is only getting the core name. */
  959         if (error || newp == NULL) {
  960                 goto done;
  961         }
  962 
  963         /*
  964          * Set case.  Check permission and then validate new core name.
  965          * It must be either "core", "/core", or end in ".core".
  966          */
  967         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CORENAME,
  968             p, KAUTH_ARG(KAUTH_REQ_PROCESS_CORENAME_SET), cnbuf, NULL);
  969         if (error) {
  970                 goto done;
  971         }
  972         len = strlen(cnbuf);
  973         if ((len < 4 || strcmp(cnbuf + len - 4, "core") != 0) ||
  974             (len > 4 && cnbuf[len - 5] != '/' && cnbuf[len - 5] != '.')) {
  975                 error = EINVAL;
  976                 goto done;
  977         }
  978 
  979         /* Allocate, copy and set the new core name for plimit structure. */
  980         cname = kmem_alloc(++len, KM_NOSLEEP);
  981         if (cname == NULL) {
  982                 error = ENOMEM;
  983                 goto done;
  984         }
  985         memcpy(cname, cnbuf, len);
  986         lim_setcorename(p, cname, len);
  987 done:
  988         rw_exit(&p->p_reflock);
  989         PNBUF_PUT(cnbuf);
  990         return error;
  991 }
  992 
  993 /*
  994  * sysctl_proc_stop: helper routine for checking/setting the stop flags.
  995  */
  996 static int
  997 sysctl_proc_stop(SYSCTLFN_ARGS)
  998 {
  999         struct proc *p;
 1000         int isset, flag, error = 0;
 1001         struct sysctlnode node;
 1002 
 1003         if (namelen != 0)
 1004                 return EINVAL;
 1005 
 1006         /* Find the process.  Hold a reference (p_reflock), if found. */
 1007         error = sysctl_proc_findproc(l, (pid_t)name[-2], &p);
 1008         if (error)
 1009                 return error;
 1010 
 1011         /* XXX-elad */
 1012         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE, p,
 1013             KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
 1014         if (error) {
 1015                 goto out;
 1016         }
 1017 
 1018         /* Determine the flag. */
 1019         switch (rnode->sysctl_num) {
 1020         case PROC_PID_STOPFORK:
 1021                 flag = PS_STOPFORK;
 1022                 break;
 1023         case PROC_PID_STOPEXEC:
 1024                 flag = PS_STOPEXEC;
 1025                 break;
 1026         case PROC_PID_STOPEXIT:
 1027                 flag = PS_STOPEXIT;
 1028                 break;
 1029         default:
 1030                 error = EINVAL;
 1031                 goto out;
 1032         }
 1033         isset = (p->p_flag & flag) ? 1 : 0;
 1034         node = *rnode;
 1035         node.sysctl_data = &isset;
 1036         error = sysctl_lookup(SYSCTLFN_CALL(&node));
 1037 
 1038         /* Return if error, or if callers is only getting the flag. */
 1039         if (error || newp == NULL) {
 1040                 goto out;
 1041         }
 1042 
 1043         /* Check if caller can set the flags. */
 1044         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_STOPFLAG,
 1045             p, KAUTH_ARG(flag), NULL, NULL);
 1046         if (error) {
 1047                 goto out;
 1048         }
 1049         mutex_enter(p->p_lock);
 1050         if (isset) {
 1051                 p->p_sflag |= flag;
 1052         } else {
 1053                 p->p_sflag &= ~flag;
 1054         }
 1055         mutex_exit(p->p_lock);
 1056 out:
 1057         rw_exit(&p->p_reflock);
 1058         return error;
 1059 }
 1060 
 1061 /*
 1062  * sysctl_proc_plimit: helper routine to get/set rlimits of a process.
 1063  */
 1064 static int
 1065 sysctl_proc_plimit(SYSCTLFN_ARGS)
 1066 {
 1067         struct proc *p;
 1068         u_int limitno;
 1069         int which, error = 0;
 1070         struct rlimit alim;
 1071         struct sysctlnode node;
 1072 
 1073         if (namelen != 0)
 1074                 return EINVAL;
 1075 
 1076         which = name[-1];
 1077         if (which != PROC_PID_LIMIT_TYPE_SOFT &&
 1078             which != PROC_PID_LIMIT_TYPE_HARD)
 1079                 return EINVAL;
 1080 
 1081         limitno = name[-2] - 1;
 1082         if (limitno >= RLIM_NLIMITS)
 1083                 return EINVAL;
 1084 
 1085         if (name[-3] != PROC_PID_LIMIT)
 1086                 return EINVAL;
 1087 
 1088         /* Find the process.  Hold a reference (p_reflock), if found. */
 1089         error = sysctl_proc_findproc(l, (pid_t)name[-4], &p);
 1090         if (error)
 1091                 return error;
 1092 
 1093         /* XXX-elad */
 1094         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE, p,
 1095             KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
 1096         if (error)
 1097                 goto out;
 1098 
 1099         /* Check if caller can retrieve the limits. */
 1100         if (newp == NULL) {
 1101                 error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_RLIMIT,
 1102                     p, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_GET), &alim,
 1103                     KAUTH_ARG(which));
 1104                 if (error)
 1105                         goto out;
 1106         }
 1107 
 1108         /* Retrieve the limits. */
 1109         node = *rnode;
 1110         memcpy(&alim, &p->p_rlimit[limitno], sizeof(alim));
 1111         if (which == PROC_PID_LIMIT_TYPE_HARD) {
 1112                 node.sysctl_data = &alim.rlim_max;
 1113         } else {
 1114                 node.sysctl_data = &alim.rlim_cur;
 1115         }
 1116         error = sysctl_lookup(SYSCTLFN_CALL(&node));
 1117 
 1118         /* Return if error, or if we are only retrieving the limits. */
 1119         if (error || newp == NULL) {
 1120                 goto out;
 1121         }
 1122         error = dosetrlimit(l, p, limitno, &alim);
 1123 out:
 1124         rw_exit(&p->p_reflock);
 1125         return error;
 1126 }
 1127 
 1128 /*
 1129  * Setup sysctl nodes.
 1130  */
 1131 static void
 1132 sysctl_proc_setup(void)
 1133 {
 1134 
 1135         sysctl_createv(&proc_sysctllog, 0, NULL, NULL,
 1136                        CTLFLAG_PERMANENT|CTLFLAG_ANYNUMBER,
 1137                        CTLTYPE_NODE, "curproc",
 1138                        SYSCTL_DESCR("Per-process settings"),
 1139                        NULL, 0, NULL, 0,
 1140                        CTL_PROC, PROC_CURPROC, CTL_EOL);
 1141 
 1142         sysctl_createv(&proc_sysctllog, 0, NULL, NULL,
 1143                        CTLFLAG_PERMANENT|CTLFLAG_READONLY,
 1144                        CTLTYPE_INT, "paxflags",
 1145                        SYSCTL_DESCR("Process PAX control flags"),
 1146                        sysctl_proc_paxflags, 0, NULL, 0,
 1147                        CTL_PROC, PROC_CURPROC, PROC_PID_PAXFLAGS, CTL_EOL);
 1148 
 1149         sysctl_createv(&proc_sysctllog, 0, NULL, NULL,
 1150                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
 1151                        CTLTYPE_STRING, "corename",
 1152                        SYSCTL_DESCR("Core file name"),
 1153                        sysctl_proc_corename, 0, NULL, MAXPATHLEN,
 1154                        CTL_PROC, PROC_CURPROC, PROC_PID_CORENAME, CTL_EOL);
 1155         sysctl_createv(&proc_sysctllog, 0, NULL, NULL,
 1156                        CTLFLAG_PERMANENT,
 1157                        CTLTYPE_NODE, "rlimit",
 1158                        SYSCTL_DESCR("Process limits"),
 1159                        NULL, 0, NULL, 0,
 1160                        CTL_PROC, PROC_CURPROC, PROC_PID_LIMIT, CTL_EOL);
 1161 
 1162 #define create_proc_plimit(s, n) do {                                   \
 1163         sysctl_createv(&proc_sysctllog, 0, NULL, NULL,                  \
 1164                        CTLFLAG_PERMANENT,                               \
 1165                        CTLTYPE_NODE, s,                                 \
 1166                        SYSCTL_DESCR("Process " s " limits"),            \
 1167                        NULL, 0, NULL, 0,                                \
 1168                        CTL_PROC, PROC_CURPROC, PROC_PID_LIMIT, n,       \
 1169                        CTL_EOL);                                        \
 1170         sysctl_createv(&proc_sysctllog, 0, NULL, NULL,                  \
 1171                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE, \
 1172                        CTLTYPE_QUAD, "soft",                            \
 1173                        SYSCTL_DESCR("Process soft " s " limit"),        \
 1174                        sysctl_proc_plimit, 0, NULL, 0,                  \
 1175                        CTL_PROC, PROC_CURPROC, PROC_PID_LIMIT, n,       \
 1176                        PROC_PID_LIMIT_TYPE_SOFT, CTL_EOL);              \
 1177         sysctl_createv(&proc_sysctllog, 0, NULL, NULL,                  \
 1178                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE, \
 1179                        CTLTYPE_QUAD, "hard",                            \
 1180                        SYSCTL_DESCR("Process hard " s " limit"),        \
 1181                        sysctl_proc_plimit, 0, NULL, 0,                  \
 1182                        CTL_PROC, PROC_CURPROC, PROC_PID_LIMIT, n,       \
 1183                        PROC_PID_LIMIT_TYPE_HARD, CTL_EOL);              \
 1184         } while (0/*CONSTCOND*/)
 1185 
 1186         create_proc_plimit("cputime",           PROC_PID_LIMIT_CPU);
 1187         create_proc_plimit("filesize",          PROC_PID_LIMIT_FSIZE);
 1188         create_proc_plimit("datasize",          PROC_PID_LIMIT_DATA);
 1189         create_proc_plimit("stacksize",         PROC_PID_LIMIT_STACK);
 1190         create_proc_plimit("coredumpsize",      PROC_PID_LIMIT_CORE);
 1191         create_proc_plimit("memoryuse",         PROC_PID_LIMIT_RSS);
 1192         create_proc_plimit("memorylocked",      PROC_PID_LIMIT_MEMLOCK);
 1193         create_proc_plimit("maxproc",           PROC_PID_LIMIT_NPROC);
 1194         create_proc_plimit("descriptors",       PROC_PID_LIMIT_NOFILE);
 1195         create_proc_plimit("sbsize",            PROC_PID_LIMIT_SBSIZE);
 1196         create_proc_plimit("vmemoryuse",        PROC_PID_LIMIT_AS);
 1197         create_proc_plimit("maxlwp",            PROC_PID_LIMIT_NTHR);
 1198 
 1199 #undef create_proc_plimit
 1200 
 1201         sysctl_createv(&proc_sysctllog, 0, NULL, NULL,
 1202                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
 1203                        CTLTYPE_INT, "stopfork",
 1204                        SYSCTL_DESCR("Stop process at fork(2)"),
 1205                        sysctl_proc_stop, 0, NULL, 0,
 1206                        CTL_PROC, PROC_CURPROC, PROC_PID_STOPFORK, CTL_EOL);
 1207         sysctl_createv(&proc_sysctllog, 0, NULL, NULL,
 1208                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
 1209                        CTLTYPE_INT, "stopexec",
 1210                        SYSCTL_DESCR("Stop process at execve(2)"),
 1211                        sysctl_proc_stop, 0, NULL, 0,
 1212                        CTL_PROC, PROC_CURPROC, PROC_PID_STOPEXEC, CTL_EOL);
 1213         sysctl_createv(&proc_sysctllog, 0, NULL, NULL,
 1214                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
 1215                        CTLTYPE_INT, "stopexit",
 1216                        SYSCTL_DESCR("Stop process before completing exit"),
 1217                        sysctl_proc_stop, 0, NULL, 0,
 1218                        CTL_PROC, PROC_CURPROC, PROC_PID_STOPEXIT, CTL_EOL);
 1219 }

Cache object: bf391cec60dad6899c6ee4cb9f0861d0


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