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_rctl.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) 2010 The FreeBSD Foundation
    3  * All rights reserved.
    4  *
    5  * This software was developed by Edward Tomasz Napierala under sponsorship
    6  * from the FreeBSD Foundation.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  * $FreeBSD: releng/10.3/sys/kern/kern_rctl.c 284665 2015-06-21 06:28:26Z trasz $
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD: releng/10.3/sys/kern/kern_rctl.c 284665 2015-06-21 06:28:26Z trasz $");
   34 
   35 #include <sys/param.h>
   36 #include <sys/bus.h>
   37 #include <sys/malloc.h>
   38 #include <sys/queue.h>
   39 #include <sys/refcount.h>
   40 #include <sys/jail.h>
   41 #include <sys/kernel.h>
   42 #include <sys/limits.h>
   43 #include <sys/loginclass.h>
   44 #include <sys/priv.h>
   45 #include <sys/proc.h>
   46 #include <sys/racct.h>
   47 #include <sys/rctl.h>
   48 #include <sys/resourcevar.h>
   49 #include <sys/sx.h>
   50 #include <sys/sysent.h>
   51 #include <sys/sysproto.h>
   52 #include <sys/systm.h>
   53 #include <sys/types.h>
   54 #include <sys/eventhandler.h>
   55 #include <sys/lock.h>
   56 #include <sys/mutex.h>
   57 #include <sys/rwlock.h>
   58 #include <sys/sbuf.h>
   59 #include <sys/taskqueue.h>
   60 #include <sys/tree.h>
   61 #include <vm/uma.h>
   62 
   63 #ifdef RCTL
   64 #ifndef RACCT
   65 #error "The RCTL option requires the RACCT option"
   66 #endif
   67 
   68 FEATURE(rctl, "Resource Limits");
   69 
   70 #define HRF_DEFAULT             0
   71 #define HRF_DONT_INHERIT        1
   72 #define HRF_DONT_ACCUMULATE     2
   73 
   74 /* Default buffer size for rctl_get_rules(2). */
   75 #define RCTL_DEFAULT_BUFSIZE    4096
   76 #define RCTL_MAX_INBUFLEN       4096
   77 #define RCTL_LOG_BUFSIZE        128
   78 
   79 #define RCTL_PCPU_SHIFT         (10 * 1000000)
   80 
   81 /*
   82  * 'rctl_rule_link' connects a rule with every racct it's related to.
   83  * For example, rule 'user:X:openfiles:deny=N/process' is linked
   84  * with uidinfo for user X, and to each process of that user.
   85  */
   86 struct rctl_rule_link {
   87         LIST_ENTRY(rctl_rule_link)      rrl_next;
   88         struct rctl_rule                *rrl_rule;
   89         int                             rrl_exceeded;
   90 };
   91 
   92 struct dict {
   93         const char      *d_name;
   94         int             d_value;
   95 };
   96 
   97 static struct dict subjectnames[] = {
   98         { "process", RCTL_SUBJECT_TYPE_PROCESS },
   99         { "user", RCTL_SUBJECT_TYPE_USER },
  100         { "loginclass", RCTL_SUBJECT_TYPE_LOGINCLASS },
  101         { "jail", RCTL_SUBJECT_TYPE_JAIL },
  102         { NULL, -1 }};
  103 
  104 static struct dict resourcenames[] = {
  105         { "cputime", RACCT_CPU },
  106         { "datasize", RACCT_DATA },
  107         { "stacksize", RACCT_STACK },
  108         { "coredumpsize", RACCT_CORE },
  109         { "memoryuse", RACCT_RSS },
  110         { "memorylocked", RACCT_MEMLOCK },
  111         { "maxproc", RACCT_NPROC },
  112         { "openfiles", RACCT_NOFILE },
  113         { "vmemoryuse", RACCT_VMEM },
  114         { "pseudoterminals", RACCT_NPTS },
  115         { "swapuse", RACCT_SWAP },
  116         { "nthr", RACCT_NTHR },
  117         { "msgqqueued", RACCT_MSGQQUEUED },
  118         { "msgqsize", RACCT_MSGQSIZE },
  119         { "nmsgq", RACCT_NMSGQ },
  120         { "nsem", RACCT_NSEM },
  121         { "nsemop", RACCT_NSEMOP },
  122         { "nshm", RACCT_NSHM },
  123         { "shmsize", RACCT_SHMSIZE },
  124         { "wallclock", RACCT_WALLCLOCK },
  125         { "pcpu", RACCT_PCTCPU },
  126         { NULL, -1 }};
  127 
  128 static struct dict actionnames[] = {
  129         { "sighup", RCTL_ACTION_SIGHUP },
  130         { "sigint", RCTL_ACTION_SIGINT },
  131         { "sigquit", RCTL_ACTION_SIGQUIT },
  132         { "sigill", RCTL_ACTION_SIGILL },
  133         { "sigtrap", RCTL_ACTION_SIGTRAP },
  134         { "sigabrt", RCTL_ACTION_SIGABRT },
  135         { "sigemt", RCTL_ACTION_SIGEMT },
  136         { "sigfpe", RCTL_ACTION_SIGFPE },
  137         { "sigkill", RCTL_ACTION_SIGKILL },
  138         { "sigbus", RCTL_ACTION_SIGBUS },
  139         { "sigsegv", RCTL_ACTION_SIGSEGV },
  140         { "sigsys", RCTL_ACTION_SIGSYS },
  141         { "sigpipe", RCTL_ACTION_SIGPIPE },
  142         { "sigalrm", RCTL_ACTION_SIGALRM },
  143         { "sigterm", RCTL_ACTION_SIGTERM },
  144         { "sigurg", RCTL_ACTION_SIGURG },
  145         { "sigstop", RCTL_ACTION_SIGSTOP },
  146         { "sigtstp", RCTL_ACTION_SIGTSTP },
  147         { "sigchld", RCTL_ACTION_SIGCHLD },
  148         { "sigttin", RCTL_ACTION_SIGTTIN },
  149         { "sigttou", RCTL_ACTION_SIGTTOU },
  150         { "sigio", RCTL_ACTION_SIGIO },
  151         { "sigxcpu", RCTL_ACTION_SIGXCPU },
  152         { "sigxfsz", RCTL_ACTION_SIGXFSZ },
  153         { "sigvtalrm", RCTL_ACTION_SIGVTALRM },
  154         { "sigprof", RCTL_ACTION_SIGPROF },
  155         { "sigwinch", RCTL_ACTION_SIGWINCH },
  156         { "siginfo", RCTL_ACTION_SIGINFO },
  157         { "sigusr1", RCTL_ACTION_SIGUSR1 },
  158         { "sigusr2", RCTL_ACTION_SIGUSR2 },
  159         { "sigthr", RCTL_ACTION_SIGTHR },
  160         { "deny", RCTL_ACTION_DENY },
  161         { "log", RCTL_ACTION_LOG },
  162         { "devctl", RCTL_ACTION_DEVCTL },
  163         { NULL, -1 }};
  164 
  165 static void rctl_init(void);
  166 SYSINIT(rctl, SI_SUB_RACCT, SI_ORDER_FIRST, rctl_init, NULL);
  167 
  168 static uma_zone_t rctl_rule_link_zone;
  169 static uma_zone_t rctl_rule_zone;
  170 static struct rwlock rctl_lock;
  171 RW_SYSINIT(rctl_lock, &rctl_lock, "RCTL lock");
  172 
  173 static int rctl_rule_fully_specified(const struct rctl_rule *rule);
  174 static void rctl_rule_to_sbuf(struct sbuf *sb, const struct rctl_rule *rule);
  175 
  176 static MALLOC_DEFINE(M_RCTL, "rctl", "Resource Limits");
  177 
  178 static const char *
  179 rctl_subject_type_name(int subject)
  180 {
  181         int i;
  182 
  183         for (i = 0; subjectnames[i].d_name != NULL; i++) {
  184                 if (subjectnames[i].d_value == subject)
  185                         return (subjectnames[i].d_name);
  186         }
  187 
  188         panic("rctl_subject_type_name: unknown subject type %d", subject);
  189 }
  190 
  191 static const char *
  192 rctl_action_name(int action)
  193 {
  194         int i;
  195 
  196         for (i = 0; actionnames[i].d_name != NULL; i++) {
  197                 if (actionnames[i].d_value == action)
  198                         return (actionnames[i].d_name);
  199         }
  200 
  201         panic("rctl_action_name: unknown action %d", action);
  202 }
  203 
  204 const char *
  205 rctl_resource_name(int resource)
  206 {
  207         int i;
  208 
  209         for (i = 0; resourcenames[i].d_name != NULL; i++) {
  210                 if (resourcenames[i].d_value == resource)
  211                         return (resourcenames[i].d_name);
  212         }
  213 
  214         panic("rctl_resource_name: unknown resource %d", resource);
  215 }
  216 
  217 /*
  218  * Return the amount of resource that can be allocated by 'p' before
  219  * hitting 'rule'.
  220  */
  221 static int64_t
  222 rctl_available_resource(const struct proc *p, const struct rctl_rule *rule)
  223 {
  224         int resource;
  225         int64_t available = INT64_MAX;
  226         struct ucred *cred = p->p_ucred;
  227 
  228         ASSERT_RACCT_ENABLED();
  229         rw_assert(&rctl_lock, RA_LOCKED);
  230 
  231         resource = rule->rr_resource;
  232         switch (rule->rr_per) {
  233         case RCTL_SUBJECT_TYPE_PROCESS:
  234                 available = rule->rr_amount -
  235                     p->p_racct->r_resources[resource];
  236                 break;
  237         case RCTL_SUBJECT_TYPE_USER:
  238                 available = rule->rr_amount -
  239                     cred->cr_ruidinfo->ui_racct->r_resources[resource];
  240                 break;
  241         case RCTL_SUBJECT_TYPE_LOGINCLASS:
  242                 available = rule->rr_amount -
  243                     cred->cr_loginclass->lc_racct->r_resources[resource];
  244                 break;
  245         case RCTL_SUBJECT_TYPE_JAIL:
  246                 available = rule->rr_amount -
  247                     cred->cr_prison->pr_prison_racct->prr_racct->
  248                         r_resources[resource];
  249                 break;
  250         default:
  251                 panic("rctl_compute_available: unknown per %d",
  252                     rule->rr_per);
  253         }
  254 
  255         return (available);
  256 }
  257 
  258 /*
  259  * Return non-zero if allocating 'amount' by proc 'p' would exceed
  260  * resource limit specified by 'rule'.
  261  */
  262 static int
  263 rctl_would_exceed(const struct proc *p, const struct rctl_rule *rule,
  264     int64_t amount)
  265 {
  266         int64_t available;
  267 
  268         ASSERT_RACCT_ENABLED();
  269 
  270         rw_assert(&rctl_lock, RA_LOCKED);
  271 
  272         available = rctl_available_resource(p, rule);
  273         if (available >= amount)
  274                 return (0);
  275 
  276         return (1);
  277 }
  278 
  279 /*
  280  * Special version of rctl_available() function for the %cpu resource.
  281  * We slightly cheat here and return less than we normally would.
  282  */
  283 int64_t
  284 rctl_pcpu_available(const struct proc *p) {
  285         struct rctl_rule *rule;
  286         struct rctl_rule_link *link;
  287         int64_t available, minavailable, limit;
  288 
  289         ASSERT_RACCT_ENABLED();
  290 
  291         minavailable = INT64_MAX;
  292         limit = 0;
  293 
  294         rw_rlock(&rctl_lock);
  295 
  296         LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
  297                 rule = link->rrl_rule;
  298                 if (rule->rr_resource != RACCT_PCTCPU)
  299                         continue;
  300                 if (rule->rr_action != RCTL_ACTION_DENY)
  301                         continue;
  302                 available = rctl_available_resource(p, rule);
  303                 if (available < minavailable) {
  304                         minavailable = available;
  305                         limit = rule->rr_amount;
  306                 }
  307         }
  308 
  309         rw_runlock(&rctl_lock);
  310 
  311         /*
  312          * Return slightly less than actual value of the available
  313          * %cpu resource.  This makes %cpu throttling more agressive
  314          * and lets us act sooner than the limits are already exceeded.
  315          */
  316         if (limit != 0) {
  317                 if (limit > 2 * RCTL_PCPU_SHIFT)
  318                         minavailable -= RCTL_PCPU_SHIFT;
  319                 else
  320                         minavailable -= (limit / 2);
  321         }
  322 
  323         return (minavailable);
  324 }
  325 
  326 /*
  327  * Check whether the proc 'p' can allocate 'amount' of 'resource' in addition
  328  * to what it keeps allocated now.  Returns non-zero if the allocation should
  329  * be denied, 0 otherwise.
  330  */
  331 int
  332 rctl_enforce(struct proc *p, int resource, uint64_t amount)
  333 {
  334         struct rctl_rule *rule;
  335         struct rctl_rule_link *link;
  336         struct sbuf sb;
  337         int should_deny = 0;
  338         char *buf;
  339         static int curtime = 0;
  340         static struct timeval lasttime;
  341 
  342         ASSERT_RACCT_ENABLED();
  343 
  344         rw_rlock(&rctl_lock);
  345 
  346         /*
  347          * There may be more than one matching rule; go through all of them.
  348          * Denial should be done last, after logging and sending signals.
  349          */
  350         LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
  351                 rule = link->rrl_rule;
  352                 if (rule->rr_resource != resource)
  353                         continue;
  354                 if (!rctl_would_exceed(p, rule, amount)) {
  355                         link->rrl_exceeded = 0;
  356                         continue;
  357                 }
  358 
  359                 switch (rule->rr_action) {
  360                 case RCTL_ACTION_DENY:
  361                         should_deny = 1;
  362                         continue;
  363                 case RCTL_ACTION_LOG:
  364                         /*
  365                          * If rrl_exceeded != 0, it means we've already
  366                          * logged a warning for this process.
  367                          */
  368                         if (link->rrl_exceeded != 0)
  369                                 continue;
  370 
  371                         /*
  372                          * If the process state is not fully initialized yet,
  373                          * we can't access most of the required fields, e.g.
  374                          * p->p_comm.  This happens when called from fork1().
  375                          * Ignore this rule for now; it will be processed just
  376                          * after fork, when called from racct_proc_fork_done().
  377                          */
  378                         if (p->p_state != PRS_NORMAL)
  379                                 continue;
  380 
  381                         if (!ppsratecheck(&lasttime, &curtime, 10))
  382                                 continue;
  383 
  384                         buf = malloc(RCTL_LOG_BUFSIZE, M_RCTL, M_NOWAIT);
  385                         if (buf == NULL) {
  386                                 printf("rctl_enforce: out of memory\n");
  387                                 continue;
  388                         }
  389                         sbuf_new(&sb, buf, RCTL_LOG_BUFSIZE, SBUF_FIXEDLEN);
  390                         rctl_rule_to_sbuf(&sb, rule);
  391                         sbuf_finish(&sb);
  392                         printf("rctl: rule \"%s\" matched by pid %d "
  393                             "(%s), uid %d, jail %s\n", sbuf_data(&sb),
  394                             p->p_pid, p->p_comm, p->p_ucred->cr_uid,
  395                             p->p_ucred->cr_prison->pr_prison_racct->prr_name);
  396                         sbuf_delete(&sb);
  397                         free(buf, M_RCTL);
  398                         link->rrl_exceeded = 1;
  399                         continue;
  400                 case RCTL_ACTION_DEVCTL:
  401                         if (link->rrl_exceeded != 0)
  402                                 continue;
  403 
  404                         if (p->p_state != PRS_NORMAL)
  405                                 continue;
  406         
  407                         buf = malloc(RCTL_LOG_BUFSIZE, M_RCTL, M_NOWAIT);
  408                         if (buf == NULL) {
  409                                 printf("rctl_enforce: out of memory\n");
  410                                 continue;
  411                         }
  412                         sbuf_new(&sb, buf, RCTL_LOG_BUFSIZE, SBUF_FIXEDLEN);
  413                         sbuf_printf(&sb, "rule=");
  414                         rctl_rule_to_sbuf(&sb, rule);
  415                         sbuf_printf(&sb, " pid=%d ruid=%d jail=%s",
  416                             p->p_pid, p->p_ucred->cr_ruid,
  417                             p->p_ucred->cr_prison->pr_prison_racct->prr_name);
  418                         sbuf_finish(&sb);
  419                         devctl_notify_f("RCTL", "rule", "matched",
  420                             sbuf_data(&sb), M_NOWAIT);
  421                         sbuf_delete(&sb);
  422                         free(buf, M_RCTL);
  423                         link->rrl_exceeded = 1;
  424                         continue;
  425                 default:
  426                         if (link->rrl_exceeded != 0)
  427                                 continue;
  428 
  429                         if (p->p_state != PRS_NORMAL)
  430                                 continue;
  431 
  432                         KASSERT(rule->rr_action > 0 &&
  433                             rule->rr_action <= RCTL_ACTION_SIGNAL_MAX,
  434                             ("rctl_enforce: unknown action %d",
  435                              rule->rr_action));
  436 
  437                         /*
  438                          * We're using the fact that RCTL_ACTION_SIG* values
  439                          * are equal to their counterparts from sys/signal.h.
  440                          */
  441                         kern_psignal(p, rule->rr_action);
  442                         link->rrl_exceeded = 1;
  443                         continue;
  444                 }
  445         }
  446 
  447         rw_runlock(&rctl_lock);
  448 
  449         if (should_deny) {
  450                 /*
  451                  * Return fake error code; the caller should change it
  452                  * into one proper for the situation - EFSIZ, ENOMEM etc.
  453                  */
  454                 return (EDOOFUS);
  455         }
  456 
  457         return (0);
  458 }
  459 
  460 uint64_t
  461 rctl_get_limit(struct proc *p, int resource)
  462 {
  463         struct rctl_rule *rule;
  464         struct rctl_rule_link *link;
  465         uint64_t amount = UINT64_MAX;
  466 
  467         ASSERT_RACCT_ENABLED();
  468 
  469         rw_rlock(&rctl_lock);
  470 
  471         /*
  472          * There may be more than one matching rule; go through all of them.
  473          * Denial should be done last, after logging and sending signals.
  474          */
  475         LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
  476                 rule = link->rrl_rule;
  477                 if (rule->rr_resource != resource)
  478                         continue;
  479                 if (rule->rr_action != RCTL_ACTION_DENY)
  480                         continue;
  481                 if (rule->rr_amount < amount)
  482                         amount = rule->rr_amount;
  483         }
  484 
  485         rw_runlock(&rctl_lock);
  486 
  487         return (amount);
  488 }
  489 
  490 uint64_t
  491 rctl_get_available(struct proc *p, int resource)
  492 {
  493         struct rctl_rule *rule;
  494         struct rctl_rule_link *link;
  495         int64_t available, minavailable, allocated;
  496 
  497         minavailable = INT64_MAX;
  498 
  499         ASSERT_RACCT_ENABLED();
  500 
  501         rw_rlock(&rctl_lock);
  502 
  503         /*
  504          * There may be more than one matching rule; go through all of them.
  505          * Denial should be done last, after logging and sending signals.
  506          */
  507         LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
  508                 rule = link->rrl_rule;
  509                 if (rule->rr_resource != resource)
  510                         continue;
  511                 if (rule->rr_action != RCTL_ACTION_DENY)
  512                         continue;
  513                 available = rctl_available_resource(p, rule);
  514                 if (available < minavailable)
  515                         minavailable = available;
  516         }
  517 
  518         rw_runlock(&rctl_lock);
  519 
  520         /*
  521          * XXX: Think about this _hard_.
  522          */
  523         allocated = p->p_racct->r_resources[resource];
  524         if (minavailable < INT64_MAX - allocated)
  525                 minavailable += allocated;
  526         if (minavailable < 0)
  527                 minavailable = 0;
  528         return (minavailable);
  529 }
  530 
  531 static int
  532 rctl_rule_matches(const struct rctl_rule *rule, const struct rctl_rule *filter)
  533 {
  534 
  535         ASSERT_RACCT_ENABLED();
  536 
  537         if (filter->rr_subject_type != RCTL_SUBJECT_TYPE_UNDEFINED) {
  538                 if (rule->rr_subject_type != filter->rr_subject_type)
  539                         return (0);
  540 
  541                 switch (filter->rr_subject_type) {
  542                 case RCTL_SUBJECT_TYPE_PROCESS:
  543                         if (filter->rr_subject.rs_proc != NULL &&
  544                             rule->rr_subject.rs_proc !=
  545                             filter->rr_subject.rs_proc)
  546                                 return (0);
  547                         break;
  548                 case RCTL_SUBJECT_TYPE_USER:
  549                         if (filter->rr_subject.rs_uip != NULL &&
  550                             rule->rr_subject.rs_uip !=
  551                             filter->rr_subject.rs_uip)
  552                                 return (0);
  553                         break;
  554                 case RCTL_SUBJECT_TYPE_LOGINCLASS:
  555                         if (filter->rr_subject.rs_loginclass != NULL &&
  556                             rule->rr_subject.rs_loginclass !=
  557                             filter->rr_subject.rs_loginclass)
  558                                 return (0);
  559                         break;
  560                 case RCTL_SUBJECT_TYPE_JAIL:
  561                         if (filter->rr_subject.rs_prison_racct != NULL &&
  562                             rule->rr_subject.rs_prison_racct !=
  563                             filter->rr_subject.rs_prison_racct)
  564                                 return (0);
  565                         break;
  566                 default:
  567                         panic("rctl_rule_matches: unknown subject type %d",
  568                             filter->rr_subject_type);
  569                 }
  570         }
  571 
  572         if (filter->rr_resource != RACCT_UNDEFINED) {
  573                 if (rule->rr_resource != filter->rr_resource)
  574                         return (0);
  575         }
  576 
  577         if (filter->rr_action != RCTL_ACTION_UNDEFINED) {
  578                 if (rule->rr_action != filter->rr_action)
  579                         return (0);
  580         }
  581 
  582         if (filter->rr_amount != RCTL_AMOUNT_UNDEFINED) {
  583                 if (rule->rr_amount != filter->rr_amount)
  584                         return (0);
  585         }
  586 
  587         if (filter->rr_per != RCTL_SUBJECT_TYPE_UNDEFINED) {
  588                 if (rule->rr_per != filter->rr_per)
  589                         return (0);
  590         }
  591 
  592         return (1);
  593 }
  594 
  595 static int
  596 str2value(const char *str, int *value, struct dict *table)
  597 {
  598         int i;
  599 
  600         if (value == NULL)
  601                 return (EINVAL);
  602 
  603         for (i = 0; table[i].d_name != NULL; i++) {
  604                 if (strcasecmp(table[i].d_name, str) == 0) {
  605                         *value =  table[i].d_value;
  606                         return (0);
  607                 }
  608         }
  609 
  610         return (EINVAL);
  611 }
  612 
  613 static int
  614 str2id(const char *str, id_t *value)
  615 {
  616         char *end;
  617 
  618         if (str == NULL)
  619                 return (EINVAL);
  620 
  621         *value = strtoul(str, &end, 10);
  622         if ((size_t)(end - str) != strlen(str))
  623                 return (EINVAL);
  624 
  625         return (0);
  626 }
  627 
  628 static int
  629 str2int64(const char *str, int64_t *value)
  630 {
  631         char *end;
  632 
  633         if (str == NULL)
  634                 return (EINVAL);
  635 
  636         *value = strtoul(str, &end, 10);
  637         if ((size_t)(end - str) != strlen(str))
  638                 return (EINVAL);
  639 
  640         return (0);
  641 }
  642 
  643 /*
  644  * Connect the rule to the racct, increasing refcount for the rule.
  645  */
  646 static void
  647 rctl_racct_add_rule(struct racct *racct, struct rctl_rule *rule)
  648 {
  649         struct rctl_rule_link *link;
  650 
  651         ASSERT_RACCT_ENABLED();
  652         KASSERT(rctl_rule_fully_specified(rule), ("rule not fully specified"));
  653 
  654         rctl_rule_acquire(rule);
  655         link = uma_zalloc(rctl_rule_link_zone, M_WAITOK);
  656         link->rrl_rule = rule;
  657         link->rrl_exceeded = 0;
  658 
  659         rw_wlock(&rctl_lock);
  660         LIST_INSERT_HEAD(&racct->r_rule_links, link, rrl_next);
  661         rw_wunlock(&rctl_lock);
  662 }
  663 
  664 static int
  665 rctl_racct_add_rule_locked(struct racct *racct, struct rctl_rule *rule)
  666 {
  667         struct rctl_rule_link *link;
  668 
  669         ASSERT_RACCT_ENABLED();
  670         KASSERT(rctl_rule_fully_specified(rule), ("rule not fully specified"));
  671         rw_assert(&rctl_lock, RA_WLOCKED);
  672 
  673         link = uma_zalloc(rctl_rule_link_zone, M_NOWAIT);
  674         if (link == NULL)
  675                 return (ENOMEM);
  676         rctl_rule_acquire(rule);
  677         link->rrl_rule = rule;
  678         link->rrl_exceeded = 0;
  679 
  680         LIST_INSERT_HEAD(&racct->r_rule_links, link, rrl_next);
  681         return (0);
  682 }
  683 
  684 /*
  685  * Remove limits for a rules matching the filter and release
  686  * the refcounts for the rules, possibly freeing them.  Returns
  687  * the number of limit structures removed.
  688  */
  689 static int
  690 rctl_racct_remove_rules(struct racct *racct,
  691     const struct rctl_rule *filter)
  692 {
  693         int removed = 0;
  694         struct rctl_rule_link *link, *linktmp;
  695 
  696         ASSERT_RACCT_ENABLED();
  697         rw_assert(&rctl_lock, RA_WLOCKED);
  698 
  699         LIST_FOREACH_SAFE(link, &racct->r_rule_links, rrl_next, linktmp) {
  700                 if (!rctl_rule_matches(link->rrl_rule, filter))
  701                         continue;
  702 
  703                 LIST_REMOVE(link, rrl_next);
  704                 rctl_rule_release(link->rrl_rule);
  705                 uma_zfree(rctl_rule_link_zone, link);
  706                 removed++;
  707         }
  708         return (removed);
  709 }
  710 
  711 static void
  712 rctl_rule_acquire_subject(struct rctl_rule *rule)
  713 {
  714 
  715         ASSERT_RACCT_ENABLED();
  716 
  717         switch (rule->rr_subject_type) {
  718         case RCTL_SUBJECT_TYPE_UNDEFINED:
  719         case RCTL_SUBJECT_TYPE_PROCESS:
  720                 break;
  721         case RCTL_SUBJECT_TYPE_JAIL:
  722                 if (rule->rr_subject.rs_prison_racct != NULL)
  723                         prison_racct_hold(rule->rr_subject.rs_prison_racct);
  724                 break;
  725         case RCTL_SUBJECT_TYPE_USER:
  726                 if (rule->rr_subject.rs_uip != NULL)
  727                         uihold(rule->rr_subject.rs_uip);
  728                 break;
  729         case RCTL_SUBJECT_TYPE_LOGINCLASS:
  730                 if (rule->rr_subject.rs_loginclass != NULL)
  731                         loginclass_hold(rule->rr_subject.rs_loginclass);
  732                 break;
  733         default:
  734                 panic("rctl_rule_acquire_subject: unknown subject type %d",
  735                     rule->rr_subject_type);
  736         }
  737 }
  738 
  739 static void
  740 rctl_rule_release_subject(struct rctl_rule *rule)
  741 {
  742 
  743         ASSERT_RACCT_ENABLED();
  744 
  745         switch (rule->rr_subject_type) {
  746         case RCTL_SUBJECT_TYPE_UNDEFINED:
  747         case RCTL_SUBJECT_TYPE_PROCESS:
  748                 break;
  749         case RCTL_SUBJECT_TYPE_JAIL:
  750                 if (rule->rr_subject.rs_prison_racct != NULL)
  751                         prison_racct_free(rule->rr_subject.rs_prison_racct);
  752                 break;
  753         case RCTL_SUBJECT_TYPE_USER:
  754                 if (rule->rr_subject.rs_uip != NULL)
  755                         uifree(rule->rr_subject.rs_uip);
  756                 break;
  757         case RCTL_SUBJECT_TYPE_LOGINCLASS:
  758                 if (rule->rr_subject.rs_loginclass != NULL)
  759                         loginclass_free(rule->rr_subject.rs_loginclass);
  760                 break;
  761         default:
  762                 panic("rctl_rule_release_subject: unknown subject type %d",
  763                     rule->rr_subject_type);
  764         }
  765 }
  766 
  767 struct rctl_rule *
  768 rctl_rule_alloc(int flags)
  769 {
  770         struct rctl_rule *rule;
  771 
  772         ASSERT_RACCT_ENABLED();
  773 
  774         rule = uma_zalloc(rctl_rule_zone, flags);
  775         if (rule == NULL)
  776                 return (NULL);
  777         rule->rr_subject_type = RCTL_SUBJECT_TYPE_UNDEFINED;
  778         rule->rr_subject.rs_proc = NULL;
  779         rule->rr_subject.rs_uip = NULL;
  780         rule->rr_subject.rs_loginclass = NULL;
  781         rule->rr_subject.rs_prison_racct = NULL;
  782         rule->rr_per = RCTL_SUBJECT_TYPE_UNDEFINED;
  783         rule->rr_resource = RACCT_UNDEFINED;
  784         rule->rr_action = RCTL_ACTION_UNDEFINED;
  785         rule->rr_amount = RCTL_AMOUNT_UNDEFINED;
  786         refcount_init(&rule->rr_refcount, 1);
  787 
  788         return (rule);
  789 }
  790 
  791 struct rctl_rule *
  792 rctl_rule_duplicate(const struct rctl_rule *rule, int flags)
  793 {
  794         struct rctl_rule *copy;
  795 
  796         ASSERT_RACCT_ENABLED();
  797 
  798         copy = uma_zalloc(rctl_rule_zone, flags);
  799         if (copy == NULL)
  800                 return (NULL);
  801         copy->rr_subject_type = rule->rr_subject_type;
  802         copy->rr_subject.rs_proc = rule->rr_subject.rs_proc;
  803         copy->rr_subject.rs_uip = rule->rr_subject.rs_uip;
  804         copy->rr_subject.rs_loginclass = rule->rr_subject.rs_loginclass;
  805         copy->rr_subject.rs_prison_racct = rule->rr_subject.rs_prison_racct;
  806         copy->rr_per = rule->rr_per;
  807         copy->rr_resource = rule->rr_resource;
  808         copy->rr_action = rule->rr_action;
  809         copy->rr_amount = rule->rr_amount;
  810         refcount_init(&copy->rr_refcount, 1);
  811         rctl_rule_acquire_subject(copy);
  812 
  813         return (copy);
  814 }
  815 
  816 void
  817 rctl_rule_acquire(struct rctl_rule *rule)
  818 {
  819 
  820         ASSERT_RACCT_ENABLED();
  821         KASSERT(rule->rr_refcount > 0, ("rule->rr_refcount <= 0"));
  822 
  823         refcount_acquire(&rule->rr_refcount);
  824 }
  825 
  826 static void
  827 rctl_rule_free(void *context, int pending)
  828 {
  829         struct rctl_rule *rule;
  830         
  831         rule = (struct rctl_rule *)context;
  832 
  833         ASSERT_RACCT_ENABLED();
  834         KASSERT(rule->rr_refcount == 0, ("rule->rr_refcount != 0"));
  835         
  836         /*
  837          * We don't need locking here; rule is guaranteed to be inaccessible.
  838          */
  839         
  840         rctl_rule_release_subject(rule);
  841         uma_zfree(rctl_rule_zone, rule);
  842 }
  843 
  844 void
  845 rctl_rule_release(struct rctl_rule *rule)
  846 {
  847 
  848         ASSERT_RACCT_ENABLED();
  849         KASSERT(rule->rr_refcount > 0, ("rule->rr_refcount <= 0"));
  850 
  851         if (refcount_release(&rule->rr_refcount)) {
  852                 /*
  853                  * rctl_rule_release() is often called when iterating
  854                  * over all the uidinfo structures in the system,
  855                  * holding uihashtbl_lock.  Since rctl_rule_free()
  856                  * might end up calling uifree(), this would lead
  857                  * to lock recursion.  Use taskqueue to avoid this.
  858                  */
  859                 TASK_INIT(&rule->rr_task, 0, rctl_rule_free, rule);
  860                 taskqueue_enqueue(taskqueue_thread, &rule->rr_task);
  861         }
  862 }
  863 
  864 static int
  865 rctl_rule_fully_specified(const struct rctl_rule *rule)
  866 {
  867 
  868         ASSERT_RACCT_ENABLED();
  869 
  870         switch (rule->rr_subject_type) {
  871         case RCTL_SUBJECT_TYPE_UNDEFINED:
  872                 return (0);
  873         case RCTL_SUBJECT_TYPE_PROCESS:
  874                 if (rule->rr_subject.rs_proc == NULL)
  875                         return (0);
  876                 break;
  877         case RCTL_SUBJECT_TYPE_USER:
  878                 if (rule->rr_subject.rs_uip == NULL)
  879                         return (0);
  880                 break;
  881         case RCTL_SUBJECT_TYPE_LOGINCLASS:
  882                 if (rule->rr_subject.rs_loginclass == NULL)
  883                         return (0);
  884                 break;
  885         case RCTL_SUBJECT_TYPE_JAIL:
  886                 if (rule->rr_subject.rs_prison_racct == NULL)
  887                         return (0);
  888                 break;
  889         default:
  890                 panic("rctl_rule_fully_specified: unknown subject type %d",
  891                     rule->rr_subject_type);
  892         }
  893         if (rule->rr_resource == RACCT_UNDEFINED)
  894                 return (0);
  895         if (rule->rr_action == RCTL_ACTION_UNDEFINED)
  896                 return (0);
  897         if (rule->rr_amount == RCTL_AMOUNT_UNDEFINED)
  898                 return (0);
  899         if (rule->rr_per == RCTL_SUBJECT_TYPE_UNDEFINED)
  900                 return (0);
  901 
  902         return (1);
  903 }
  904 
  905 static int
  906 rctl_string_to_rule(char *rulestr, struct rctl_rule **rulep)
  907 {
  908         int error = 0;
  909         char *subjectstr, *subject_idstr, *resourcestr, *actionstr,
  910              *amountstr, *perstr;
  911         struct rctl_rule *rule;
  912         id_t id;
  913 
  914         ASSERT_RACCT_ENABLED();
  915 
  916         rule = rctl_rule_alloc(M_WAITOK);
  917 
  918         subjectstr = strsep(&rulestr, ":");
  919         subject_idstr = strsep(&rulestr, ":");
  920         resourcestr = strsep(&rulestr, ":");
  921         actionstr = strsep(&rulestr, "=/");
  922         amountstr = strsep(&rulestr, "/");
  923         perstr = rulestr;
  924 
  925         if (subjectstr == NULL || subjectstr[0] == '\0')
  926                 rule->rr_subject_type = RCTL_SUBJECT_TYPE_UNDEFINED;
  927         else {
  928                 error = str2value(subjectstr, &rule->rr_subject_type, subjectnames);
  929                 if (error != 0)
  930                         goto out;
  931         }
  932 
  933         if (subject_idstr == NULL || subject_idstr[0] == '\0') {
  934                 rule->rr_subject.rs_proc = NULL;
  935                 rule->rr_subject.rs_uip = NULL;
  936                 rule->rr_subject.rs_loginclass = NULL;
  937                 rule->rr_subject.rs_prison_racct = NULL;
  938         } else {
  939                 switch (rule->rr_subject_type) {
  940                 case RCTL_SUBJECT_TYPE_UNDEFINED:
  941                         error = EINVAL;
  942                         goto out;
  943                 case RCTL_SUBJECT_TYPE_PROCESS:
  944                         error = str2id(subject_idstr, &id);
  945                         if (error != 0)
  946                                 goto out;
  947                         sx_assert(&allproc_lock, SA_LOCKED);
  948                         rule->rr_subject.rs_proc = pfind(id);
  949                         if (rule->rr_subject.rs_proc == NULL) {
  950                                 error = ESRCH;
  951                                 goto out;
  952                         }
  953                         PROC_UNLOCK(rule->rr_subject.rs_proc);
  954                         break;
  955                 case RCTL_SUBJECT_TYPE_USER:
  956                         error = str2id(subject_idstr, &id);
  957                         if (error != 0)
  958                                 goto out;
  959                         rule->rr_subject.rs_uip = uifind(id);
  960                         break;
  961                 case RCTL_SUBJECT_TYPE_LOGINCLASS:
  962                         rule->rr_subject.rs_loginclass =
  963                             loginclass_find(subject_idstr);
  964                         if (rule->rr_subject.rs_loginclass == NULL) {
  965                                 error = ENAMETOOLONG;
  966                                 goto out;
  967                         }
  968                         break;
  969                 case RCTL_SUBJECT_TYPE_JAIL:
  970                         rule->rr_subject.rs_prison_racct =
  971                             prison_racct_find(subject_idstr);
  972                         if (rule->rr_subject.rs_prison_racct == NULL) {
  973                                 error = ENAMETOOLONG;
  974                                 goto out;
  975                         }
  976                         break;
  977                default:
  978                        panic("rctl_string_to_rule: unknown subject type %d",
  979                            rule->rr_subject_type);
  980                }
  981         }
  982 
  983         if (resourcestr == NULL || resourcestr[0] == '\0')
  984                 rule->rr_resource = RACCT_UNDEFINED;
  985         else {
  986                 error = str2value(resourcestr, &rule->rr_resource,
  987                     resourcenames);
  988                 if (error != 0)
  989                         goto out;
  990         }
  991 
  992         if (actionstr == NULL || actionstr[0] == '\0')
  993                 rule->rr_action = RCTL_ACTION_UNDEFINED;
  994         else {
  995                 error = str2value(actionstr, &rule->rr_action, actionnames);
  996                 if (error != 0)
  997                         goto out;
  998         }
  999 
 1000         if (amountstr == NULL || amountstr[0] == '\0')
 1001                 rule->rr_amount = RCTL_AMOUNT_UNDEFINED;
 1002         else {
 1003                 error = str2int64(amountstr, &rule->rr_amount);
 1004                 if (error != 0)
 1005                         goto out;
 1006                 if (RACCT_IS_IN_MILLIONS(rule->rr_resource))
 1007                         rule->rr_amount *= 1000000;
 1008         }
 1009 
 1010         if (perstr == NULL || perstr[0] == '\0')
 1011                 rule->rr_per = RCTL_SUBJECT_TYPE_UNDEFINED;
 1012         else {
 1013                 error = str2value(perstr, &rule->rr_per, subjectnames);
 1014                 if (error != 0)
 1015                         goto out;
 1016         }
 1017 
 1018 out:
 1019         if (error == 0)
 1020                 *rulep = rule;
 1021         else
 1022                 rctl_rule_release(rule);
 1023 
 1024         return (error);
 1025 }
 1026 
 1027 /*
 1028  * Link a rule with all the subjects it applies to.
 1029  */
 1030 int
 1031 rctl_rule_add(struct rctl_rule *rule)
 1032 {
 1033         struct proc *p;
 1034         struct ucred *cred;
 1035         struct uidinfo *uip;
 1036         struct prison *pr;
 1037         struct prison_racct *prr;
 1038         struct loginclass *lc;
 1039         struct rctl_rule *rule2;
 1040         int match;
 1041 
 1042         ASSERT_RACCT_ENABLED();
 1043         KASSERT(rctl_rule_fully_specified(rule), ("rule not fully specified"));
 1044 
 1045         /*
 1046          * Some rules just don't make sense.  Note that the one below
 1047          * cannot be rewritten using RACCT_IS_DENIABLE(); the RACCT_PCTCPU,
 1048          * for example, is not deniable in the racct sense, but the
 1049          * limit is enforced in a different way, so "deny" rules for %CPU
 1050          * do make sense.
 1051          */
 1052         if (rule->rr_action == RCTL_ACTION_DENY &&
 1053             (rule->rr_resource == RACCT_CPU ||
 1054             rule->rr_resource == RACCT_WALLCLOCK))
 1055                 return (EOPNOTSUPP);
 1056 
 1057         if (rule->rr_per == RCTL_SUBJECT_TYPE_PROCESS &&
 1058             RACCT_IS_SLOPPY(rule->rr_resource))
 1059                 return (EOPNOTSUPP);
 1060 
 1061         /*
 1062          * Make sure there are no duplicated rules.  Also, for the "deny"
 1063          * rules, remove ones differing only by "amount".
 1064          */
 1065         if (rule->rr_action == RCTL_ACTION_DENY) {
 1066                 rule2 = rctl_rule_duplicate(rule, M_WAITOK);
 1067                 rule2->rr_amount = RCTL_AMOUNT_UNDEFINED;
 1068                 rctl_rule_remove(rule2);
 1069                 rctl_rule_release(rule2);
 1070         } else
 1071                 rctl_rule_remove(rule);
 1072 
 1073         switch (rule->rr_subject_type) {
 1074         case RCTL_SUBJECT_TYPE_PROCESS:
 1075                 p = rule->rr_subject.rs_proc;
 1076                 KASSERT(p != NULL, ("rctl_rule_add: NULL proc"));
 1077 
 1078                 rctl_racct_add_rule(p->p_racct, rule);
 1079                 /*
 1080                  * In case of per-process rule, we don't have anything more
 1081                  * to do.
 1082                  */
 1083                 return (0);
 1084 
 1085         case RCTL_SUBJECT_TYPE_USER:
 1086                 uip = rule->rr_subject.rs_uip;
 1087                 KASSERT(uip != NULL, ("rctl_rule_add: NULL uip"));
 1088                 rctl_racct_add_rule(uip->ui_racct, rule);
 1089                 break;
 1090 
 1091         case RCTL_SUBJECT_TYPE_LOGINCLASS:
 1092                 lc = rule->rr_subject.rs_loginclass;
 1093                 KASSERT(lc != NULL, ("rctl_rule_add: NULL loginclass"));
 1094                 rctl_racct_add_rule(lc->lc_racct, rule);
 1095                 break;
 1096 
 1097         case RCTL_SUBJECT_TYPE_JAIL:
 1098                 prr = rule->rr_subject.rs_prison_racct;
 1099                 KASSERT(prr != NULL, ("rctl_rule_add: NULL pr"));
 1100                 rctl_racct_add_rule(prr->prr_racct, rule);
 1101                 break;
 1102 
 1103         default:
 1104                 panic("rctl_rule_add: unknown subject type %d",
 1105                     rule->rr_subject_type);
 1106         }
 1107 
 1108         /*
 1109          * Now go through all the processes and add the new rule to the ones
 1110          * it applies to.
 1111          */
 1112         sx_assert(&allproc_lock, SA_LOCKED);
 1113         FOREACH_PROC_IN_SYSTEM(p) {
 1114                 cred = p->p_ucred;
 1115                 switch (rule->rr_subject_type) {
 1116                 case RCTL_SUBJECT_TYPE_USER:
 1117                         if (cred->cr_uidinfo == rule->rr_subject.rs_uip ||
 1118                             cred->cr_ruidinfo == rule->rr_subject.rs_uip)
 1119                                 break;
 1120                         continue;
 1121                 case RCTL_SUBJECT_TYPE_LOGINCLASS:
 1122                         if (cred->cr_loginclass == rule->rr_subject.rs_loginclass)
 1123                                 break;
 1124                         continue;
 1125                 case RCTL_SUBJECT_TYPE_JAIL:
 1126                         match = 0;
 1127                         for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) {
 1128                                 if (pr->pr_prison_racct == rule->rr_subject.rs_prison_racct) {
 1129                                         match = 1;
 1130                                         break;
 1131                                 }
 1132                         }
 1133                         if (match)
 1134                                 break;
 1135                         continue;
 1136                 default:
 1137                         panic("rctl_rule_add: unknown subject type %d",
 1138                             rule->rr_subject_type);
 1139                 }
 1140 
 1141                 rctl_racct_add_rule(p->p_racct, rule);
 1142         }
 1143 
 1144         return (0);
 1145 }
 1146 
 1147 static void
 1148 rctl_rule_remove_callback(struct racct *racct, void *arg2, void *arg3)
 1149 {
 1150         struct rctl_rule *filter = (struct rctl_rule *)arg2;
 1151         int found = 0;
 1152 
 1153         ASSERT_RACCT_ENABLED();
 1154 
 1155         rw_wlock(&rctl_lock);
 1156         found += rctl_racct_remove_rules(racct, filter);
 1157         rw_wunlock(&rctl_lock);
 1158 
 1159         *((int *)arg3) += found;
 1160 }
 1161 
 1162 /*
 1163  * Remove all rules that match the filter.
 1164  */
 1165 int
 1166 rctl_rule_remove(struct rctl_rule *filter)
 1167 {
 1168         int found = 0;
 1169         struct proc *p;
 1170 
 1171         ASSERT_RACCT_ENABLED();
 1172 
 1173         if (filter->rr_subject_type == RCTL_SUBJECT_TYPE_PROCESS &&
 1174             filter->rr_subject.rs_proc != NULL) {
 1175                 p = filter->rr_subject.rs_proc;
 1176                 rw_wlock(&rctl_lock);
 1177                 found = rctl_racct_remove_rules(p->p_racct, filter);
 1178                 rw_wunlock(&rctl_lock);
 1179                 if (found)
 1180                         return (0);
 1181                 return (ESRCH);
 1182         }
 1183 
 1184         loginclass_racct_foreach(rctl_rule_remove_callback, filter,
 1185             (void *)&found);
 1186         ui_racct_foreach(rctl_rule_remove_callback, filter,
 1187             (void *)&found);
 1188         prison_racct_foreach(rctl_rule_remove_callback, filter,
 1189             (void *)&found);
 1190 
 1191         sx_assert(&allproc_lock, SA_LOCKED);
 1192         rw_wlock(&rctl_lock);
 1193         FOREACH_PROC_IN_SYSTEM(p) {
 1194                 found += rctl_racct_remove_rules(p->p_racct, filter);
 1195         }
 1196         rw_wunlock(&rctl_lock);
 1197 
 1198         if (found)
 1199                 return (0);
 1200         return (ESRCH);
 1201 }
 1202 
 1203 /*
 1204  * Appends a rule to the sbuf.
 1205  */
 1206 static void
 1207 rctl_rule_to_sbuf(struct sbuf *sb, const struct rctl_rule *rule)
 1208 {
 1209         int64_t amount;
 1210 
 1211         ASSERT_RACCT_ENABLED();
 1212 
 1213         sbuf_printf(sb, "%s:", rctl_subject_type_name(rule->rr_subject_type));
 1214 
 1215         switch (rule->rr_subject_type) {
 1216         case RCTL_SUBJECT_TYPE_PROCESS:
 1217                 if (rule->rr_subject.rs_proc == NULL)
 1218                         sbuf_printf(sb, ":");
 1219                 else
 1220                         sbuf_printf(sb, "%d:",
 1221                             rule->rr_subject.rs_proc->p_pid);
 1222                 break;
 1223         case RCTL_SUBJECT_TYPE_USER:
 1224                 if (rule->rr_subject.rs_uip == NULL)
 1225                         sbuf_printf(sb, ":");
 1226                 else
 1227                         sbuf_printf(sb, "%d:",
 1228                             rule->rr_subject.rs_uip->ui_uid);
 1229                 break;
 1230         case RCTL_SUBJECT_TYPE_LOGINCLASS:
 1231                 if (rule->rr_subject.rs_loginclass == NULL)
 1232                         sbuf_printf(sb, ":");
 1233                 else
 1234                         sbuf_printf(sb, "%s:",
 1235                             rule->rr_subject.rs_loginclass->lc_name);
 1236                 break;
 1237         case RCTL_SUBJECT_TYPE_JAIL:
 1238                 if (rule->rr_subject.rs_prison_racct == NULL)
 1239                         sbuf_printf(sb, ":");
 1240                 else
 1241                         sbuf_printf(sb, "%s:",
 1242                             rule->rr_subject.rs_prison_racct->prr_name);
 1243                 break;
 1244         default:
 1245                 panic("rctl_rule_to_sbuf: unknown subject type %d",
 1246                     rule->rr_subject_type);
 1247         }
 1248 
 1249         amount = rule->rr_amount;
 1250         if (amount != RCTL_AMOUNT_UNDEFINED &&
 1251             RACCT_IS_IN_MILLIONS(rule->rr_resource))
 1252                 amount /= 1000000;
 1253 
 1254         sbuf_printf(sb, "%s:%s=%jd",
 1255             rctl_resource_name(rule->rr_resource),
 1256             rctl_action_name(rule->rr_action),
 1257             amount);
 1258 
 1259         if (rule->rr_per != rule->rr_subject_type)
 1260                 sbuf_printf(sb, "/%s", rctl_subject_type_name(rule->rr_per));
 1261 }
 1262 
 1263 /*
 1264  * Routine used by RCTL syscalls to read in input string.
 1265  */
 1266 static int
 1267 rctl_read_inbuf(char **inputstr, const char *inbufp, size_t inbuflen)
 1268 {
 1269         int error;
 1270         char *str;
 1271 
 1272         ASSERT_RACCT_ENABLED();
 1273 
 1274         if (inbuflen <= 0)
 1275                 return (EINVAL);
 1276         if (inbuflen > RCTL_MAX_INBUFLEN)
 1277                 return (E2BIG);
 1278 
 1279         str = malloc(inbuflen + 1, M_RCTL, M_WAITOK);
 1280         error = copyinstr(inbufp, str, inbuflen, NULL);
 1281         if (error != 0) {
 1282                 free(str, M_RCTL);
 1283                 return (error);
 1284         }
 1285 
 1286         *inputstr = str;
 1287 
 1288         return (0);
 1289 }
 1290 
 1291 /*
 1292  * Routine used by RCTL syscalls to write out output string.
 1293  */
 1294 static int
 1295 rctl_write_outbuf(struct sbuf *outputsbuf, char *outbufp, size_t outbuflen)
 1296 {
 1297         int error;
 1298 
 1299         ASSERT_RACCT_ENABLED();
 1300 
 1301         if (outputsbuf == NULL)
 1302                 return (0);
 1303 
 1304         sbuf_finish(outputsbuf);
 1305         if (outbuflen < sbuf_len(outputsbuf) + 1) {
 1306                 sbuf_delete(outputsbuf);
 1307                 return (ERANGE);
 1308         }
 1309         error = copyout(sbuf_data(outputsbuf), outbufp,
 1310             sbuf_len(outputsbuf) + 1);
 1311         sbuf_delete(outputsbuf);
 1312         return (error);
 1313 }
 1314 
 1315 static struct sbuf *
 1316 rctl_racct_to_sbuf(struct racct *racct, int sloppy)
 1317 {
 1318         int i;
 1319         int64_t amount;
 1320         struct sbuf *sb;
 1321 
 1322         ASSERT_RACCT_ENABLED();
 1323 
 1324         sb = sbuf_new_auto();
 1325         for (i = 0; i <= RACCT_MAX; i++) {
 1326                 if (sloppy == 0 && RACCT_IS_SLOPPY(i))
 1327                         continue;
 1328                 amount = racct->r_resources[i];
 1329                 if (RACCT_IS_IN_MILLIONS(i))
 1330                         amount /= 1000000;
 1331                 sbuf_printf(sb, "%s=%jd,", rctl_resource_name(i), amount);
 1332         }
 1333         sbuf_setpos(sb, sbuf_len(sb) - 1);
 1334         return (sb);
 1335 }
 1336 
 1337 int
 1338 sys_rctl_get_racct(struct thread *td, struct rctl_get_racct_args *uap)
 1339 {
 1340         int error;
 1341         char *inputstr;
 1342         struct rctl_rule *filter;
 1343         struct sbuf *outputsbuf = NULL;
 1344         struct proc *p;
 1345         struct uidinfo *uip;
 1346         struct loginclass *lc;
 1347         struct prison_racct *prr;
 1348 
 1349         if (!racct_enable)
 1350                 return (ENOSYS);
 1351 
 1352         error = priv_check(td, PRIV_RCTL_GET_RACCT);
 1353         if (error != 0)
 1354                 return (error);
 1355 
 1356         error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen);
 1357         if (error != 0)
 1358                 return (error);
 1359 
 1360         sx_slock(&allproc_lock);
 1361         error = rctl_string_to_rule(inputstr, &filter);
 1362         free(inputstr, M_RCTL);
 1363         if (error != 0) {
 1364                 sx_sunlock(&allproc_lock);
 1365                 return (error);
 1366         }
 1367 
 1368         switch (filter->rr_subject_type) {
 1369         case RCTL_SUBJECT_TYPE_PROCESS:
 1370                 p = filter->rr_subject.rs_proc;
 1371                 if (p == NULL) {
 1372                         error = EINVAL;
 1373                         goto out;
 1374                 }
 1375                 outputsbuf = rctl_racct_to_sbuf(p->p_racct, 0);
 1376                 break;
 1377         case RCTL_SUBJECT_TYPE_USER:
 1378                 uip = filter->rr_subject.rs_uip;
 1379                 if (uip == NULL) {
 1380                         error = EINVAL;
 1381                         goto out;
 1382                 }
 1383                 outputsbuf = rctl_racct_to_sbuf(uip->ui_racct, 1);
 1384                 break;
 1385         case RCTL_SUBJECT_TYPE_LOGINCLASS:
 1386                 lc = filter->rr_subject.rs_loginclass;
 1387                 if (lc == NULL) {
 1388                         error = EINVAL;
 1389                         goto out;
 1390                 }
 1391                 outputsbuf = rctl_racct_to_sbuf(lc->lc_racct, 1);
 1392                 break;
 1393         case RCTL_SUBJECT_TYPE_JAIL:
 1394                 prr = filter->rr_subject.rs_prison_racct;
 1395                 if (prr == NULL) {
 1396                         error = EINVAL;
 1397                         goto out;
 1398                 }
 1399                 outputsbuf = rctl_racct_to_sbuf(prr->prr_racct, 1);
 1400                 break;
 1401         default:
 1402                 error = EINVAL;
 1403         }
 1404 out:
 1405         rctl_rule_release(filter);
 1406         sx_sunlock(&allproc_lock);
 1407         if (error != 0)
 1408                 return (error);
 1409 
 1410         error = rctl_write_outbuf(outputsbuf, uap->outbufp, uap->outbuflen);
 1411 
 1412         return (error);
 1413 }
 1414 
 1415 static void
 1416 rctl_get_rules_callback(struct racct *racct, void *arg2, void *arg3)
 1417 {
 1418         struct rctl_rule *filter = (struct rctl_rule *)arg2;
 1419         struct rctl_rule_link *link;
 1420         struct sbuf *sb = (struct sbuf *)arg3;
 1421 
 1422         ASSERT_RACCT_ENABLED();
 1423 
 1424         rw_rlock(&rctl_lock);
 1425         LIST_FOREACH(link, &racct->r_rule_links, rrl_next) {
 1426                 if (!rctl_rule_matches(link->rrl_rule, filter))
 1427                         continue;
 1428                 rctl_rule_to_sbuf(sb, link->rrl_rule);
 1429                 sbuf_printf(sb, ",");
 1430         }
 1431         rw_runlock(&rctl_lock);
 1432 }
 1433 
 1434 int
 1435 sys_rctl_get_rules(struct thread *td, struct rctl_get_rules_args *uap)
 1436 {
 1437         int error;
 1438         size_t bufsize = RCTL_DEFAULT_BUFSIZE;
 1439         char *inputstr, *buf;
 1440         struct sbuf *sb;
 1441         struct rctl_rule *filter;
 1442         struct rctl_rule_link *link;
 1443         struct proc *p;
 1444 
 1445         if (!racct_enable)
 1446                 return (ENOSYS);
 1447 
 1448         error = priv_check(td, PRIV_RCTL_GET_RULES);
 1449         if (error != 0)
 1450                 return (error);
 1451 
 1452         error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen);
 1453         if (error != 0)
 1454                 return (error);
 1455 
 1456         sx_slock(&allproc_lock);
 1457         error = rctl_string_to_rule(inputstr, &filter);
 1458         free(inputstr, M_RCTL);
 1459         if (error != 0) {
 1460                 sx_sunlock(&allproc_lock);
 1461                 return (error);
 1462         }
 1463 
 1464 again:
 1465         buf = malloc(bufsize, M_RCTL, M_WAITOK);
 1466         sb = sbuf_new(NULL, buf, bufsize, SBUF_FIXEDLEN);
 1467         KASSERT(sb != NULL, ("sbuf_new failed"));
 1468 
 1469         sx_assert(&allproc_lock, SA_LOCKED);
 1470         FOREACH_PROC_IN_SYSTEM(p) {
 1471                 rw_rlock(&rctl_lock);
 1472                 LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
 1473                         /*
 1474                          * Non-process rules will be added to the buffer later.
 1475                          * Adding them here would result in duplicated output.
 1476                          */
 1477                         if (link->rrl_rule->rr_subject_type !=
 1478                             RCTL_SUBJECT_TYPE_PROCESS)
 1479                                 continue;
 1480                         if (!rctl_rule_matches(link->rrl_rule, filter))
 1481                                 continue;
 1482                         rctl_rule_to_sbuf(sb, link->rrl_rule);
 1483                         sbuf_printf(sb, ",");
 1484                 }
 1485                 rw_runlock(&rctl_lock);
 1486         }
 1487 
 1488         loginclass_racct_foreach(rctl_get_rules_callback, filter, sb);
 1489         ui_racct_foreach(rctl_get_rules_callback, filter, sb);
 1490         prison_racct_foreach(rctl_get_rules_callback, filter, sb);
 1491         if (sbuf_error(sb) == ENOMEM) {
 1492                 sbuf_delete(sb);
 1493                 free(buf, M_RCTL);
 1494                 bufsize *= 4;
 1495                 goto again;
 1496         }
 1497 
 1498         /*
 1499          * Remove trailing ",".
 1500          */
 1501         if (sbuf_len(sb) > 0)
 1502                 sbuf_setpos(sb, sbuf_len(sb) - 1);
 1503 
 1504         error = rctl_write_outbuf(sb, uap->outbufp, uap->outbuflen);
 1505 
 1506         rctl_rule_release(filter);
 1507         sx_sunlock(&allproc_lock);
 1508         free(buf, M_RCTL);
 1509         return (error);
 1510 }
 1511 
 1512 int
 1513 sys_rctl_get_limits(struct thread *td, struct rctl_get_limits_args *uap)
 1514 {
 1515         int error;
 1516         size_t bufsize = RCTL_DEFAULT_BUFSIZE;
 1517         char *inputstr, *buf;
 1518         struct sbuf *sb;
 1519         struct rctl_rule *filter;
 1520         struct rctl_rule_link *link;
 1521 
 1522         if (!racct_enable)
 1523                 return (ENOSYS);
 1524 
 1525         error = priv_check(td, PRIV_RCTL_GET_LIMITS);
 1526         if (error != 0)
 1527                 return (error);
 1528 
 1529         error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen);
 1530         if (error != 0)
 1531                 return (error);
 1532 
 1533         sx_slock(&allproc_lock);
 1534         error = rctl_string_to_rule(inputstr, &filter);
 1535         free(inputstr, M_RCTL);
 1536         if (error != 0) {
 1537                 sx_sunlock(&allproc_lock);
 1538                 return (error);
 1539         }
 1540 
 1541         if (filter->rr_subject_type == RCTL_SUBJECT_TYPE_UNDEFINED) {
 1542                 rctl_rule_release(filter);
 1543                 sx_sunlock(&allproc_lock);
 1544                 return (EINVAL);
 1545         }
 1546         if (filter->rr_subject_type != RCTL_SUBJECT_TYPE_PROCESS) {
 1547                 rctl_rule_release(filter);
 1548                 sx_sunlock(&allproc_lock);
 1549                 return (EOPNOTSUPP);
 1550         }
 1551         if (filter->rr_subject.rs_proc == NULL) {
 1552                 rctl_rule_release(filter);
 1553                 sx_sunlock(&allproc_lock);
 1554                 return (EINVAL);
 1555         }
 1556 
 1557 again:
 1558         buf = malloc(bufsize, M_RCTL, M_WAITOK);
 1559         sb = sbuf_new(NULL, buf, bufsize, SBUF_FIXEDLEN);
 1560         KASSERT(sb != NULL, ("sbuf_new failed"));
 1561 
 1562         rw_rlock(&rctl_lock);
 1563         LIST_FOREACH(link, &filter->rr_subject.rs_proc->p_racct->r_rule_links,
 1564             rrl_next) {
 1565                 rctl_rule_to_sbuf(sb, link->rrl_rule);
 1566                 sbuf_printf(sb, ",");
 1567         }
 1568         rw_runlock(&rctl_lock);
 1569         if (sbuf_error(sb) == ENOMEM) {
 1570                 sbuf_delete(sb);
 1571                 free(buf, M_RCTL);
 1572                 bufsize *= 4;
 1573                 goto again;
 1574         }
 1575 
 1576         /*
 1577          * Remove trailing ",".
 1578          */
 1579         if (sbuf_len(sb) > 0)
 1580                 sbuf_setpos(sb, sbuf_len(sb) - 1);
 1581 
 1582         error = rctl_write_outbuf(sb, uap->outbufp, uap->outbuflen);
 1583         rctl_rule_release(filter);
 1584         sx_sunlock(&allproc_lock);
 1585         free(buf, M_RCTL);
 1586         return (error);
 1587 }
 1588 
 1589 int
 1590 sys_rctl_add_rule(struct thread *td, struct rctl_add_rule_args *uap)
 1591 {
 1592         int error;
 1593         struct rctl_rule *rule;
 1594         char *inputstr;
 1595 
 1596         if (!racct_enable)
 1597                 return (ENOSYS);
 1598 
 1599         error = priv_check(td, PRIV_RCTL_ADD_RULE);
 1600         if (error != 0)
 1601                 return (error);
 1602 
 1603         error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen);
 1604         if (error != 0)
 1605                 return (error);
 1606 
 1607         sx_slock(&allproc_lock);
 1608         error = rctl_string_to_rule(inputstr, &rule);
 1609         free(inputstr, M_RCTL);
 1610         if (error != 0) {
 1611                 sx_sunlock(&allproc_lock);
 1612                 return (error);
 1613         }
 1614         /*
 1615          * The 'per' part of a rule is optional.
 1616          */
 1617         if (rule->rr_per == RCTL_SUBJECT_TYPE_UNDEFINED &&
 1618             rule->rr_subject_type != RCTL_SUBJECT_TYPE_UNDEFINED)
 1619                 rule->rr_per = rule->rr_subject_type;
 1620 
 1621         if (!rctl_rule_fully_specified(rule)) {
 1622                 error = EINVAL;
 1623                 goto out;
 1624         }
 1625 
 1626         error = rctl_rule_add(rule);
 1627 
 1628 out:
 1629         rctl_rule_release(rule);
 1630         sx_sunlock(&allproc_lock);
 1631         return (error);
 1632 }
 1633 
 1634 int
 1635 sys_rctl_remove_rule(struct thread *td, struct rctl_remove_rule_args *uap)
 1636 {
 1637         int error;
 1638         struct rctl_rule *filter;
 1639         char *inputstr;
 1640 
 1641         if (!racct_enable)
 1642                 return (ENOSYS);
 1643 
 1644         error = priv_check(td, PRIV_RCTL_REMOVE_RULE);
 1645         if (error != 0)
 1646                 return (error);
 1647 
 1648         error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen);
 1649         if (error != 0)
 1650                 return (error);
 1651 
 1652         sx_slock(&allproc_lock);
 1653         error = rctl_string_to_rule(inputstr, &filter);
 1654         free(inputstr, M_RCTL);
 1655         if (error != 0) {
 1656                 sx_sunlock(&allproc_lock);
 1657                 return (error);
 1658         }
 1659 
 1660         error = rctl_rule_remove(filter);
 1661         rctl_rule_release(filter);
 1662         sx_sunlock(&allproc_lock);
 1663 
 1664         return (error);
 1665 }
 1666 
 1667 /*
 1668  * Update RCTL rule list after credential change.
 1669  */
 1670 void
 1671 rctl_proc_ucred_changed(struct proc *p, struct ucred *newcred)
 1672 {
 1673         int rulecnt, i;
 1674         struct rctl_rule_link *link, *newlink;
 1675         struct uidinfo *newuip;
 1676         struct loginclass *newlc;
 1677         struct prison_racct *newprr;
 1678         LIST_HEAD(, rctl_rule_link) newrules;
 1679 
 1680         ASSERT_RACCT_ENABLED();
 1681 
 1682         newuip = newcred->cr_ruidinfo;
 1683         newlc = newcred->cr_loginclass;
 1684         newprr = newcred->cr_prison->pr_prison_racct;
 1685         
 1686         LIST_INIT(&newrules);
 1687 
 1688 again:
 1689         /*
 1690          * First, count the rules that apply to the process with new
 1691          * credentials.
 1692          */
 1693         rulecnt = 0;
 1694         rw_rlock(&rctl_lock);
 1695         LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
 1696                 if (link->rrl_rule->rr_subject_type ==
 1697                     RCTL_SUBJECT_TYPE_PROCESS)
 1698                         rulecnt++;
 1699         }
 1700         LIST_FOREACH(link, &newuip->ui_racct->r_rule_links, rrl_next)
 1701                 rulecnt++;
 1702         LIST_FOREACH(link, &newlc->lc_racct->r_rule_links, rrl_next)
 1703                 rulecnt++;
 1704         LIST_FOREACH(link, &newprr->prr_racct->r_rule_links, rrl_next)
 1705                 rulecnt++;
 1706         rw_runlock(&rctl_lock);
 1707 
 1708         /*
 1709          * Create temporary list.  We've dropped the rctl_lock in order
 1710          * to use M_WAITOK.
 1711          */
 1712         for (i = 0; i < rulecnt; i++) {
 1713                 newlink = uma_zalloc(rctl_rule_link_zone, M_WAITOK);
 1714                 newlink->rrl_rule = NULL;
 1715                 LIST_INSERT_HEAD(&newrules, newlink, rrl_next);
 1716         }
 1717 
 1718         newlink = LIST_FIRST(&newrules);
 1719 
 1720         /*
 1721          * Assign rules to the newly allocated list entries.
 1722          */
 1723         rw_wlock(&rctl_lock);
 1724         LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
 1725                 if (link->rrl_rule->rr_subject_type ==
 1726                     RCTL_SUBJECT_TYPE_PROCESS) {
 1727                         if (newlink == NULL)
 1728                                 goto goaround;
 1729                         rctl_rule_acquire(link->rrl_rule);
 1730                         newlink->rrl_rule = link->rrl_rule;
 1731                         newlink = LIST_NEXT(newlink, rrl_next);
 1732                         rulecnt--;
 1733                 }
 1734         }
 1735         
 1736         LIST_FOREACH(link, &newuip->ui_racct->r_rule_links, rrl_next) {
 1737                 if (newlink == NULL)
 1738                         goto goaround;
 1739                 rctl_rule_acquire(link->rrl_rule);
 1740                 newlink->rrl_rule = link->rrl_rule;
 1741                 newlink = LIST_NEXT(newlink, rrl_next);
 1742                 rulecnt--;
 1743         }
 1744 
 1745         LIST_FOREACH(link, &newlc->lc_racct->r_rule_links, rrl_next) {
 1746                 if (newlink == NULL)
 1747                         goto goaround;
 1748                 rctl_rule_acquire(link->rrl_rule);
 1749                 newlink->rrl_rule = link->rrl_rule;
 1750                 newlink = LIST_NEXT(newlink, rrl_next);
 1751                 rulecnt--;
 1752         }
 1753 
 1754         LIST_FOREACH(link, &newprr->prr_racct->r_rule_links, rrl_next) {
 1755                 if (newlink == NULL)
 1756                         goto goaround;
 1757                 rctl_rule_acquire(link->rrl_rule);
 1758                 newlink->rrl_rule = link->rrl_rule;
 1759                 newlink = LIST_NEXT(newlink, rrl_next);
 1760                 rulecnt--;
 1761         }
 1762 
 1763         if (rulecnt == 0) {
 1764                 /*
 1765                  * Free the old rule list.
 1766                  */
 1767                 while (!LIST_EMPTY(&p->p_racct->r_rule_links)) {
 1768                         link = LIST_FIRST(&p->p_racct->r_rule_links);
 1769                         LIST_REMOVE(link, rrl_next);
 1770                         rctl_rule_release(link->rrl_rule);
 1771                         uma_zfree(rctl_rule_link_zone, link);
 1772                 }
 1773 
 1774                 /*
 1775                  * Replace lists and we're done.
 1776                  *
 1777                  * XXX: Is there any way to switch list heads instead
 1778                  *      of iterating here?
 1779                  */
 1780                 while (!LIST_EMPTY(&newrules)) {
 1781                         newlink = LIST_FIRST(&newrules);
 1782                         LIST_REMOVE(newlink, rrl_next);
 1783                         LIST_INSERT_HEAD(&p->p_racct->r_rule_links,
 1784                             newlink, rrl_next);
 1785                 }
 1786 
 1787                 rw_wunlock(&rctl_lock);
 1788 
 1789                 return;
 1790         }
 1791 
 1792 goaround:
 1793         rw_wunlock(&rctl_lock);
 1794 
 1795         /*
 1796          * Rule list changed while we were not holding the rctl_lock.
 1797          * Free the new list and try again.
 1798          */
 1799         while (!LIST_EMPTY(&newrules)) {
 1800                 newlink = LIST_FIRST(&newrules);
 1801                 LIST_REMOVE(newlink, rrl_next);
 1802                 if (newlink->rrl_rule != NULL)
 1803                         rctl_rule_release(newlink->rrl_rule);
 1804                 uma_zfree(rctl_rule_link_zone, newlink);
 1805         }
 1806 
 1807         goto again;
 1808 }
 1809 
 1810 /*
 1811  * Assign RCTL rules to the newly created process.
 1812  */
 1813 int
 1814 rctl_proc_fork(struct proc *parent, struct proc *child)
 1815 {
 1816         int error;
 1817         struct rctl_rule_link *link;
 1818         struct rctl_rule *rule;
 1819 
 1820         LIST_INIT(&child->p_racct->r_rule_links);
 1821 
 1822         ASSERT_RACCT_ENABLED();
 1823         KASSERT(parent->p_racct != NULL, ("process without racct; p = %p", parent));
 1824 
 1825         rw_wlock(&rctl_lock);
 1826 
 1827         /*
 1828          * Go through limits applicable to the parent and assign them
 1829          * to the child.  Rules with 'process' subject have to be duplicated
 1830          * in order to make their rr_subject point to the new process.
 1831          */
 1832         LIST_FOREACH(link, &parent->p_racct->r_rule_links, rrl_next) {
 1833                 if (link->rrl_rule->rr_subject_type ==
 1834                     RCTL_SUBJECT_TYPE_PROCESS) {
 1835                         rule = rctl_rule_duplicate(link->rrl_rule, M_NOWAIT);
 1836                         if (rule == NULL)
 1837                                 goto fail;
 1838                         KASSERT(rule->rr_subject.rs_proc == parent,
 1839                             ("rule->rr_subject.rs_proc != parent"));
 1840                         rule->rr_subject.rs_proc = child;
 1841                         error = rctl_racct_add_rule_locked(child->p_racct,
 1842                             rule);
 1843                         rctl_rule_release(rule);
 1844                         if (error != 0)
 1845                                 goto fail;
 1846                 } else {
 1847                         error = rctl_racct_add_rule_locked(child->p_racct,
 1848                             link->rrl_rule);
 1849                         if (error != 0)
 1850                                 goto fail;
 1851                 }
 1852         }
 1853 
 1854         rw_wunlock(&rctl_lock);
 1855         return (0);
 1856 
 1857 fail:
 1858         while (!LIST_EMPTY(&child->p_racct->r_rule_links)) {
 1859                 link = LIST_FIRST(&child->p_racct->r_rule_links);
 1860                 LIST_REMOVE(link, rrl_next);
 1861                 rctl_rule_release(link->rrl_rule);
 1862                 uma_zfree(rctl_rule_link_zone, link);
 1863         }
 1864         rw_wunlock(&rctl_lock);
 1865         return (EAGAIN);
 1866 }
 1867 
 1868 /*
 1869  * Release rules attached to the racct.
 1870  */
 1871 void
 1872 rctl_racct_release(struct racct *racct)
 1873 {
 1874         struct rctl_rule_link *link;
 1875 
 1876         ASSERT_RACCT_ENABLED();
 1877 
 1878         rw_wlock(&rctl_lock);
 1879         while (!LIST_EMPTY(&racct->r_rule_links)) {
 1880                 link = LIST_FIRST(&racct->r_rule_links);
 1881                 LIST_REMOVE(link, rrl_next);
 1882                 rctl_rule_release(link->rrl_rule);
 1883                 uma_zfree(rctl_rule_link_zone, link);
 1884         }
 1885         rw_wunlock(&rctl_lock);
 1886 }
 1887 
 1888 static void
 1889 rctl_init(void)
 1890 {
 1891 
 1892         if (!racct_enable)
 1893                 return;
 1894 
 1895         rctl_rule_link_zone = uma_zcreate("rctl_rule_link",
 1896             sizeof(struct rctl_rule_link), NULL, NULL, NULL, NULL,
 1897             UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
 1898         rctl_rule_zone = uma_zcreate("rctl_rule", sizeof(struct rctl_rule),
 1899             NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
 1900 }
 1901 
 1902 #else /* !RCTL */
 1903 
 1904 int
 1905 sys_rctl_get_racct(struct thread *td, struct rctl_get_racct_args *uap)
 1906 {
 1907         
 1908         return (ENOSYS);
 1909 }
 1910 
 1911 int
 1912 sys_rctl_get_rules(struct thread *td, struct rctl_get_rules_args *uap)
 1913 {
 1914         
 1915         return (ENOSYS);
 1916 }
 1917 
 1918 int
 1919 sys_rctl_get_limits(struct thread *td, struct rctl_get_limits_args *uap)
 1920 {
 1921         
 1922         return (ENOSYS);
 1923 }
 1924 
 1925 int
 1926 sys_rctl_add_rule(struct thread *td, struct rctl_add_rule_args *uap)
 1927 {
 1928         
 1929         return (ENOSYS);
 1930 }
 1931 
 1932 int
 1933 sys_rctl_remove_rule(struct thread *td, struct rctl_remove_rule_args *uap)
 1934 {
 1935         
 1936         return (ENOSYS);
 1937 }
 1938 
 1939 #endif /* !RCTL */

Cache object: 09716e15e23404ed905d17c3056127b9


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