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

Cache object: 961acdc3f4970fe4e1205598c0d882c3


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