1ec125fbbSEdward Tomasz Napierala /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 38a36da99SPedro F. Giffuni * 4ec125fbbSEdward Tomasz Napierala * Copyright (c) 2010 The FreeBSD Foundation 5ec125fbbSEdward Tomasz Napierala * 6ec125fbbSEdward Tomasz Napierala * This software was developed by Edward Tomasz Napierala under sponsorship 7ec125fbbSEdward Tomasz Napierala * from the FreeBSD Foundation. 8ec125fbbSEdward Tomasz Napierala * 9ec125fbbSEdward Tomasz Napierala * Redistribution and use in source and binary forms, with or without 10ec125fbbSEdward Tomasz Napierala * modification, are permitted provided that the following conditions 11ec125fbbSEdward Tomasz Napierala * are met: 12ec125fbbSEdward Tomasz Napierala * 1. Redistributions of source code must retain the above copyright 13ec125fbbSEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer. 14ec125fbbSEdward Tomasz Napierala * 2. Redistributions in binary form must reproduce the above copyright 15ec125fbbSEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer in the 16ec125fbbSEdward Tomasz Napierala * documentation and/or other materials provided with the distribution. 17ec125fbbSEdward Tomasz Napierala * 18ec125fbbSEdward Tomasz Napierala * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19ec125fbbSEdward Tomasz Napierala * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20ec125fbbSEdward Tomasz Napierala * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21ec125fbbSEdward Tomasz Napierala * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22ec125fbbSEdward Tomasz Napierala * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23ec125fbbSEdward Tomasz Napierala * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24ec125fbbSEdward Tomasz Napierala * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25ec125fbbSEdward Tomasz Napierala * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26ec125fbbSEdward Tomasz Napierala * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27ec125fbbSEdward Tomasz Napierala * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28ec125fbbSEdward Tomasz Napierala * SUCH DAMAGE. 29ec125fbbSEdward Tomasz Napierala */ 30ec125fbbSEdward Tomasz Napierala 31e0205aa3SOlivier Certner #ifdef RCTL 32e0205aa3SOlivier Certner 33ec125fbbSEdward Tomasz Napierala #include <sys/param.h> 34773e541eSWarner Losh #include <sys/devctl.h> 35ec125fbbSEdward Tomasz Napierala #include <sys/malloc.h> 36ec125fbbSEdward Tomasz Napierala #include <sys/queue.h> 37ec125fbbSEdward Tomasz Napierala #include <sys/refcount.h> 38ec125fbbSEdward Tomasz Napierala #include <sys/jail.h> 39ec125fbbSEdward Tomasz Napierala #include <sys/kernel.h> 40ec125fbbSEdward Tomasz Napierala #include <sys/limits.h> 41ec125fbbSEdward Tomasz Napierala #include <sys/loginclass.h> 42*6bb132baSBrooks Davis #include <sys/malloc.h> 43ec125fbbSEdward Tomasz Napierala #include <sys/priv.h> 44ec125fbbSEdward Tomasz Napierala #include <sys/proc.h> 45ec125fbbSEdward Tomasz Napierala #include <sys/racct.h> 46ec125fbbSEdward Tomasz Napierala #include <sys/rctl.h> 47ec125fbbSEdward Tomasz Napierala #include <sys/resourcevar.h> 48ec125fbbSEdward Tomasz Napierala #include <sys/sx.h> 49ec125fbbSEdward Tomasz Napierala #include <sys/sysproto.h> 50ec125fbbSEdward Tomasz Napierala #include <sys/systm.h> 51ec125fbbSEdward Tomasz Napierala #include <sys/types.h> 52ec125fbbSEdward Tomasz Napierala #include <sys/eventhandler.h> 53ec125fbbSEdward Tomasz Napierala #include <sys/lock.h> 54ec125fbbSEdward Tomasz Napierala #include <sys/mutex.h> 55ec125fbbSEdward Tomasz Napierala #include <sys/rwlock.h> 56ec125fbbSEdward Tomasz Napierala #include <sys/sbuf.h> 57ec125fbbSEdward Tomasz Napierala #include <sys/taskqueue.h> 58ec125fbbSEdward Tomasz Napierala #include <sys/tree.h> 59ec125fbbSEdward Tomasz Napierala #include <vm/uma.h> 60ec125fbbSEdward Tomasz Napierala 61ec125fbbSEdward Tomasz Napierala #ifndef RACCT 62ec125fbbSEdward Tomasz Napierala #error "The RCTL option requires the RACCT option" 63ec125fbbSEdward Tomasz Napierala #endif 64ec125fbbSEdward Tomasz Napierala 65ec125fbbSEdward Tomasz Napierala FEATURE(rctl, "Resource Limits"); 66ec125fbbSEdward Tomasz Napierala 67ec125fbbSEdward Tomasz Napierala #define HRF_DEFAULT 0 68ec125fbbSEdward Tomasz Napierala #define HRF_DONT_INHERIT 1 69ec125fbbSEdward Tomasz Napierala #define HRF_DONT_ACCUMULATE 2 70ec125fbbSEdward Tomasz Napierala 71ea228b48SEdward Tomasz Napierala #define RCTL_MAX_INBUFSIZE 4 * 1024 72ea228b48SEdward Tomasz Napierala #define RCTL_MAX_OUTBUFSIZE 16 * 1024 * 1024 73ec125fbbSEdward Tomasz Napierala #define RCTL_LOG_BUFSIZE 128 74ec125fbbSEdward Tomasz Napierala 7536af9869SEdward Tomasz Napierala #define RCTL_PCPU_SHIFT (10 * 1000000) 7636af9869SEdward Tomasz Napierala 77ae34b6ffSEdward Tomasz Napierala static unsigned int rctl_maxbufsize = RCTL_MAX_OUTBUFSIZE; 78f70c075eSEdward Tomasz Napierala static int rctl_log_rate_limit = 10; 79f70c075eSEdward Tomasz Napierala static int rctl_devctl_rate_limit = 10; 808bd8c8f1SEdward Tomasz Napierala 818bd8c8f1SEdward Tomasz Napierala /* 828bd8c8f1SEdward Tomasz Napierala * Values below are initialized in rctl_init(). 838bd8c8f1SEdward Tomasz Napierala */ 848bd8c8f1SEdward Tomasz Napierala static int rctl_throttle_min = -1; 858bd8c8f1SEdward Tomasz Napierala static int rctl_throttle_max = -1; 868bd8c8f1SEdward Tomasz Napierala static int rctl_throttle_pct = -1; 878bd8c8f1SEdward Tomasz Napierala static int rctl_throttle_pct2 = -1; 888bd8c8f1SEdward Tomasz Napierala 898bd8c8f1SEdward Tomasz Napierala static int rctl_throttle_min_sysctl(SYSCTL_HANDLER_ARGS); 908bd8c8f1SEdward Tomasz Napierala static int rctl_throttle_max_sysctl(SYSCTL_HANDLER_ARGS); 918bd8c8f1SEdward Tomasz Napierala static int rctl_throttle_pct_sysctl(SYSCTL_HANDLER_ARGS); 928bd8c8f1SEdward Tomasz Napierala static int rctl_throttle_pct2_sysctl(SYSCTL_HANDLER_ARGS); 932b4035eeSEdward Tomasz Napierala 94e0d69c5aSPawel Biernacki SYSCTL_NODE(_kern_racct, OID_AUTO, rctl, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 95e0d69c5aSPawel Biernacki "Resource Limits"); 962b4035eeSEdward Tomasz Napierala SYSCTL_UINT(_kern_racct_rctl, OID_AUTO, maxbufsize, CTLFLAG_RWTUN, 972b4035eeSEdward Tomasz Napierala &rctl_maxbufsize, 0, "Maximum output buffer size"); 98f70c075eSEdward Tomasz Napierala SYSCTL_UINT(_kern_racct_rctl, OID_AUTO, log_rate_limit, CTLFLAG_RW, 99f70c075eSEdward Tomasz Napierala &rctl_log_rate_limit, 0, "Maximum number of log messages per second"); 1008bd8c8f1SEdward Tomasz Napierala SYSCTL_UINT(_kern_racct_rctl, OID_AUTO, devctl_rate_limit, CTLFLAG_RWTUN, 101f70c075eSEdward Tomasz Napierala &rctl_devctl_rate_limit, 0, "Maximum number of devctl messages per second"); 1028bd8c8f1SEdward Tomasz Napierala SYSCTL_PROC(_kern_racct_rctl, OID_AUTO, throttle_min, 103e0d69c5aSPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, 0, 104e0d69c5aSPawel Biernacki &rctl_throttle_min_sysctl, "IU", 1058bd8c8f1SEdward Tomasz Napierala "Shortest throttling duration, in hz"); 1068bd8c8f1SEdward Tomasz Napierala TUNABLE_INT("kern.racct.rctl.throttle_min", &rctl_throttle_min); 1078bd8c8f1SEdward Tomasz Napierala SYSCTL_PROC(_kern_racct_rctl, OID_AUTO, throttle_max, 108e0d69c5aSPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, 0, 109e0d69c5aSPawel Biernacki &rctl_throttle_max_sysctl, "IU", 1108bd8c8f1SEdward Tomasz Napierala "Longest throttling duration, in hz"); 1118bd8c8f1SEdward Tomasz Napierala TUNABLE_INT("kern.racct.rctl.throttle_max", &rctl_throttle_max); 1128bd8c8f1SEdward Tomasz Napierala SYSCTL_PROC(_kern_racct_rctl, OID_AUTO, throttle_pct, 113e0d69c5aSPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, 0, 114e0d69c5aSPawel Biernacki &rctl_throttle_pct_sysctl, "IU", 115ae34b6ffSEdward Tomasz Napierala "Throttling penalty for process consumption, in percent"); 1168bd8c8f1SEdward Tomasz Napierala TUNABLE_INT("kern.racct.rctl.throttle_pct", &rctl_throttle_pct); 1178bd8c8f1SEdward Tomasz Napierala SYSCTL_PROC(_kern_racct_rctl, OID_AUTO, throttle_pct2, 118e0d69c5aSPawel Biernacki CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, 0, 119e0d69c5aSPawel Biernacki &rctl_throttle_pct2_sysctl, "IU", 120ae34b6ffSEdward Tomasz Napierala "Throttling penalty for container consumption, in percent"); 1218bd8c8f1SEdward Tomasz Napierala TUNABLE_INT("kern.racct.rctl.throttle_pct2", &rctl_throttle_pct2); 1222b4035eeSEdward Tomasz Napierala 123ec125fbbSEdward Tomasz Napierala /* 124ec125fbbSEdward Tomasz Napierala * 'rctl_rule_link' connects a rule with every racct it's related to. 125ec125fbbSEdward Tomasz Napierala * For example, rule 'user:X:openfiles:deny=N/process' is linked 126ec125fbbSEdward Tomasz Napierala * with uidinfo for user X, and to each process of that user. 127ec125fbbSEdward Tomasz Napierala */ 128ec125fbbSEdward Tomasz Napierala struct rctl_rule_link { 129ec125fbbSEdward Tomasz Napierala LIST_ENTRY(rctl_rule_link) rrl_next; 130ec125fbbSEdward Tomasz Napierala struct rctl_rule *rrl_rule; 131ec125fbbSEdward Tomasz Napierala int rrl_exceeded; 132ec125fbbSEdward Tomasz Napierala }; 133ec125fbbSEdward Tomasz Napierala 134ec125fbbSEdward Tomasz Napierala struct dict { 135ec125fbbSEdward Tomasz Napierala const char *d_name; 136ec125fbbSEdward Tomasz Napierala int d_value; 137ec125fbbSEdward Tomasz Napierala }; 138ec125fbbSEdward Tomasz Napierala 139ec125fbbSEdward Tomasz Napierala static struct dict subjectnames[] = { 140ec125fbbSEdward Tomasz Napierala { "process", RCTL_SUBJECT_TYPE_PROCESS }, 141ec125fbbSEdward Tomasz Napierala { "user", RCTL_SUBJECT_TYPE_USER }, 142ec125fbbSEdward Tomasz Napierala { "loginclass", RCTL_SUBJECT_TYPE_LOGINCLASS }, 143ec125fbbSEdward Tomasz Napierala { "jail", RCTL_SUBJECT_TYPE_JAIL }, 144ec125fbbSEdward Tomasz Napierala { NULL, -1 }}; 145ec125fbbSEdward Tomasz Napierala 146ec125fbbSEdward Tomasz Napierala static struct dict resourcenames[] = { 14785a2f1b4SEdward Tomasz Napierala { "cputime", RACCT_CPU }, 14885a2f1b4SEdward Tomasz Napierala { "datasize", RACCT_DATA }, 14985a2f1b4SEdward Tomasz Napierala { "stacksize", RACCT_STACK }, 15085a2f1b4SEdward Tomasz Napierala { "coredumpsize", RACCT_CORE }, 15185a2f1b4SEdward Tomasz Napierala { "memoryuse", RACCT_RSS }, 15285a2f1b4SEdward Tomasz Napierala { "memorylocked", RACCT_MEMLOCK }, 15385a2f1b4SEdward Tomasz Napierala { "maxproc", RACCT_NPROC }, 15485a2f1b4SEdward Tomasz Napierala { "openfiles", RACCT_NOFILE }, 15585a2f1b4SEdward Tomasz Napierala { "vmemoryuse", RACCT_VMEM }, 15685a2f1b4SEdward Tomasz Napierala { "pseudoterminals", RACCT_NPTS }, 15785a2f1b4SEdward Tomasz Napierala { "swapuse", RACCT_SWAP }, 158ec125fbbSEdward Tomasz Napierala { "nthr", RACCT_NTHR }, 159ec125fbbSEdward Tomasz Napierala { "msgqqueued", RACCT_MSGQQUEUED }, 160ec125fbbSEdward Tomasz Napierala { "msgqsize", RACCT_MSGQSIZE }, 161ec125fbbSEdward Tomasz Napierala { "nmsgq", RACCT_NMSGQ }, 162ec125fbbSEdward Tomasz Napierala { "nsem", RACCT_NSEM }, 163ec125fbbSEdward Tomasz Napierala { "nsemop", RACCT_NSEMOP }, 164ec125fbbSEdward Tomasz Napierala { "nshm", RACCT_NSHM }, 165ec125fbbSEdward Tomasz Napierala { "shmsize", RACCT_SHMSIZE }, 166ec125fbbSEdward Tomasz Napierala { "wallclock", RACCT_WALLCLOCK }, 16736af9869SEdward Tomasz Napierala { "pcpu", RACCT_PCTCPU }, 168ae34b6ffSEdward Tomasz Napierala { "readbps", RACCT_READBPS }, 169ae34b6ffSEdward Tomasz Napierala { "writebps", RACCT_WRITEBPS }, 170ae34b6ffSEdward Tomasz Napierala { "readiops", RACCT_READIOPS }, 171ae34b6ffSEdward Tomasz Napierala { "writeiops", RACCT_WRITEIOPS }, 172ec125fbbSEdward Tomasz Napierala { NULL, -1 }}; 173ec125fbbSEdward Tomasz Napierala 174ec125fbbSEdward Tomasz Napierala static struct dict actionnames[] = { 175ec125fbbSEdward Tomasz Napierala { "sighup", RCTL_ACTION_SIGHUP }, 176ec125fbbSEdward Tomasz Napierala { "sigint", RCTL_ACTION_SIGINT }, 177ec125fbbSEdward Tomasz Napierala { "sigquit", RCTL_ACTION_SIGQUIT }, 178ec125fbbSEdward Tomasz Napierala { "sigill", RCTL_ACTION_SIGILL }, 179ec125fbbSEdward Tomasz Napierala { "sigtrap", RCTL_ACTION_SIGTRAP }, 180ec125fbbSEdward Tomasz Napierala { "sigabrt", RCTL_ACTION_SIGABRT }, 181ec125fbbSEdward Tomasz Napierala { "sigemt", RCTL_ACTION_SIGEMT }, 182ec125fbbSEdward Tomasz Napierala { "sigfpe", RCTL_ACTION_SIGFPE }, 183ec125fbbSEdward Tomasz Napierala { "sigkill", RCTL_ACTION_SIGKILL }, 184ec125fbbSEdward Tomasz Napierala { "sigbus", RCTL_ACTION_SIGBUS }, 185ec125fbbSEdward Tomasz Napierala { "sigsegv", RCTL_ACTION_SIGSEGV }, 186ec125fbbSEdward Tomasz Napierala { "sigsys", RCTL_ACTION_SIGSYS }, 187ec125fbbSEdward Tomasz Napierala { "sigpipe", RCTL_ACTION_SIGPIPE }, 188ec125fbbSEdward Tomasz Napierala { "sigalrm", RCTL_ACTION_SIGALRM }, 189ec125fbbSEdward Tomasz Napierala { "sigterm", RCTL_ACTION_SIGTERM }, 190ec125fbbSEdward Tomasz Napierala { "sigurg", RCTL_ACTION_SIGURG }, 191ec125fbbSEdward Tomasz Napierala { "sigstop", RCTL_ACTION_SIGSTOP }, 192ec125fbbSEdward Tomasz Napierala { "sigtstp", RCTL_ACTION_SIGTSTP }, 193ec125fbbSEdward Tomasz Napierala { "sigchld", RCTL_ACTION_SIGCHLD }, 194ec125fbbSEdward Tomasz Napierala { "sigttin", RCTL_ACTION_SIGTTIN }, 195ec125fbbSEdward Tomasz Napierala { "sigttou", RCTL_ACTION_SIGTTOU }, 196ec125fbbSEdward Tomasz Napierala { "sigio", RCTL_ACTION_SIGIO }, 197ec125fbbSEdward Tomasz Napierala { "sigxcpu", RCTL_ACTION_SIGXCPU }, 198ec125fbbSEdward Tomasz Napierala { "sigxfsz", RCTL_ACTION_SIGXFSZ }, 199ec125fbbSEdward Tomasz Napierala { "sigvtalrm", RCTL_ACTION_SIGVTALRM }, 200ec125fbbSEdward Tomasz Napierala { "sigprof", RCTL_ACTION_SIGPROF }, 201ec125fbbSEdward Tomasz Napierala { "sigwinch", RCTL_ACTION_SIGWINCH }, 202ec125fbbSEdward Tomasz Napierala { "siginfo", RCTL_ACTION_SIGINFO }, 203ec125fbbSEdward Tomasz Napierala { "sigusr1", RCTL_ACTION_SIGUSR1 }, 204ec125fbbSEdward Tomasz Napierala { "sigusr2", RCTL_ACTION_SIGUSR2 }, 205ec125fbbSEdward Tomasz Napierala { "sigthr", RCTL_ACTION_SIGTHR }, 206ec125fbbSEdward Tomasz Napierala { "deny", RCTL_ACTION_DENY }, 207ec125fbbSEdward Tomasz Napierala { "log", RCTL_ACTION_LOG }, 208ec125fbbSEdward Tomasz Napierala { "devctl", RCTL_ACTION_DEVCTL }, 209ae34b6ffSEdward Tomasz Napierala { "throttle", RCTL_ACTION_THROTTLE }, 210ec125fbbSEdward Tomasz Napierala { NULL, -1 }}; 211ec125fbbSEdward Tomasz Napierala 212ec125fbbSEdward Tomasz Napierala static void rctl_init(void); 213ec125fbbSEdward Tomasz Napierala SYSINIT(rctl, SI_SUB_RACCT, SI_ORDER_FIRST, rctl_init, NULL); 214ec125fbbSEdward Tomasz Napierala 215ec125fbbSEdward Tomasz Napierala static uma_zone_t rctl_rule_zone; 216c1a43e73SEdward Tomasz Napierala static uma_zone_t rctl_rule_link_zone; 2174c230cdaSEdward Tomasz Napierala 218ec125fbbSEdward Tomasz Napierala static int rctl_rule_fully_specified(const struct rctl_rule *rule); 219ec125fbbSEdward Tomasz Napierala static void rctl_rule_to_sbuf(struct sbuf *sb, const struct rctl_rule *rule); 220ec125fbbSEdward Tomasz Napierala 221d745c852SEd Schouten static MALLOC_DEFINE(M_RCTL, "rctl", "Resource Limits"); 222ec125fbbSEdward Tomasz Napierala 2238bd8c8f1SEdward Tomasz Napierala static int rctl_throttle_min_sysctl(SYSCTL_HANDLER_ARGS) 2248bd8c8f1SEdward Tomasz Napierala { 225c1a43e73SEdward Tomasz Napierala int error, val = rctl_throttle_min; 2268bd8c8f1SEdward Tomasz Napierala 2278bd8c8f1SEdward Tomasz Napierala error = sysctl_handle_int(oidp, &val, 0, req); 2288bd8c8f1SEdward Tomasz Napierala if (error || !req->newptr) 2298bd8c8f1SEdward Tomasz Napierala return (error); 2308bd8c8f1SEdward Tomasz Napierala if (val < 1 || val > rctl_throttle_max) 2318bd8c8f1SEdward Tomasz Napierala return (EINVAL); 2328bd8c8f1SEdward Tomasz Napierala 233bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 2348bd8c8f1SEdward Tomasz Napierala rctl_throttle_min = val; 235bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 2368bd8c8f1SEdward Tomasz Napierala 2378bd8c8f1SEdward Tomasz Napierala return (0); 2388bd8c8f1SEdward Tomasz Napierala } 2398bd8c8f1SEdward Tomasz Napierala 2408bd8c8f1SEdward Tomasz Napierala static int rctl_throttle_max_sysctl(SYSCTL_HANDLER_ARGS) 2418bd8c8f1SEdward Tomasz Napierala { 242c1a43e73SEdward Tomasz Napierala int error, val = rctl_throttle_max; 2438bd8c8f1SEdward Tomasz Napierala 2448bd8c8f1SEdward Tomasz Napierala error = sysctl_handle_int(oidp, &val, 0, req); 2458bd8c8f1SEdward Tomasz Napierala if (error || !req->newptr) 2468bd8c8f1SEdward Tomasz Napierala return (error); 2478bd8c8f1SEdward Tomasz Napierala if (val < rctl_throttle_min) 2488bd8c8f1SEdward Tomasz Napierala return (EINVAL); 2498bd8c8f1SEdward Tomasz Napierala 250bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 2518bd8c8f1SEdward Tomasz Napierala rctl_throttle_max = val; 252bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 2538bd8c8f1SEdward Tomasz Napierala 2548bd8c8f1SEdward Tomasz Napierala return (0); 2558bd8c8f1SEdward Tomasz Napierala } 2568bd8c8f1SEdward Tomasz Napierala 2578bd8c8f1SEdward Tomasz Napierala static int rctl_throttle_pct_sysctl(SYSCTL_HANDLER_ARGS) 2588bd8c8f1SEdward Tomasz Napierala { 259c1a43e73SEdward Tomasz Napierala int error, val = rctl_throttle_pct; 2608bd8c8f1SEdward Tomasz Napierala 2618bd8c8f1SEdward Tomasz Napierala error = sysctl_handle_int(oidp, &val, 0, req); 2628bd8c8f1SEdward Tomasz Napierala if (error || !req->newptr) 2638bd8c8f1SEdward Tomasz Napierala return (error); 2648bd8c8f1SEdward Tomasz Napierala if (val < 0) 2658bd8c8f1SEdward Tomasz Napierala return (EINVAL); 2668bd8c8f1SEdward Tomasz Napierala 267bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 2688bd8c8f1SEdward Tomasz Napierala rctl_throttle_pct = val; 269bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 2708bd8c8f1SEdward Tomasz Napierala 2718bd8c8f1SEdward Tomasz Napierala return (0); 2728bd8c8f1SEdward Tomasz Napierala } 2738bd8c8f1SEdward Tomasz Napierala 2748bd8c8f1SEdward Tomasz Napierala static int rctl_throttle_pct2_sysctl(SYSCTL_HANDLER_ARGS) 2758bd8c8f1SEdward Tomasz Napierala { 276c1a43e73SEdward Tomasz Napierala int error, val = rctl_throttle_pct2; 2778bd8c8f1SEdward Tomasz Napierala 2788bd8c8f1SEdward Tomasz Napierala error = sysctl_handle_int(oidp, &val, 0, req); 2798bd8c8f1SEdward Tomasz Napierala if (error || !req->newptr) 2808bd8c8f1SEdward Tomasz Napierala return (error); 2818bd8c8f1SEdward Tomasz Napierala if (val < 0) 2828bd8c8f1SEdward Tomasz Napierala return (EINVAL); 2838bd8c8f1SEdward Tomasz Napierala 284bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 2858bd8c8f1SEdward Tomasz Napierala rctl_throttle_pct2 = val; 286bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 2878bd8c8f1SEdward Tomasz Napierala 2888bd8c8f1SEdward Tomasz Napierala return (0); 2898bd8c8f1SEdward Tomasz Napierala } 2908bd8c8f1SEdward Tomasz Napierala 291ec125fbbSEdward Tomasz Napierala static const char * 292ec125fbbSEdward Tomasz Napierala rctl_subject_type_name(int subject) 293ec125fbbSEdward Tomasz Napierala { 294ec125fbbSEdward Tomasz Napierala int i; 295ec125fbbSEdward Tomasz Napierala 296ec125fbbSEdward Tomasz Napierala for (i = 0; subjectnames[i].d_name != NULL; i++) { 297ec125fbbSEdward Tomasz Napierala if (subjectnames[i].d_value == subject) 298ec125fbbSEdward Tomasz Napierala return (subjectnames[i].d_name); 299ec125fbbSEdward Tomasz Napierala } 300ec125fbbSEdward Tomasz Napierala 301ec125fbbSEdward Tomasz Napierala panic("rctl_subject_type_name: unknown subject type %d", subject); 302ec125fbbSEdward Tomasz Napierala } 303ec125fbbSEdward Tomasz Napierala 304ec125fbbSEdward Tomasz Napierala static const char * 305ec125fbbSEdward Tomasz Napierala rctl_action_name(int action) 306ec125fbbSEdward Tomasz Napierala { 307ec125fbbSEdward Tomasz Napierala int i; 308ec125fbbSEdward Tomasz Napierala 309ec125fbbSEdward Tomasz Napierala for (i = 0; actionnames[i].d_name != NULL; i++) { 310ec125fbbSEdward Tomasz Napierala if (actionnames[i].d_value == action) 311ec125fbbSEdward Tomasz Napierala return (actionnames[i].d_name); 312ec125fbbSEdward Tomasz Napierala } 313ec125fbbSEdward Tomasz Napierala 314ec125fbbSEdward Tomasz Napierala panic("rctl_action_name: unknown action %d", action); 315ec125fbbSEdward Tomasz Napierala } 316ec125fbbSEdward Tomasz Napierala 317ec125fbbSEdward Tomasz Napierala const char * 318ec125fbbSEdward Tomasz Napierala rctl_resource_name(int resource) 319ec125fbbSEdward Tomasz Napierala { 320ec125fbbSEdward Tomasz Napierala int i; 321ec125fbbSEdward Tomasz Napierala 322ec125fbbSEdward Tomasz Napierala for (i = 0; resourcenames[i].d_name != NULL; i++) { 323ec125fbbSEdward Tomasz Napierala if (resourcenames[i].d_value == resource) 324ec125fbbSEdward Tomasz Napierala return (resourcenames[i].d_name); 325ec125fbbSEdward Tomasz Napierala } 326ec125fbbSEdward Tomasz Napierala 327ec125fbbSEdward Tomasz Napierala panic("rctl_resource_name: unknown resource %d", resource); 328ec125fbbSEdward Tomasz Napierala } 329ec125fbbSEdward Tomasz Napierala 330ac3c9819SEdward Tomasz Napierala static struct racct * 331ac3c9819SEdward Tomasz Napierala rctl_proc_rule_to_racct(const struct proc *p, const struct rctl_rule *rule) 332ac3c9819SEdward Tomasz Napierala { 333ac3c9819SEdward Tomasz Napierala struct ucred *cred = p->p_ucred; 334ac3c9819SEdward Tomasz Napierala 335ac3c9819SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 336bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 337ac3c9819SEdward Tomasz Napierala 338ac3c9819SEdward Tomasz Napierala switch (rule->rr_per) { 339ac3c9819SEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_PROCESS: 340ac3c9819SEdward Tomasz Napierala return (p->p_racct); 341ac3c9819SEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_USER: 342ac3c9819SEdward Tomasz Napierala return (cred->cr_ruidinfo->ui_racct); 343ac3c9819SEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_LOGINCLASS: 344ac3c9819SEdward Tomasz Napierala return (cred->cr_loginclass->lc_racct); 345ac3c9819SEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_JAIL: 346ac3c9819SEdward Tomasz Napierala return (cred->cr_prison->pr_prison_racct->prr_racct); 347ac3c9819SEdward Tomasz Napierala default: 348ac3c9819SEdward Tomasz Napierala panic("%s: unknown per %d", __func__, rule->rr_per); 349ac3c9819SEdward Tomasz Napierala } 350ac3c9819SEdward Tomasz Napierala } 351ac3c9819SEdward Tomasz Napierala 352ec125fbbSEdward Tomasz Napierala /* 353ec125fbbSEdward Tomasz Napierala * Return the amount of resource that can be allocated by 'p' before 354ec125fbbSEdward Tomasz Napierala * hitting 'rule'. 355ec125fbbSEdward Tomasz Napierala */ 356ec125fbbSEdward Tomasz Napierala static int64_t 357ec125fbbSEdward Tomasz Napierala rctl_available_resource(const struct proc *p, const struct rctl_rule *rule) 358ec125fbbSEdward Tomasz Napierala { 359ac3c9819SEdward Tomasz Napierala const struct racct *racct; 360c1a43e73SEdward Tomasz Napierala int64_t available; 361ec125fbbSEdward Tomasz Napierala 3624b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 363bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 364ec125fbbSEdward Tomasz Napierala 365ac3c9819SEdward Tomasz Napierala racct = rctl_proc_rule_to_racct(p, rule); 366ac3c9819SEdward Tomasz Napierala available = rule->rr_amount - racct->r_resources[rule->rr_resource]; 367ec125fbbSEdward Tomasz Napierala 368ec125fbbSEdward Tomasz Napierala return (available); 369ec125fbbSEdward Tomasz Napierala } 370ec125fbbSEdward Tomasz Napierala 371ec125fbbSEdward Tomasz Napierala /* 372ae34b6ffSEdward Tomasz Napierala * Called every second for proc, uidinfo, loginclass, and jail containers. 373ae34b6ffSEdward Tomasz Napierala * If the limit isn't exceeded, it decreases the usage amount to zero. 374ae34b6ffSEdward Tomasz Napierala * Otherwise, it decreases it by the value of the limit. This way 375ae34b6ffSEdward Tomasz Napierala * resource consumption exceeding the limit "carries over" to the next 376ae34b6ffSEdward Tomasz Napierala * period. 377ec125fbbSEdward Tomasz Napierala */ 378ae34b6ffSEdward Tomasz Napierala void 379ae34b6ffSEdward Tomasz Napierala rctl_throttle_decay(struct racct *racct, int resource) 380ec125fbbSEdward Tomasz Napierala { 381ae34b6ffSEdward Tomasz Napierala struct rctl_rule *rule; 382ae34b6ffSEdward Tomasz Napierala struct rctl_rule_link *link; 383ae34b6ffSEdward Tomasz Napierala int64_t minavailable; 384ec125fbbSEdward Tomasz Napierala 3854b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 386bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 387ec125fbbSEdward Tomasz Napierala 388ae34b6ffSEdward Tomasz Napierala minavailable = INT64_MAX; 389ec125fbbSEdward Tomasz Napierala 390ae34b6ffSEdward Tomasz Napierala LIST_FOREACH(link, &racct->r_rule_links, rrl_next) { 391ae34b6ffSEdward Tomasz Napierala rule = link->rrl_rule; 392ae34b6ffSEdward Tomasz Napierala 393ae34b6ffSEdward Tomasz Napierala if (rule->rr_resource != resource) 394ae34b6ffSEdward Tomasz Napierala continue; 395ae34b6ffSEdward Tomasz Napierala if (rule->rr_action != RCTL_ACTION_THROTTLE) 396ae34b6ffSEdward Tomasz Napierala continue; 397ae34b6ffSEdward Tomasz Napierala 398ae34b6ffSEdward Tomasz Napierala if (rule->rr_amount < minavailable) 399ae34b6ffSEdward Tomasz Napierala minavailable = rule->rr_amount; 400ae34b6ffSEdward Tomasz Napierala } 401ae34b6ffSEdward Tomasz Napierala 402ae34b6ffSEdward Tomasz Napierala if (racct->r_resources[resource] < minavailable) { 403ae34b6ffSEdward Tomasz Napierala racct->r_resources[resource] = 0; 404ae34b6ffSEdward Tomasz Napierala } else { 405ae34b6ffSEdward Tomasz Napierala /* 406ae34b6ffSEdward Tomasz Napierala * Cap utilization counter at ten times the limit. Otherwise, 407ae34b6ffSEdward Tomasz Napierala * if we changed the rule lowering the allowed amount, it could 408ae34b6ffSEdward Tomasz Napierala * take unreasonably long time for the accumulated resource 409ae34b6ffSEdward Tomasz Napierala * usage to drop. 410ae34b6ffSEdward Tomasz Napierala */ 411ae34b6ffSEdward Tomasz Napierala if (racct->r_resources[resource] > minavailable * 10) 412ae34b6ffSEdward Tomasz Napierala racct->r_resources[resource] = minavailable * 10; 413ae34b6ffSEdward Tomasz Napierala 414ae34b6ffSEdward Tomasz Napierala racct->r_resources[resource] -= minavailable; 415ae34b6ffSEdward Tomasz Napierala } 416ec125fbbSEdward Tomasz Napierala } 417ec125fbbSEdward Tomasz Napierala 418ec125fbbSEdward Tomasz Napierala /* 419af1a7b25SEdward Tomasz Napierala * Special version of rctl_get_available() for the %CPU resource. 42036af9869SEdward Tomasz Napierala * We slightly cheat here and return less than we normally would. 42136af9869SEdward Tomasz Napierala */ 42236af9869SEdward Tomasz Napierala int64_t 42336af9869SEdward Tomasz Napierala rctl_pcpu_available(const struct proc *p) { 42436af9869SEdward Tomasz Napierala struct rctl_rule *rule; 42536af9869SEdward Tomasz Napierala struct rctl_rule_link *link; 42636af9869SEdward Tomasz Napierala int64_t available, minavailable, limit; 42736af9869SEdward Tomasz Napierala 4284b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 429bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 4304b5c9cf6SEdward Tomasz Napierala 43136af9869SEdward Tomasz Napierala minavailable = INT64_MAX; 43236af9869SEdward Tomasz Napierala limit = 0; 43336af9869SEdward Tomasz Napierala 43436af9869SEdward Tomasz Napierala LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) { 43536af9869SEdward Tomasz Napierala rule = link->rrl_rule; 43636af9869SEdward Tomasz Napierala if (rule->rr_resource != RACCT_PCTCPU) 43736af9869SEdward Tomasz Napierala continue; 43836af9869SEdward Tomasz Napierala if (rule->rr_action != RCTL_ACTION_DENY) 43936af9869SEdward Tomasz Napierala continue; 44036af9869SEdward Tomasz Napierala available = rctl_available_resource(p, rule); 44136af9869SEdward Tomasz Napierala if (available < minavailable) { 44236af9869SEdward Tomasz Napierala minavailable = available; 44336af9869SEdward Tomasz Napierala limit = rule->rr_amount; 44436af9869SEdward Tomasz Napierala } 44536af9869SEdward Tomasz Napierala } 44636af9869SEdward Tomasz Napierala 44736af9869SEdward Tomasz Napierala /* 44836af9869SEdward Tomasz Napierala * Return slightly less than actual value of the available 449e3043798SPedro F. Giffuni * %cpu resource. This makes %cpu throttling more aggressive 45036af9869SEdward Tomasz Napierala * and lets us act sooner than the limits are already exceeded. 45136af9869SEdward Tomasz Napierala */ 45236af9869SEdward Tomasz Napierala if (limit != 0) { 45336af9869SEdward Tomasz Napierala if (limit > 2 * RCTL_PCPU_SHIFT) 45436af9869SEdward Tomasz Napierala minavailable -= RCTL_PCPU_SHIFT; 45536af9869SEdward Tomasz Napierala else 45636af9869SEdward Tomasz Napierala minavailable -= (limit / 2); 45736af9869SEdward Tomasz Napierala } 45836af9869SEdward Tomasz Napierala 45936af9869SEdward Tomasz Napierala return (minavailable); 46036af9869SEdward Tomasz Napierala } 46136af9869SEdward Tomasz Napierala 462ae34b6ffSEdward Tomasz Napierala static uint64_t 463ae34b6ffSEdward Tomasz Napierala xadd(uint64_t a, uint64_t b) 464ae34b6ffSEdward Tomasz Napierala { 465ae34b6ffSEdward Tomasz Napierala uint64_t c; 466ae34b6ffSEdward Tomasz Napierala 467ae34b6ffSEdward Tomasz Napierala c = a + b; 468ae34b6ffSEdward Tomasz Napierala 469ae34b6ffSEdward Tomasz Napierala /* 470ae34b6ffSEdward Tomasz Napierala * Detect overflow. 471ae34b6ffSEdward Tomasz Napierala */ 472ae34b6ffSEdward Tomasz Napierala if (c < a || c < b) 473ae34b6ffSEdward Tomasz Napierala return (UINT64_MAX); 474ae34b6ffSEdward Tomasz Napierala 475ae34b6ffSEdward Tomasz Napierala return (c); 476ae34b6ffSEdward Tomasz Napierala } 477ae34b6ffSEdward Tomasz Napierala 478ae34b6ffSEdward Tomasz Napierala static uint64_t 479ae34b6ffSEdward Tomasz Napierala xmul(uint64_t a, uint64_t b) 480ae34b6ffSEdward Tomasz Napierala { 481ae34b6ffSEdward Tomasz Napierala 482f459a818SEdward Tomasz Napierala if (b != 0 && a > UINT64_MAX / b) 483ae34b6ffSEdward Tomasz Napierala return (UINT64_MAX); 484ae34b6ffSEdward Tomasz Napierala 485f459a818SEdward Tomasz Napierala return (a * b); 486ae34b6ffSEdward Tomasz Napierala } 487ae34b6ffSEdward Tomasz Napierala 48836af9869SEdward Tomasz Napierala /* 489ec125fbbSEdward Tomasz Napierala * Check whether the proc 'p' can allocate 'amount' of 'resource' in addition 490ec125fbbSEdward Tomasz Napierala * to what it keeps allocated now. Returns non-zero if the allocation should 491ec125fbbSEdward Tomasz Napierala * be denied, 0 otherwise. 492ec125fbbSEdward Tomasz Napierala */ 493ec125fbbSEdward Tomasz Napierala int 494ec125fbbSEdward Tomasz Napierala rctl_enforce(struct proc *p, int resource, uint64_t amount) 495ec125fbbSEdward Tomasz Napierala { 496f70c075eSEdward Tomasz Napierala static struct timeval log_lasttime, devctl_lasttime; 497f70c075eSEdward Tomasz Napierala static int log_curtime = 0, devctl_curtime = 0; 498ec125fbbSEdward Tomasz Napierala struct rctl_rule *rule; 499ec125fbbSEdward Tomasz Napierala struct rctl_rule_link *link; 500ec125fbbSEdward Tomasz Napierala struct sbuf sb; 501c1a43e73SEdward Tomasz Napierala char *buf; 502ae34b6ffSEdward Tomasz Napierala int64_t available; 503ae34b6ffSEdward Tomasz Napierala uint64_t sleep_ms, sleep_ratio; 504ec125fbbSEdward Tomasz Napierala int should_deny = 0; 505ec125fbbSEdward Tomasz Napierala 5064b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 507bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 508ec125fbbSEdward Tomasz Napierala 509ec125fbbSEdward Tomasz Napierala /* 510ec125fbbSEdward Tomasz Napierala * There may be more than one matching rule; go through all of them. 511ec125fbbSEdward Tomasz Napierala * Denial should be done last, after logging and sending signals. 512ec125fbbSEdward Tomasz Napierala */ 513ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) { 514ec125fbbSEdward Tomasz Napierala rule = link->rrl_rule; 515ec125fbbSEdward Tomasz Napierala if (rule->rr_resource != resource) 516ec125fbbSEdward Tomasz Napierala continue; 517ae34b6ffSEdward Tomasz Napierala 518ae34b6ffSEdward Tomasz Napierala available = rctl_available_resource(p, rule); 519ae34b6ffSEdward Tomasz Napierala if (available >= (int64_t)amount) { 520ec125fbbSEdward Tomasz Napierala link->rrl_exceeded = 0; 521ec125fbbSEdward Tomasz Napierala continue; 522ec125fbbSEdward Tomasz Napierala } 523ec125fbbSEdward Tomasz Napierala 524ec125fbbSEdward Tomasz Napierala switch (rule->rr_action) { 525ec125fbbSEdward Tomasz Napierala case RCTL_ACTION_DENY: 526ec125fbbSEdward Tomasz Napierala should_deny = 1; 527ec125fbbSEdward Tomasz Napierala continue; 528ec125fbbSEdward Tomasz Napierala case RCTL_ACTION_LOG: 529ec125fbbSEdward Tomasz Napierala /* 530ec125fbbSEdward Tomasz Napierala * If rrl_exceeded != 0, it means we've already 531ec125fbbSEdward Tomasz Napierala * logged a warning for this process. 532ec125fbbSEdward Tomasz Napierala */ 533ec125fbbSEdward Tomasz Napierala if (link->rrl_exceeded != 0) 534ec125fbbSEdward Tomasz Napierala continue; 535ec125fbbSEdward Tomasz Napierala 53672a401d9SEdward Tomasz Napierala /* 53772a401d9SEdward Tomasz Napierala * If the process state is not fully initialized yet, 53872a401d9SEdward Tomasz Napierala * we can't access most of the required fields, e.g. 53972a401d9SEdward Tomasz Napierala * p->p_comm. This happens when called from fork1(). 54072a401d9SEdward Tomasz Napierala * Ignore this rule for now; it will be processed just 54172a401d9SEdward Tomasz Napierala * after fork, when called from racct_proc_fork_done(). 54272a401d9SEdward Tomasz Napierala */ 54372a401d9SEdward Tomasz Napierala if (p->p_state != PRS_NORMAL) 54472a401d9SEdward Tomasz Napierala continue; 54572a401d9SEdward Tomasz Napierala 546f70c075eSEdward Tomasz Napierala if (!ppsratecheck(&log_lasttime, &log_curtime, 547f70c075eSEdward Tomasz Napierala rctl_log_rate_limit)) 548ec125fbbSEdward Tomasz Napierala continue; 549ec125fbbSEdward Tomasz Napierala 550ec125fbbSEdward Tomasz Napierala buf = malloc(RCTL_LOG_BUFSIZE, M_RCTL, M_NOWAIT); 551ec125fbbSEdward Tomasz Napierala if (buf == NULL) { 552ec125fbbSEdward Tomasz Napierala printf("rctl_enforce: out of memory\n"); 553ec125fbbSEdward Tomasz Napierala continue; 554ec125fbbSEdward Tomasz Napierala } 555ec125fbbSEdward Tomasz Napierala sbuf_new(&sb, buf, RCTL_LOG_BUFSIZE, SBUF_FIXEDLEN); 556ec125fbbSEdward Tomasz Napierala rctl_rule_to_sbuf(&sb, rule); 557ec125fbbSEdward Tomasz Napierala sbuf_finish(&sb); 558ec125fbbSEdward Tomasz Napierala printf("rctl: rule \"%s\" matched by pid %d " 559ec125fbbSEdward Tomasz Napierala "(%s), uid %d, jail %s\n", sbuf_data(&sb), 560ec125fbbSEdward Tomasz Napierala p->p_pid, p->p_comm, p->p_ucred->cr_uid, 561a7ad07bfSEdward Tomasz Napierala p->p_ucred->cr_prison->pr_prison_racct->prr_name); 562ec125fbbSEdward Tomasz Napierala sbuf_delete(&sb); 563ec125fbbSEdward Tomasz Napierala free(buf, M_RCTL); 564ec125fbbSEdward Tomasz Napierala link->rrl_exceeded = 1; 565ec125fbbSEdward Tomasz Napierala continue; 566ec125fbbSEdward Tomasz Napierala case RCTL_ACTION_DEVCTL: 567ec125fbbSEdward Tomasz Napierala if (link->rrl_exceeded != 0) 568ec125fbbSEdward Tomasz Napierala continue; 569ec125fbbSEdward Tomasz Napierala 57072a401d9SEdward Tomasz Napierala if (p->p_state != PRS_NORMAL) 57172a401d9SEdward Tomasz Napierala continue; 57272a401d9SEdward Tomasz Napierala 573f70c075eSEdward Tomasz Napierala if (!ppsratecheck(&devctl_lasttime, &devctl_curtime, 574f70c075eSEdward Tomasz Napierala rctl_devctl_rate_limit)) 575f70c075eSEdward Tomasz Napierala continue; 576f70c075eSEdward Tomasz Napierala 577ec125fbbSEdward Tomasz Napierala buf = malloc(RCTL_LOG_BUFSIZE, M_RCTL, M_NOWAIT); 578ec125fbbSEdward Tomasz Napierala if (buf == NULL) { 579ec125fbbSEdward Tomasz Napierala printf("rctl_enforce: out of memory\n"); 580ec125fbbSEdward Tomasz Napierala continue; 581ec125fbbSEdward Tomasz Napierala } 582ec125fbbSEdward Tomasz Napierala sbuf_new(&sb, buf, RCTL_LOG_BUFSIZE, SBUF_FIXEDLEN); 5830a713948SAlexander Motin sbuf_cat(&sb, "rule="); 584ec125fbbSEdward Tomasz Napierala rctl_rule_to_sbuf(&sb, rule); 585ec125fbbSEdward Tomasz Napierala sbuf_printf(&sb, " pid=%d ruid=%d jail=%s", 586ec125fbbSEdward Tomasz Napierala p->p_pid, p->p_ucred->cr_ruid, 587a7ad07bfSEdward Tomasz Napierala p->p_ucred->cr_prison->pr_prison_racct->prr_name); 588ec125fbbSEdward Tomasz Napierala sbuf_finish(&sb); 589887611b1SWarner Losh devctl_notify("RCTL", "rule", "matched", 590887611b1SWarner Losh sbuf_data(&sb)); 591ec125fbbSEdward Tomasz Napierala sbuf_delete(&sb); 592ec125fbbSEdward Tomasz Napierala free(buf, M_RCTL); 593ec125fbbSEdward Tomasz Napierala link->rrl_exceeded = 1; 594ec125fbbSEdward Tomasz Napierala continue; 595ae34b6ffSEdward Tomasz Napierala case RCTL_ACTION_THROTTLE: 596ae34b6ffSEdward Tomasz Napierala if (p->p_state != PRS_NORMAL) 597ae34b6ffSEdward Tomasz Napierala continue; 598ae34b6ffSEdward Tomasz Napierala 599e8a5a1adSJason A. Harmening if (rule->rr_amount == 0) { 600e8a5a1adSJason A. Harmening racct_proc_throttle(p, rctl_throttle_max); 601e8a5a1adSJason A. Harmening continue; 602e8a5a1adSJason A. Harmening } 603e8a5a1adSJason A. Harmening 604ae34b6ffSEdward Tomasz Napierala /* 605ae34b6ffSEdward Tomasz Napierala * Make the process sleep for a fraction of second 606ae34b6ffSEdward Tomasz Napierala * proportional to the ratio of process' resource 607ae34b6ffSEdward Tomasz Napierala * utilization compared to the limit. The point is 608ae34b6ffSEdward Tomasz Napierala * to penalize resource hogs: processes that consume 609ae34b6ffSEdward Tomasz Napierala * more of the available resources sleep for longer. 610ae34b6ffSEdward Tomasz Napierala * 611ae34b6ffSEdward Tomasz Napierala * We're trying to defer division until the very end, 612ae34b6ffSEdward Tomasz Napierala * to minimize the rounding effects. The following 613ae34b6ffSEdward Tomasz Napierala * calculation could have been written in a clearer 614ae34b6ffSEdward Tomasz Napierala * way like this: 615ae34b6ffSEdward Tomasz Napierala * 616ae34b6ffSEdward Tomasz Napierala * sleep_ms = hz * p->p_racct->r_resources[resource] / 617ae34b6ffSEdward Tomasz Napierala * rule->rr_amount; 618ae34b6ffSEdward Tomasz Napierala * sleep_ms *= rctl_throttle_pct / 100; 619ae34b6ffSEdward Tomasz Napierala * if (sleep_ms < rctl_throttle_min) 620ae34b6ffSEdward Tomasz Napierala * sleep_ms = rctl_throttle_min; 621ae34b6ffSEdward Tomasz Napierala * 622ae34b6ffSEdward Tomasz Napierala */ 623ae34b6ffSEdward Tomasz Napierala sleep_ms = xmul(hz, p->p_racct->r_resources[resource]); 624ae34b6ffSEdward Tomasz Napierala sleep_ms = xmul(sleep_ms, rctl_throttle_pct) / 100; 625ae34b6ffSEdward Tomasz Napierala if (sleep_ms < rctl_throttle_min * rule->rr_amount) 626ae34b6ffSEdward Tomasz Napierala sleep_ms = rctl_throttle_min * rule->rr_amount; 627ae34b6ffSEdward Tomasz Napierala 628ae34b6ffSEdward Tomasz Napierala /* 629ae34b6ffSEdward Tomasz Napierala * Multiply that by the ratio of the resource 630ae34b6ffSEdward Tomasz Napierala * consumption for the container compared to the limit, 631ae34b6ffSEdward Tomasz Napierala * squared. In other words, a process in a container 632ae34b6ffSEdward Tomasz Napierala * that is two times over the limit will be throttled 633ae34b6ffSEdward Tomasz Napierala * four times as much for hitting the same rule. The 634ae34b6ffSEdward Tomasz Napierala * point is to penalize processes more if the container 635ae34b6ffSEdward Tomasz Napierala * itself (eg certain UID or jail) is above the limit. 636ae34b6ffSEdward Tomasz Napierala */ 637ae34b6ffSEdward Tomasz Napierala if (available < 0) 638ae34b6ffSEdward Tomasz Napierala sleep_ratio = -available / rule->rr_amount; 639ae34b6ffSEdward Tomasz Napierala else 640ae34b6ffSEdward Tomasz Napierala sleep_ratio = 0; 641ae34b6ffSEdward Tomasz Napierala sleep_ratio = xmul(sleep_ratio, sleep_ratio); 642ae34b6ffSEdward Tomasz Napierala sleep_ratio = xmul(sleep_ratio, rctl_throttle_pct2) / 100; 643ae34b6ffSEdward Tomasz Napierala sleep_ms = xadd(sleep_ms, xmul(sleep_ms, sleep_ratio)); 644ae34b6ffSEdward Tomasz Napierala 645ae34b6ffSEdward Tomasz Napierala /* 646ae34b6ffSEdward Tomasz Napierala * Finally the division. 647ae34b6ffSEdward Tomasz Napierala */ 648ae34b6ffSEdward Tomasz Napierala sleep_ms /= rule->rr_amount; 649ae34b6ffSEdward Tomasz Napierala 650ae34b6ffSEdward Tomasz Napierala if (sleep_ms > rctl_throttle_max) 651ae34b6ffSEdward Tomasz Napierala sleep_ms = rctl_throttle_max; 652ae34b6ffSEdward Tomasz Napierala #if 0 65374a7305aSEdward Tomasz Napierala printf("%s: pid %d (%s), %jd of %jd, will sleep for %ju ms (ratio %ju, available %jd)\n", 654ae34b6ffSEdward Tomasz Napierala __func__, p->p_pid, p->p_comm, 655ae34b6ffSEdward Tomasz Napierala p->p_racct->r_resources[resource], 65674a7305aSEdward Tomasz Napierala rule->rr_amount, (uintmax_t)sleep_ms, 65774a7305aSEdward Tomasz Napierala (uintmax_t)sleep_ratio, (intmax_t)available); 658ae34b6ffSEdward Tomasz Napierala #endif 659ae34b6ffSEdward Tomasz Napierala 660ae34b6ffSEdward Tomasz Napierala KASSERT(sleep_ms >= rctl_throttle_min, ("%s: %ju < %d\n", 661ae34b6ffSEdward Tomasz Napierala __func__, (uintmax_t)sleep_ms, rctl_throttle_min)); 662ae34b6ffSEdward Tomasz Napierala racct_proc_throttle(p, sleep_ms); 663ae34b6ffSEdward Tomasz Napierala continue; 664ec125fbbSEdward Tomasz Napierala default: 665ec125fbbSEdward Tomasz Napierala if (link->rrl_exceeded != 0) 666ec125fbbSEdward Tomasz Napierala continue; 667ec125fbbSEdward Tomasz Napierala 66872a401d9SEdward Tomasz Napierala if (p->p_state != PRS_NORMAL) 66972a401d9SEdward Tomasz Napierala continue; 67072a401d9SEdward Tomasz Napierala 671ec125fbbSEdward Tomasz Napierala KASSERT(rule->rr_action > 0 && 672ec125fbbSEdward Tomasz Napierala rule->rr_action <= RCTL_ACTION_SIGNAL_MAX, 673ec125fbbSEdward Tomasz Napierala ("rctl_enforce: unknown action %d", 674ec125fbbSEdward Tomasz Napierala rule->rr_action)); 675ec125fbbSEdward Tomasz Napierala 676ec125fbbSEdward Tomasz Napierala /* 677ec125fbbSEdward Tomasz Napierala * We're using the fact that RCTL_ACTION_SIG* values 678ec125fbbSEdward Tomasz Napierala * are equal to their counterparts from sys/signal.h. 679ec125fbbSEdward Tomasz Napierala */ 6808451d0ddSKip Macy kern_psignal(p, rule->rr_action); 681ec125fbbSEdward Tomasz Napierala link->rrl_exceeded = 1; 682ec125fbbSEdward Tomasz Napierala continue; 683ec125fbbSEdward Tomasz Napierala } 684ec125fbbSEdward Tomasz Napierala } 685ec125fbbSEdward Tomasz Napierala 686ec125fbbSEdward Tomasz Napierala if (should_deny) { 687ec125fbbSEdward Tomasz Napierala /* 688ec125fbbSEdward Tomasz Napierala * Return fake error code; the caller should change it 689ec125fbbSEdward Tomasz Napierala * into one proper for the situation - EFSIZ, ENOMEM etc. 690ec125fbbSEdward Tomasz Napierala */ 691ec125fbbSEdward Tomasz Napierala return (EDOOFUS); 692ec125fbbSEdward Tomasz Napierala } 693ec125fbbSEdward Tomasz Napierala 694ec125fbbSEdward Tomasz Napierala return (0); 695ec125fbbSEdward Tomasz Napierala } 696ec125fbbSEdward Tomasz Napierala 697ec125fbbSEdward Tomasz Napierala uint64_t 698ec125fbbSEdward Tomasz Napierala rctl_get_limit(struct proc *p, int resource) 699ec125fbbSEdward Tomasz Napierala { 700ec125fbbSEdward Tomasz Napierala struct rctl_rule *rule; 701ec125fbbSEdward Tomasz Napierala struct rctl_rule_link *link; 702ec125fbbSEdward Tomasz Napierala uint64_t amount = UINT64_MAX; 703ec125fbbSEdward Tomasz Napierala 7044b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 705bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 706ec125fbbSEdward Tomasz Napierala 707ec125fbbSEdward Tomasz Napierala /* 708ec125fbbSEdward Tomasz Napierala * There may be more than one matching rule; go through all of them. 709ec125fbbSEdward Tomasz Napierala * Denial should be done last, after logging and sending signals. 710ec125fbbSEdward Tomasz Napierala */ 711ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) { 712ec125fbbSEdward Tomasz Napierala rule = link->rrl_rule; 713ec125fbbSEdward Tomasz Napierala if (rule->rr_resource != resource) 714ec125fbbSEdward Tomasz Napierala continue; 715ec125fbbSEdward Tomasz Napierala if (rule->rr_action != RCTL_ACTION_DENY) 716ec125fbbSEdward Tomasz Napierala continue; 717ec125fbbSEdward Tomasz Napierala if (rule->rr_amount < amount) 718ec125fbbSEdward Tomasz Napierala amount = rule->rr_amount; 719ec125fbbSEdward Tomasz Napierala } 720ec125fbbSEdward Tomasz Napierala 721ec125fbbSEdward Tomasz Napierala return (amount); 722ec125fbbSEdward Tomasz Napierala } 723ec125fbbSEdward Tomasz Napierala 724ec125fbbSEdward Tomasz Napierala uint64_t 725ec125fbbSEdward Tomasz Napierala rctl_get_available(struct proc *p, int resource) 726ec125fbbSEdward Tomasz Napierala { 727ec125fbbSEdward Tomasz Napierala struct rctl_rule *rule; 728ec125fbbSEdward Tomasz Napierala struct rctl_rule_link *link; 729ec125fbbSEdward Tomasz Napierala int64_t available, minavailable, allocated; 730ec125fbbSEdward Tomasz Napierala 731ec125fbbSEdward Tomasz Napierala minavailable = INT64_MAX; 732ec125fbbSEdward Tomasz Napierala 7334b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 734bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 735ec125fbbSEdward Tomasz Napierala 736ec125fbbSEdward Tomasz Napierala /* 737ec125fbbSEdward Tomasz Napierala * There may be more than one matching rule; go through all of them. 738ec125fbbSEdward Tomasz Napierala * Denial should be done last, after logging and sending signals. 739ec125fbbSEdward Tomasz Napierala */ 740ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) { 741ec125fbbSEdward Tomasz Napierala rule = link->rrl_rule; 742ec125fbbSEdward Tomasz Napierala if (rule->rr_resource != resource) 743ec125fbbSEdward Tomasz Napierala continue; 744ec125fbbSEdward Tomasz Napierala if (rule->rr_action != RCTL_ACTION_DENY) 745ec125fbbSEdward Tomasz Napierala continue; 746ec125fbbSEdward Tomasz Napierala available = rctl_available_resource(p, rule); 747ec125fbbSEdward Tomasz Napierala if (available < minavailable) 748ec125fbbSEdward Tomasz Napierala minavailable = available; 749ec125fbbSEdward Tomasz Napierala } 750ec125fbbSEdward Tomasz Napierala 751ec125fbbSEdward Tomasz Napierala /* 752ec125fbbSEdward Tomasz Napierala * XXX: Think about this _hard_. 753ec125fbbSEdward Tomasz Napierala */ 754ec125fbbSEdward Tomasz Napierala allocated = p->p_racct->r_resources[resource]; 755ec125fbbSEdward Tomasz Napierala if (minavailable < INT64_MAX - allocated) 756ec125fbbSEdward Tomasz Napierala minavailable += allocated; 757ec125fbbSEdward Tomasz Napierala if (minavailable < 0) 758ec125fbbSEdward Tomasz Napierala minavailable = 0; 759bbe4eb6dSEdward Tomasz Napierala 760ec125fbbSEdward Tomasz Napierala return (minavailable); 761ec125fbbSEdward Tomasz Napierala } 762ec125fbbSEdward Tomasz Napierala 763ec125fbbSEdward Tomasz Napierala static int 764ec125fbbSEdward Tomasz Napierala rctl_rule_matches(const struct rctl_rule *rule, const struct rctl_rule *filter) 765ec125fbbSEdward Tomasz Napierala { 766ec125fbbSEdward Tomasz Napierala 7674b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 7684b5c9cf6SEdward Tomasz Napierala 769ec125fbbSEdward Tomasz Napierala if (filter->rr_subject_type != RCTL_SUBJECT_TYPE_UNDEFINED) { 770ec125fbbSEdward Tomasz Napierala if (rule->rr_subject_type != filter->rr_subject_type) 771ec125fbbSEdward Tomasz Napierala return (0); 772ec125fbbSEdward Tomasz Napierala 773ec125fbbSEdward Tomasz Napierala switch (filter->rr_subject_type) { 774ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_PROCESS: 775ec125fbbSEdward Tomasz Napierala if (filter->rr_subject.rs_proc != NULL && 776ec125fbbSEdward Tomasz Napierala rule->rr_subject.rs_proc != 777ec125fbbSEdward Tomasz Napierala filter->rr_subject.rs_proc) 778ec125fbbSEdward Tomasz Napierala return (0); 779ec125fbbSEdward Tomasz Napierala break; 780ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_USER: 781ec125fbbSEdward Tomasz Napierala if (filter->rr_subject.rs_uip != NULL && 782ec125fbbSEdward Tomasz Napierala rule->rr_subject.rs_uip != 783ec125fbbSEdward Tomasz Napierala filter->rr_subject.rs_uip) 784ec125fbbSEdward Tomasz Napierala return (0); 785ec125fbbSEdward Tomasz Napierala break; 786ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_LOGINCLASS: 787415896e3SEdward Tomasz Napierala if (filter->rr_subject.rs_loginclass != NULL && 788415896e3SEdward Tomasz Napierala rule->rr_subject.rs_loginclass != 789415896e3SEdward Tomasz Napierala filter->rr_subject.rs_loginclass) 790ec125fbbSEdward Tomasz Napierala return (0); 791ec125fbbSEdward Tomasz Napierala break; 792ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_JAIL: 793a7ad07bfSEdward Tomasz Napierala if (filter->rr_subject.rs_prison_racct != NULL && 794a7ad07bfSEdward Tomasz Napierala rule->rr_subject.rs_prison_racct != 795a7ad07bfSEdward Tomasz Napierala filter->rr_subject.rs_prison_racct) 796ec125fbbSEdward Tomasz Napierala return (0); 797ec125fbbSEdward Tomasz Napierala break; 798ec125fbbSEdward Tomasz Napierala default: 799ec125fbbSEdward Tomasz Napierala panic("rctl_rule_matches: unknown subject type %d", 800ec125fbbSEdward Tomasz Napierala filter->rr_subject_type); 801ec125fbbSEdward Tomasz Napierala } 802ec125fbbSEdward Tomasz Napierala } 803ec125fbbSEdward Tomasz Napierala 804ec125fbbSEdward Tomasz Napierala if (filter->rr_resource != RACCT_UNDEFINED) { 805ec125fbbSEdward Tomasz Napierala if (rule->rr_resource != filter->rr_resource) 806ec125fbbSEdward Tomasz Napierala return (0); 807ec125fbbSEdward Tomasz Napierala } 808ec125fbbSEdward Tomasz Napierala 809ec125fbbSEdward Tomasz Napierala if (filter->rr_action != RCTL_ACTION_UNDEFINED) { 810ec125fbbSEdward Tomasz Napierala if (rule->rr_action != filter->rr_action) 811ec125fbbSEdward Tomasz Napierala return (0); 812ec125fbbSEdward Tomasz Napierala } 813ec125fbbSEdward Tomasz Napierala 814ec125fbbSEdward Tomasz Napierala if (filter->rr_amount != RCTL_AMOUNT_UNDEFINED) { 815ec125fbbSEdward Tomasz Napierala if (rule->rr_amount != filter->rr_amount) 816ec125fbbSEdward Tomasz Napierala return (0); 817ec125fbbSEdward Tomasz Napierala } 818ec125fbbSEdward Tomasz Napierala 819ec125fbbSEdward Tomasz Napierala if (filter->rr_per != RCTL_SUBJECT_TYPE_UNDEFINED) { 820ec125fbbSEdward Tomasz Napierala if (rule->rr_per != filter->rr_per) 821ec125fbbSEdward Tomasz Napierala return (0); 822ec125fbbSEdward Tomasz Napierala } 823ec125fbbSEdward Tomasz Napierala 824ec125fbbSEdward Tomasz Napierala return (1); 825ec125fbbSEdward Tomasz Napierala } 826ec125fbbSEdward Tomasz Napierala 827ec125fbbSEdward Tomasz Napierala static int 828ec125fbbSEdward Tomasz Napierala str2value(const char *str, int *value, struct dict *table) 829ec125fbbSEdward Tomasz Napierala { 830ec125fbbSEdward Tomasz Napierala int i; 831ec125fbbSEdward Tomasz Napierala 832ec125fbbSEdward Tomasz Napierala if (value == NULL) 833ec125fbbSEdward Tomasz Napierala return (EINVAL); 834ec125fbbSEdward Tomasz Napierala 835ec125fbbSEdward Tomasz Napierala for (i = 0; table[i].d_name != NULL; i++) { 836ec125fbbSEdward Tomasz Napierala if (strcasecmp(table[i].d_name, str) == 0) { 837ec125fbbSEdward Tomasz Napierala *value = table[i].d_value; 838ec125fbbSEdward Tomasz Napierala return (0); 839ec125fbbSEdward Tomasz Napierala } 840ec125fbbSEdward Tomasz Napierala } 841ec125fbbSEdward Tomasz Napierala 842ec125fbbSEdward Tomasz Napierala return (EINVAL); 843ec125fbbSEdward Tomasz Napierala } 844ec125fbbSEdward Tomasz Napierala 845ec125fbbSEdward Tomasz Napierala static int 846ec125fbbSEdward Tomasz Napierala str2id(const char *str, id_t *value) 847ec125fbbSEdward Tomasz Napierala { 848ec125fbbSEdward Tomasz Napierala char *end; 849ec125fbbSEdward Tomasz Napierala 850ec125fbbSEdward Tomasz Napierala if (str == NULL) 851ec125fbbSEdward Tomasz Napierala return (EINVAL); 852ec125fbbSEdward Tomasz Napierala 853ec125fbbSEdward Tomasz Napierala *value = strtoul(str, &end, 10); 854ec125fbbSEdward Tomasz Napierala if ((size_t)(end - str) != strlen(str)) 855ec125fbbSEdward Tomasz Napierala return (EINVAL); 856ec125fbbSEdward Tomasz Napierala 857ec125fbbSEdward Tomasz Napierala return (0); 858ec125fbbSEdward Tomasz Napierala } 859ec125fbbSEdward Tomasz Napierala 860ec125fbbSEdward Tomasz Napierala static int 861ec125fbbSEdward Tomasz Napierala str2int64(const char *str, int64_t *value) 862ec125fbbSEdward Tomasz Napierala { 863ec125fbbSEdward Tomasz Napierala char *end; 864ec125fbbSEdward Tomasz Napierala 865ec125fbbSEdward Tomasz Napierala if (str == NULL) 866ec125fbbSEdward Tomasz Napierala return (EINVAL); 867ec125fbbSEdward Tomasz Napierala 868ec125fbbSEdward Tomasz Napierala *value = strtoul(str, &end, 10); 869ec125fbbSEdward Tomasz Napierala if ((size_t)(end - str) != strlen(str)) 870ec125fbbSEdward Tomasz Napierala return (EINVAL); 871ec125fbbSEdward Tomasz Napierala 872b450d447SEdward Tomasz Napierala if (*value < 0) 873b450d447SEdward Tomasz Napierala return (ERANGE); 874b450d447SEdward Tomasz Napierala 875ec125fbbSEdward Tomasz Napierala return (0); 876ec125fbbSEdward Tomasz Napierala } 877ec125fbbSEdward Tomasz Napierala 878ec125fbbSEdward Tomasz Napierala /* 879ec125fbbSEdward Tomasz Napierala * Connect the rule to the racct, increasing refcount for the rule. 880ec125fbbSEdward Tomasz Napierala */ 881ec125fbbSEdward Tomasz Napierala static void 882ec125fbbSEdward Tomasz Napierala rctl_racct_add_rule(struct racct *racct, struct rctl_rule *rule) 883ec125fbbSEdward Tomasz Napierala { 884ec125fbbSEdward Tomasz Napierala struct rctl_rule_link *link; 885ec125fbbSEdward Tomasz Napierala 8864b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 887ec125fbbSEdward Tomasz Napierala KASSERT(rctl_rule_fully_specified(rule), ("rule not fully specified")); 888ec125fbbSEdward Tomasz Napierala 889ec125fbbSEdward Tomasz Napierala rctl_rule_acquire(rule); 890ec125fbbSEdward Tomasz Napierala link = uma_zalloc(rctl_rule_link_zone, M_WAITOK); 891ec125fbbSEdward Tomasz Napierala link->rrl_rule = rule; 892ec125fbbSEdward Tomasz Napierala link->rrl_exceeded = 0; 893ec125fbbSEdward Tomasz Napierala 894bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 895ec125fbbSEdward Tomasz Napierala LIST_INSERT_HEAD(&racct->r_rule_links, link, rrl_next); 896bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 897ec125fbbSEdward Tomasz Napierala } 898ec125fbbSEdward Tomasz Napierala 899ec125fbbSEdward Tomasz Napierala static int 900ec125fbbSEdward Tomasz Napierala rctl_racct_add_rule_locked(struct racct *racct, struct rctl_rule *rule) 901ec125fbbSEdward Tomasz Napierala { 902ec125fbbSEdward Tomasz Napierala struct rctl_rule_link *link; 903ec125fbbSEdward Tomasz Napierala 9044b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 905ec125fbbSEdward Tomasz Napierala KASSERT(rctl_rule_fully_specified(rule), ("rule not fully specified")); 906bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 907ec125fbbSEdward Tomasz Napierala 908ec125fbbSEdward Tomasz Napierala link = uma_zalloc(rctl_rule_link_zone, M_NOWAIT); 909ec125fbbSEdward Tomasz Napierala if (link == NULL) 910ec125fbbSEdward Tomasz Napierala return (ENOMEM); 911ec125fbbSEdward Tomasz Napierala rctl_rule_acquire(rule); 912ec125fbbSEdward Tomasz Napierala link->rrl_rule = rule; 913ec125fbbSEdward Tomasz Napierala link->rrl_exceeded = 0; 914ec125fbbSEdward Tomasz Napierala 915ec125fbbSEdward Tomasz Napierala LIST_INSERT_HEAD(&racct->r_rule_links, link, rrl_next); 916bbe4eb6dSEdward Tomasz Napierala 917ec125fbbSEdward Tomasz Napierala return (0); 918ec125fbbSEdward Tomasz Napierala } 919ec125fbbSEdward Tomasz Napierala 920ec125fbbSEdward Tomasz Napierala /* 921ec125fbbSEdward Tomasz Napierala * Remove limits for a rules matching the filter and release 922ec125fbbSEdward Tomasz Napierala * the refcounts for the rules, possibly freeing them. Returns 923ec125fbbSEdward Tomasz Napierala * the number of limit structures removed. 924ec125fbbSEdward Tomasz Napierala */ 925ec125fbbSEdward Tomasz Napierala static int 926ec125fbbSEdward Tomasz Napierala rctl_racct_remove_rules(struct racct *racct, 927ec125fbbSEdward Tomasz Napierala const struct rctl_rule *filter) 928ec125fbbSEdward Tomasz Napierala { 929ec125fbbSEdward Tomasz Napierala struct rctl_rule_link *link, *linktmp; 930c1a43e73SEdward Tomasz Napierala int removed = 0; 931ec125fbbSEdward Tomasz Napierala 9324b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 933bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 934ec125fbbSEdward Tomasz Napierala 935ec125fbbSEdward Tomasz Napierala LIST_FOREACH_SAFE(link, &racct->r_rule_links, rrl_next, linktmp) { 936ec125fbbSEdward Tomasz Napierala if (!rctl_rule_matches(link->rrl_rule, filter)) 937ec125fbbSEdward Tomasz Napierala continue; 938ec125fbbSEdward Tomasz Napierala 939ec125fbbSEdward Tomasz Napierala LIST_REMOVE(link, rrl_next); 940ec125fbbSEdward Tomasz Napierala rctl_rule_release(link->rrl_rule); 941ec125fbbSEdward Tomasz Napierala uma_zfree(rctl_rule_link_zone, link); 942ec125fbbSEdward Tomasz Napierala removed++; 943ec125fbbSEdward Tomasz Napierala } 944ec125fbbSEdward Tomasz Napierala return (removed); 945ec125fbbSEdward Tomasz Napierala } 946ec125fbbSEdward Tomasz Napierala 947ec125fbbSEdward Tomasz Napierala static void 948ec125fbbSEdward Tomasz Napierala rctl_rule_acquire_subject(struct rctl_rule *rule) 949ec125fbbSEdward Tomasz Napierala { 950ec125fbbSEdward Tomasz Napierala 9514b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 9524b5c9cf6SEdward Tomasz Napierala 953ec125fbbSEdward Tomasz Napierala switch (rule->rr_subject_type) { 954ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_UNDEFINED: 955ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_PROCESS: 956a7ad07bfSEdward Tomasz Napierala break; 957ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_JAIL: 958a7ad07bfSEdward Tomasz Napierala if (rule->rr_subject.rs_prison_racct != NULL) 959a7ad07bfSEdward Tomasz Napierala prison_racct_hold(rule->rr_subject.rs_prison_racct); 960ec125fbbSEdward Tomasz Napierala break; 961ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_USER: 962ec125fbbSEdward Tomasz Napierala if (rule->rr_subject.rs_uip != NULL) 963ec125fbbSEdward Tomasz Napierala uihold(rule->rr_subject.rs_uip); 964ec125fbbSEdward Tomasz Napierala break; 965ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_LOGINCLASS: 966415896e3SEdward Tomasz Napierala if (rule->rr_subject.rs_loginclass != NULL) 967415896e3SEdward Tomasz Napierala loginclass_hold(rule->rr_subject.rs_loginclass); 968ec125fbbSEdward Tomasz Napierala break; 969ec125fbbSEdward Tomasz Napierala default: 970ec125fbbSEdward Tomasz Napierala panic("rctl_rule_acquire_subject: unknown subject type %d", 971ec125fbbSEdward Tomasz Napierala rule->rr_subject_type); 972ec125fbbSEdward Tomasz Napierala } 973ec125fbbSEdward Tomasz Napierala } 974ec125fbbSEdward Tomasz Napierala 975ec125fbbSEdward Tomasz Napierala static void 976ec125fbbSEdward Tomasz Napierala rctl_rule_release_subject(struct rctl_rule *rule) 977ec125fbbSEdward Tomasz Napierala { 978ec125fbbSEdward Tomasz Napierala 9794b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 9804b5c9cf6SEdward Tomasz Napierala 981ec125fbbSEdward Tomasz Napierala switch (rule->rr_subject_type) { 982ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_UNDEFINED: 983ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_PROCESS: 984a7ad07bfSEdward Tomasz Napierala break; 985ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_JAIL: 986a7ad07bfSEdward Tomasz Napierala if (rule->rr_subject.rs_prison_racct != NULL) 987a7ad07bfSEdward Tomasz Napierala prison_racct_free(rule->rr_subject.rs_prison_racct); 988ec125fbbSEdward Tomasz Napierala break; 989ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_USER: 990ec125fbbSEdward Tomasz Napierala if (rule->rr_subject.rs_uip != NULL) 991ec125fbbSEdward Tomasz Napierala uifree(rule->rr_subject.rs_uip); 992ec125fbbSEdward Tomasz Napierala break; 993ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_LOGINCLASS: 994415896e3SEdward Tomasz Napierala if (rule->rr_subject.rs_loginclass != NULL) 995415896e3SEdward Tomasz Napierala loginclass_free(rule->rr_subject.rs_loginclass); 996ec125fbbSEdward Tomasz Napierala break; 997ec125fbbSEdward Tomasz Napierala default: 998ec125fbbSEdward Tomasz Napierala panic("rctl_rule_release_subject: unknown subject type %d", 999ec125fbbSEdward Tomasz Napierala rule->rr_subject_type); 1000ec125fbbSEdward Tomasz Napierala } 1001ec125fbbSEdward Tomasz Napierala } 1002ec125fbbSEdward Tomasz Napierala 1003ec125fbbSEdward Tomasz Napierala struct rctl_rule * 1004ec125fbbSEdward Tomasz Napierala rctl_rule_alloc(int flags) 1005ec125fbbSEdward Tomasz Napierala { 1006ec125fbbSEdward Tomasz Napierala struct rctl_rule *rule; 1007ec125fbbSEdward Tomasz Napierala 10084b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 10094b5c9cf6SEdward Tomasz Napierala 1010ec125fbbSEdward Tomasz Napierala rule = uma_zalloc(rctl_rule_zone, flags); 1011ec125fbbSEdward Tomasz Napierala if (rule == NULL) 1012ec125fbbSEdward Tomasz Napierala return (NULL); 1013ec125fbbSEdward Tomasz Napierala rule->rr_subject_type = RCTL_SUBJECT_TYPE_UNDEFINED; 1014ec125fbbSEdward Tomasz Napierala rule->rr_subject.rs_proc = NULL; 1015ec125fbbSEdward Tomasz Napierala rule->rr_subject.rs_uip = NULL; 1016415896e3SEdward Tomasz Napierala rule->rr_subject.rs_loginclass = NULL; 1017a7ad07bfSEdward Tomasz Napierala rule->rr_subject.rs_prison_racct = NULL; 1018ec125fbbSEdward Tomasz Napierala rule->rr_per = RCTL_SUBJECT_TYPE_UNDEFINED; 1019ec125fbbSEdward Tomasz Napierala rule->rr_resource = RACCT_UNDEFINED; 1020ec125fbbSEdward Tomasz Napierala rule->rr_action = RCTL_ACTION_UNDEFINED; 1021ec125fbbSEdward Tomasz Napierala rule->rr_amount = RCTL_AMOUNT_UNDEFINED; 1022ec125fbbSEdward Tomasz Napierala refcount_init(&rule->rr_refcount, 1); 1023ec125fbbSEdward Tomasz Napierala 1024ec125fbbSEdward Tomasz Napierala return (rule); 1025ec125fbbSEdward Tomasz Napierala } 1026ec125fbbSEdward Tomasz Napierala 1027ec125fbbSEdward Tomasz Napierala struct rctl_rule * 1028ec125fbbSEdward Tomasz Napierala rctl_rule_duplicate(const struct rctl_rule *rule, int flags) 1029ec125fbbSEdward Tomasz Napierala { 1030ec125fbbSEdward Tomasz Napierala struct rctl_rule *copy; 1031ec125fbbSEdward Tomasz Napierala 10324b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 10334b5c9cf6SEdward Tomasz Napierala 1034ec125fbbSEdward Tomasz Napierala copy = uma_zalloc(rctl_rule_zone, flags); 1035ec125fbbSEdward Tomasz Napierala if (copy == NULL) 1036ec125fbbSEdward Tomasz Napierala return (NULL); 1037ec125fbbSEdward Tomasz Napierala copy->rr_subject_type = rule->rr_subject_type; 1038ec125fbbSEdward Tomasz Napierala copy->rr_subject.rs_proc = rule->rr_subject.rs_proc; 1039ec125fbbSEdward Tomasz Napierala copy->rr_subject.rs_uip = rule->rr_subject.rs_uip; 1040415896e3SEdward Tomasz Napierala copy->rr_subject.rs_loginclass = rule->rr_subject.rs_loginclass; 1041a7ad07bfSEdward Tomasz Napierala copy->rr_subject.rs_prison_racct = rule->rr_subject.rs_prison_racct; 1042ec125fbbSEdward Tomasz Napierala copy->rr_per = rule->rr_per; 1043ec125fbbSEdward Tomasz Napierala copy->rr_resource = rule->rr_resource; 1044ec125fbbSEdward Tomasz Napierala copy->rr_action = rule->rr_action; 1045ec125fbbSEdward Tomasz Napierala copy->rr_amount = rule->rr_amount; 1046ec125fbbSEdward Tomasz Napierala refcount_init(©->rr_refcount, 1); 1047ec125fbbSEdward Tomasz Napierala rctl_rule_acquire_subject(copy); 1048ec125fbbSEdward Tomasz Napierala 1049ec125fbbSEdward Tomasz Napierala return (copy); 1050ec125fbbSEdward Tomasz Napierala } 1051ec125fbbSEdward Tomasz Napierala 1052ec125fbbSEdward Tomasz Napierala void 1053ec125fbbSEdward Tomasz Napierala rctl_rule_acquire(struct rctl_rule *rule) 1054ec125fbbSEdward Tomasz Napierala { 1055ec125fbbSEdward Tomasz Napierala 10564b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 1057ec125fbbSEdward Tomasz Napierala KASSERT(rule->rr_refcount > 0, ("rule->rr_refcount <= 0")); 1058ec125fbbSEdward Tomasz Napierala 1059ec125fbbSEdward Tomasz Napierala refcount_acquire(&rule->rr_refcount); 1060ec125fbbSEdward Tomasz Napierala } 1061ec125fbbSEdward Tomasz Napierala 1062ec125fbbSEdward Tomasz Napierala static void 1063ec125fbbSEdward Tomasz Napierala rctl_rule_free(void *context, int pending) 1064ec125fbbSEdward Tomasz Napierala { 1065ec125fbbSEdward Tomasz Napierala struct rctl_rule *rule; 1066ec125fbbSEdward Tomasz Napierala 1067ec125fbbSEdward Tomasz Napierala rule = (struct rctl_rule *)context; 1068ec125fbbSEdward Tomasz Napierala 10694b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 1070ec125fbbSEdward Tomasz Napierala KASSERT(rule->rr_refcount == 0, ("rule->rr_refcount != 0")); 1071ec125fbbSEdward Tomasz Napierala 1072ec125fbbSEdward Tomasz Napierala /* 1073ec125fbbSEdward Tomasz Napierala * We don't need locking here; rule is guaranteed to be inaccessible. 1074ec125fbbSEdward Tomasz Napierala */ 1075ec125fbbSEdward Tomasz Napierala 1076ec125fbbSEdward Tomasz Napierala rctl_rule_release_subject(rule); 1077ec125fbbSEdward Tomasz Napierala uma_zfree(rctl_rule_zone, rule); 1078ec125fbbSEdward Tomasz Napierala } 1079ec125fbbSEdward Tomasz Napierala 1080ec125fbbSEdward Tomasz Napierala void 1081ec125fbbSEdward Tomasz Napierala rctl_rule_release(struct rctl_rule *rule) 1082ec125fbbSEdward Tomasz Napierala { 1083ec125fbbSEdward Tomasz Napierala 10844b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 1085ec125fbbSEdward Tomasz Napierala KASSERT(rule->rr_refcount > 0, ("rule->rr_refcount <= 0")); 1086ec125fbbSEdward Tomasz Napierala 1087ec125fbbSEdward Tomasz Napierala if (refcount_release(&rule->rr_refcount)) { 1088ec125fbbSEdward Tomasz Napierala /* 1089ec125fbbSEdward Tomasz Napierala * rctl_rule_release() is often called when iterating 1090ec125fbbSEdward Tomasz Napierala * over all the uidinfo structures in the system, 1091ec125fbbSEdward Tomasz Napierala * holding uihashtbl_lock. Since rctl_rule_free() 1092ec125fbbSEdward Tomasz Napierala * might end up calling uifree(), this would lead 1093ec125fbbSEdward Tomasz Napierala * to lock recursion. Use taskqueue to avoid this. 1094ec125fbbSEdward Tomasz Napierala */ 1095ec125fbbSEdward Tomasz Napierala TASK_INIT(&rule->rr_task, 0, rctl_rule_free, rule); 1096ec125fbbSEdward Tomasz Napierala taskqueue_enqueue(taskqueue_thread, &rule->rr_task); 1097ec125fbbSEdward Tomasz Napierala } 1098ec125fbbSEdward Tomasz Napierala } 1099ec125fbbSEdward Tomasz Napierala 1100ec125fbbSEdward Tomasz Napierala static int 1101ec125fbbSEdward Tomasz Napierala rctl_rule_fully_specified(const struct rctl_rule *rule) 1102ec125fbbSEdward Tomasz Napierala { 1103ec125fbbSEdward Tomasz Napierala 11044b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 11054b5c9cf6SEdward Tomasz Napierala 1106ec125fbbSEdward Tomasz Napierala switch (rule->rr_subject_type) { 1107ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_UNDEFINED: 1108ec125fbbSEdward Tomasz Napierala return (0); 1109ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_PROCESS: 1110ec125fbbSEdward Tomasz Napierala if (rule->rr_subject.rs_proc == NULL) 1111ec125fbbSEdward Tomasz Napierala return (0); 1112ec125fbbSEdward Tomasz Napierala break; 1113ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_USER: 1114ec125fbbSEdward Tomasz Napierala if (rule->rr_subject.rs_uip == NULL) 1115ec125fbbSEdward Tomasz Napierala return (0); 1116ec125fbbSEdward Tomasz Napierala break; 1117ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_LOGINCLASS: 1118415896e3SEdward Tomasz Napierala if (rule->rr_subject.rs_loginclass == NULL) 1119ec125fbbSEdward Tomasz Napierala return (0); 1120ec125fbbSEdward Tomasz Napierala break; 1121ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_JAIL: 1122a7ad07bfSEdward Tomasz Napierala if (rule->rr_subject.rs_prison_racct == NULL) 1123ec125fbbSEdward Tomasz Napierala return (0); 1124ec125fbbSEdward Tomasz Napierala break; 1125ec125fbbSEdward Tomasz Napierala default: 1126ec125fbbSEdward Tomasz Napierala panic("rctl_rule_fully_specified: unknown subject type %d", 1127ec125fbbSEdward Tomasz Napierala rule->rr_subject_type); 1128ec125fbbSEdward Tomasz Napierala } 1129ec125fbbSEdward Tomasz Napierala if (rule->rr_resource == RACCT_UNDEFINED) 1130ec125fbbSEdward Tomasz Napierala return (0); 1131ec125fbbSEdward Tomasz Napierala if (rule->rr_action == RCTL_ACTION_UNDEFINED) 1132ec125fbbSEdward Tomasz Napierala return (0); 1133ec125fbbSEdward Tomasz Napierala if (rule->rr_amount == RCTL_AMOUNT_UNDEFINED) 1134ec125fbbSEdward Tomasz Napierala return (0); 1135ec125fbbSEdward Tomasz Napierala if (rule->rr_per == RCTL_SUBJECT_TYPE_UNDEFINED) 1136ec125fbbSEdward Tomasz Napierala return (0); 1137ec125fbbSEdward Tomasz Napierala 1138ec125fbbSEdward Tomasz Napierala return (1); 1139ec125fbbSEdward Tomasz Napierala } 1140ec125fbbSEdward Tomasz Napierala 1141ec125fbbSEdward Tomasz Napierala static int 1142ec125fbbSEdward Tomasz Napierala rctl_string_to_rule(char *rulestr, struct rctl_rule **rulep) 1143ec125fbbSEdward Tomasz Napierala { 1144c1a43e73SEdward Tomasz Napierala struct rctl_rule *rule; 1145ec125fbbSEdward Tomasz Napierala char *subjectstr, *subject_idstr, *resourcestr, *actionstr, 1146ec125fbbSEdward Tomasz Napierala *amountstr, *perstr; 1147ec125fbbSEdward Tomasz Napierala id_t id; 1148c1a43e73SEdward Tomasz Napierala int error = 0; 1149ec125fbbSEdward Tomasz Napierala 11504b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 11514b5c9cf6SEdward Tomasz Napierala 1152ec125fbbSEdward Tomasz Napierala rule = rctl_rule_alloc(M_WAITOK); 1153ec125fbbSEdward Tomasz Napierala 1154ec125fbbSEdward Tomasz Napierala subjectstr = strsep(&rulestr, ":"); 1155ec125fbbSEdward Tomasz Napierala subject_idstr = strsep(&rulestr, ":"); 1156ec125fbbSEdward Tomasz Napierala resourcestr = strsep(&rulestr, ":"); 1157ec125fbbSEdward Tomasz Napierala actionstr = strsep(&rulestr, "=/"); 1158ec125fbbSEdward Tomasz Napierala amountstr = strsep(&rulestr, "/"); 1159ec125fbbSEdward Tomasz Napierala perstr = rulestr; 1160ec125fbbSEdward Tomasz Napierala 1161ec125fbbSEdward Tomasz Napierala if (subjectstr == NULL || subjectstr[0] == '\0') 1162ec125fbbSEdward Tomasz Napierala rule->rr_subject_type = RCTL_SUBJECT_TYPE_UNDEFINED; 1163ec125fbbSEdward Tomasz Napierala else { 1164ec125fbbSEdward Tomasz Napierala error = str2value(subjectstr, &rule->rr_subject_type, subjectnames); 1165ec125fbbSEdward Tomasz Napierala if (error != 0) 1166ec125fbbSEdward Tomasz Napierala goto out; 1167ec125fbbSEdward Tomasz Napierala } 1168ec125fbbSEdward Tomasz Napierala 1169ec125fbbSEdward Tomasz Napierala if (subject_idstr == NULL || subject_idstr[0] == '\0') { 1170ec125fbbSEdward Tomasz Napierala rule->rr_subject.rs_proc = NULL; 1171ec125fbbSEdward Tomasz Napierala rule->rr_subject.rs_uip = NULL; 1172415896e3SEdward Tomasz Napierala rule->rr_subject.rs_loginclass = NULL; 1173a7ad07bfSEdward Tomasz Napierala rule->rr_subject.rs_prison_racct = NULL; 1174ec125fbbSEdward Tomasz Napierala } else { 1175ec125fbbSEdward Tomasz Napierala switch (rule->rr_subject_type) { 1176ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_UNDEFINED: 1177ec125fbbSEdward Tomasz Napierala error = EINVAL; 1178ec125fbbSEdward Tomasz Napierala goto out; 1179ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_PROCESS: 1180ec125fbbSEdward Tomasz Napierala error = str2id(subject_idstr, &id); 1181ec125fbbSEdward Tomasz Napierala if (error != 0) 1182ec125fbbSEdward Tomasz Napierala goto out; 1183ec125fbbSEdward Tomasz Napierala sx_assert(&allproc_lock, SA_LOCKED); 1184ec125fbbSEdward Tomasz Napierala rule->rr_subject.rs_proc = pfind(id); 1185ec125fbbSEdward Tomasz Napierala if (rule->rr_subject.rs_proc == NULL) { 1186ec125fbbSEdward Tomasz Napierala error = ESRCH; 1187ec125fbbSEdward Tomasz Napierala goto out; 1188ec125fbbSEdward Tomasz Napierala } 1189ec125fbbSEdward Tomasz Napierala PROC_UNLOCK(rule->rr_subject.rs_proc); 1190ec125fbbSEdward Tomasz Napierala break; 1191ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_USER: 1192ec125fbbSEdward Tomasz Napierala error = str2id(subject_idstr, &id); 1193ec125fbbSEdward Tomasz Napierala if (error != 0) 1194ec125fbbSEdward Tomasz Napierala goto out; 1195ec125fbbSEdward Tomasz Napierala rule->rr_subject.rs_uip = uifind(id); 1196ec125fbbSEdward Tomasz Napierala break; 1197ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_LOGINCLASS: 1198415896e3SEdward Tomasz Napierala rule->rr_subject.rs_loginclass = 1199ec125fbbSEdward Tomasz Napierala loginclass_find(subject_idstr); 1200415896e3SEdward Tomasz Napierala if (rule->rr_subject.rs_loginclass == NULL) { 1201ec125fbbSEdward Tomasz Napierala error = ENAMETOOLONG; 1202ec125fbbSEdward Tomasz Napierala goto out; 1203ec125fbbSEdward Tomasz Napierala } 1204ec125fbbSEdward Tomasz Napierala break; 1205ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_JAIL: 1206a7ad07bfSEdward Tomasz Napierala rule->rr_subject.rs_prison_racct = 1207a7ad07bfSEdward Tomasz Napierala prison_racct_find(subject_idstr); 1208a7ad07bfSEdward Tomasz Napierala if (rule->rr_subject.rs_prison_racct == NULL) { 1209a7ad07bfSEdward Tomasz Napierala error = ENAMETOOLONG; 1210ec125fbbSEdward Tomasz Napierala goto out; 1211ec125fbbSEdward Tomasz Napierala } 1212ec125fbbSEdward Tomasz Napierala break; 1213ec125fbbSEdward Tomasz Napierala default: 1214ec125fbbSEdward Tomasz Napierala panic("rctl_string_to_rule: unknown subject type %d", 1215ec125fbbSEdward Tomasz Napierala rule->rr_subject_type); 1216ec125fbbSEdward Tomasz Napierala } 1217ec125fbbSEdward Tomasz Napierala } 1218ec125fbbSEdward Tomasz Napierala 1219ec125fbbSEdward Tomasz Napierala if (resourcestr == NULL || resourcestr[0] == '\0') 1220ec125fbbSEdward Tomasz Napierala rule->rr_resource = RACCT_UNDEFINED; 1221ec125fbbSEdward Tomasz Napierala else { 1222ec125fbbSEdward Tomasz Napierala error = str2value(resourcestr, &rule->rr_resource, 1223ec125fbbSEdward Tomasz Napierala resourcenames); 1224ec125fbbSEdward Tomasz Napierala if (error != 0) 1225ec125fbbSEdward Tomasz Napierala goto out; 1226ec125fbbSEdward Tomasz Napierala } 1227ec125fbbSEdward Tomasz Napierala 1228ec125fbbSEdward Tomasz Napierala if (actionstr == NULL || actionstr[0] == '\0') 1229ec125fbbSEdward Tomasz Napierala rule->rr_action = RCTL_ACTION_UNDEFINED; 1230ec125fbbSEdward Tomasz Napierala else { 1231ec125fbbSEdward Tomasz Napierala error = str2value(actionstr, &rule->rr_action, actionnames); 1232ec125fbbSEdward Tomasz Napierala if (error != 0) 1233ec125fbbSEdward Tomasz Napierala goto out; 1234ec125fbbSEdward Tomasz Napierala } 1235ec125fbbSEdward Tomasz Napierala 1236ec125fbbSEdward Tomasz Napierala if (amountstr == NULL || amountstr[0] == '\0') 1237ec125fbbSEdward Tomasz Napierala rule->rr_amount = RCTL_AMOUNT_UNDEFINED; 1238ec125fbbSEdward Tomasz Napierala else { 1239ec125fbbSEdward Tomasz Napierala error = str2int64(amountstr, &rule->rr_amount); 1240ec125fbbSEdward Tomasz Napierala if (error != 0) 1241ec125fbbSEdward Tomasz Napierala goto out; 1242b450d447SEdward Tomasz Napierala if (RACCT_IS_IN_MILLIONS(rule->rr_resource)) { 1243b450d447SEdward Tomasz Napierala if (rule->rr_amount > INT64_MAX / 1000000) { 1244b450d447SEdward Tomasz Napierala error = ERANGE; 1245b450d447SEdward Tomasz Napierala goto out; 1246b450d447SEdward Tomasz Napierala } 1247cff08ec0SEdward Tomasz Napierala rule->rr_amount *= 1000000; 1248ec125fbbSEdward Tomasz Napierala } 1249b450d447SEdward Tomasz Napierala } 1250ec125fbbSEdward Tomasz Napierala 1251ec125fbbSEdward Tomasz Napierala if (perstr == NULL || perstr[0] == '\0') 1252ec125fbbSEdward Tomasz Napierala rule->rr_per = RCTL_SUBJECT_TYPE_UNDEFINED; 1253ec125fbbSEdward Tomasz Napierala else { 1254ec125fbbSEdward Tomasz Napierala error = str2value(perstr, &rule->rr_per, subjectnames); 1255ec125fbbSEdward Tomasz Napierala if (error != 0) 1256ec125fbbSEdward Tomasz Napierala goto out; 1257ec125fbbSEdward Tomasz Napierala } 1258ec125fbbSEdward Tomasz Napierala 1259ec125fbbSEdward Tomasz Napierala out: 1260ec125fbbSEdward Tomasz Napierala if (error == 0) 1261ec125fbbSEdward Tomasz Napierala *rulep = rule; 1262ec125fbbSEdward Tomasz Napierala else 1263ec125fbbSEdward Tomasz Napierala rctl_rule_release(rule); 1264ec125fbbSEdward Tomasz Napierala 1265ec125fbbSEdward Tomasz Napierala return (error); 1266ec125fbbSEdward Tomasz Napierala } 1267ec125fbbSEdward Tomasz Napierala 1268ec125fbbSEdward Tomasz Napierala /* 1269ec125fbbSEdward Tomasz Napierala * Link a rule with all the subjects it applies to. 1270ec125fbbSEdward Tomasz Napierala */ 1271ec125fbbSEdward Tomasz Napierala int 1272ec125fbbSEdward Tomasz Napierala rctl_rule_add(struct rctl_rule *rule) 1273ec125fbbSEdward Tomasz Napierala { 1274ec125fbbSEdward Tomasz Napierala struct proc *p; 1275ec125fbbSEdward Tomasz Napierala struct ucred *cred; 1276ec125fbbSEdward Tomasz Napierala struct uidinfo *uip; 1277ec125fbbSEdward Tomasz Napierala struct prison *pr; 1278a7ad07bfSEdward Tomasz Napierala struct prison_racct *prr; 1279ec125fbbSEdward Tomasz Napierala struct loginclass *lc; 1280ec125fbbSEdward Tomasz Napierala struct rctl_rule *rule2; 1281ec125fbbSEdward Tomasz Napierala int match; 1282ec125fbbSEdward Tomasz Napierala 12834b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 1284ec125fbbSEdward Tomasz Napierala KASSERT(rctl_rule_fully_specified(rule), ("rule not fully specified")); 1285ec125fbbSEdward Tomasz Napierala 1286ec125fbbSEdward Tomasz Napierala /* 1287ae34b6ffSEdward Tomasz Napierala * Some rules just don't make sense, like "deny" rule for an undeniable 1288ae34b6ffSEdward Tomasz Napierala * resource. The exception are the RSS and %CPU resources - they are 1289ae34b6ffSEdward Tomasz Napierala * not deniable in the racct sense, but the limit is enforced in 1290ae34b6ffSEdward Tomasz Napierala * a different way. 1291ec125fbbSEdward Tomasz Napierala */ 1292ec125fbbSEdward Tomasz Napierala if (rule->rr_action == RCTL_ACTION_DENY && 1293ae34b6ffSEdward Tomasz Napierala !RACCT_IS_DENIABLE(rule->rr_resource) && 1294ae34b6ffSEdward Tomasz Napierala rule->rr_resource != RACCT_RSS && 1295ae34b6ffSEdward Tomasz Napierala rule->rr_resource != RACCT_PCTCPU) { 1296ec125fbbSEdward Tomasz Napierala return (EOPNOTSUPP); 1297ae34b6ffSEdward Tomasz Napierala } 1298ae34b6ffSEdward Tomasz Napierala 1299ae34b6ffSEdward Tomasz Napierala if (rule->rr_action == RCTL_ACTION_THROTTLE && 1300ae34b6ffSEdward Tomasz Napierala !RACCT_IS_DECAYING(rule->rr_resource)) { 1301ae34b6ffSEdward Tomasz Napierala return (EOPNOTSUPP); 1302ae34b6ffSEdward Tomasz Napierala } 1303ae34b6ffSEdward Tomasz Napierala 1304ae34b6ffSEdward Tomasz Napierala if (rule->rr_action == RCTL_ACTION_THROTTLE && 1305ae34b6ffSEdward Tomasz Napierala rule->rr_resource == RACCT_PCTCPU) { 1306ae34b6ffSEdward Tomasz Napierala return (EOPNOTSUPP); 1307ae34b6ffSEdward Tomasz Napierala } 1308ec125fbbSEdward Tomasz Napierala 1309ec125fbbSEdward Tomasz Napierala if (rule->rr_per == RCTL_SUBJECT_TYPE_PROCESS && 1310ae34b6ffSEdward Tomasz Napierala RACCT_IS_SLOPPY(rule->rr_resource)) { 1311ec125fbbSEdward Tomasz Napierala return (EOPNOTSUPP); 1312ae34b6ffSEdward Tomasz Napierala } 1313ec125fbbSEdward Tomasz Napierala 1314ec125fbbSEdward Tomasz Napierala /* 1315ec125fbbSEdward Tomasz Napierala * Make sure there are no duplicated rules. Also, for the "deny" 1316ec125fbbSEdward Tomasz Napierala * rules, remove ones differing only by "amount". 1317ec125fbbSEdward Tomasz Napierala */ 1318ec125fbbSEdward Tomasz Napierala if (rule->rr_action == RCTL_ACTION_DENY) { 1319ec125fbbSEdward Tomasz Napierala rule2 = rctl_rule_duplicate(rule, M_WAITOK); 1320ec125fbbSEdward Tomasz Napierala rule2->rr_amount = RCTL_AMOUNT_UNDEFINED; 1321ec125fbbSEdward Tomasz Napierala rctl_rule_remove(rule2); 1322ec125fbbSEdward Tomasz Napierala rctl_rule_release(rule2); 1323ec125fbbSEdward Tomasz Napierala } else 1324ec125fbbSEdward Tomasz Napierala rctl_rule_remove(rule); 1325ec125fbbSEdward Tomasz Napierala 1326ec125fbbSEdward Tomasz Napierala switch (rule->rr_subject_type) { 1327ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_PROCESS: 1328ec125fbbSEdward Tomasz Napierala p = rule->rr_subject.rs_proc; 1329ec125fbbSEdward Tomasz Napierala KASSERT(p != NULL, ("rctl_rule_add: NULL proc")); 1330ec125fbbSEdward Tomasz Napierala 1331ec125fbbSEdward Tomasz Napierala rctl_racct_add_rule(p->p_racct, rule); 1332ec125fbbSEdward Tomasz Napierala /* 1333ec125fbbSEdward Tomasz Napierala * In case of per-process rule, we don't have anything more 1334ec125fbbSEdward Tomasz Napierala * to do. 1335ec125fbbSEdward Tomasz Napierala */ 1336ec125fbbSEdward Tomasz Napierala return (0); 1337ec125fbbSEdward Tomasz Napierala 1338ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_USER: 1339ec125fbbSEdward Tomasz Napierala uip = rule->rr_subject.rs_uip; 1340ec125fbbSEdward Tomasz Napierala KASSERT(uip != NULL, ("rctl_rule_add: NULL uip")); 1341ec125fbbSEdward Tomasz Napierala rctl_racct_add_rule(uip->ui_racct, rule); 1342ec125fbbSEdward Tomasz Napierala break; 1343ec125fbbSEdward Tomasz Napierala 1344ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_LOGINCLASS: 1345415896e3SEdward Tomasz Napierala lc = rule->rr_subject.rs_loginclass; 1346ec125fbbSEdward Tomasz Napierala KASSERT(lc != NULL, ("rctl_rule_add: NULL loginclass")); 1347ec125fbbSEdward Tomasz Napierala rctl_racct_add_rule(lc->lc_racct, rule); 1348ec125fbbSEdward Tomasz Napierala break; 1349ec125fbbSEdward Tomasz Napierala 1350ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_JAIL: 1351a7ad07bfSEdward Tomasz Napierala prr = rule->rr_subject.rs_prison_racct; 1352a7ad07bfSEdward Tomasz Napierala KASSERT(prr != NULL, ("rctl_rule_add: NULL pr")); 1353a7ad07bfSEdward Tomasz Napierala rctl_racct_add_rule(prr->prr_racct, rule); 1354ec125fbbSEdward Tomasz Napierala break; 1355ec125fbbSEdward Tomasz Napierala 1356ec125fbbSEdward Tomasz Napierala default: 1357ec125fbbSEdward Tomasz Napierala panic("rctl_rule_add: unknown subject type %d", 1358ec125fbbSEdward Tomasz Napierala rule->rr_subject_type); 1359ec125fbbSEdward Tomasz Napierala } 1360ec125fbbSEdward Tomasz Napierala 1361ec125fbbSEdward Tomasz Napierala /* 1362ec125fbbSEdward Tomasz Napierala * Now go through all the processes and add the new rule to the ones 1363ec125fbbSEdward Tomasz Napierala * it applies to. 1364ec125fbbSEdward Tomasz Napierala */ 1365ec125fbbSEdward Tomasz Napierala sx_assert(&allproc_lock, SA_LOCKED); 1366ec125fbbSEdward Tomasz Napierala FOREACH_PROC_IN_SYSTEM(p) { 1367ec125fbbSEdward Tomasz Napierala cred = p->p_ucred; 1368ec125fbbSEdward Tomasz Napierala switch (rule->rr_subject_type) { 1369ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_USER: 1370ec125fbbSEdward Tomasz Napierala if (cred->cr_uidinfo == rule->rr_subject.rs_uip || 1371ec125fbbSEdward Tomasz Napierala cred->cr_ruidinfo == rule->rr_subject.rs_uip) 1372ec125fbbSEdward Tomasz Napierala break; 1373ec125fbbSEdward Tomasz Napierala continue; 1374ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_LOGINCLASS: 1375415896e3SEdward Tomasz Napierala if (cred->cr_loginclass == rule->rr_subject.rs_loginclass) 1376ec125fbbSEdward Tomasz Napierala break; 1377ec125fbbSEdward Tomasz Napierala continue; 1378ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_JAIL: 1379ec125fbbSEdward Tomasz Napierala match = 0; 1380ec125fbbSEdward Tomasz Napierala for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) { 1381a7ad07bfSEdward Tomasz Napierala if (pr->pr_prison_racct == rule->rr_subject.rs_prison_racct) { 1382ec125fbbSEdward Tomasz Napierala match = 1; 1383ec125fbbSEdward Tomasz Napierala break; 1384ec125fbbSEdward Tomasz Napierala } 1385ec125fbbSEdward Tomasz Napierala } 1386ec125fbbSEdward Tomasz Napierala if (match) 1387ec125fbbSEdward Tomasz Napierala break; 1388ec125fbbSEdward Tomasz Napierala continue; 1389ec125fbbSEdward Tomasz Napierala default: 1390ec125fbbSEdward Tomasz Napierala panic("rctl_rule_add: unknown subject type %d", 1391ec125fbbSEdward Tomasz Napierala rule->rr_subject_type); 1392ec125fbbSEdward Tomasz Napierala } 1393ec125fbbSEdward Tomasz Napierala 1394ec125fbbSEdward Tomasz Napierala rctl_racct_add_rule(p->p_racct, rule); 1395ec125fbbSEdward Tomasz Napierala } 1396ec125fbbSEdward Tomasz Napierala 1397ec125fbbSEdward Tomasz Napierala return (0); 1398ec125fbbSEdward Tomasz Napierala } 1399ec125fbbSEdward Tomasz Napierala 1400ec125fbbSEdward Tomasz Napierala static void 140115db3c07SEdward Tomasz Napierala rctl_rule_pre_callback(void) 140215db3c07SEdward Tomasz Napierala { 140315db3c07SEdward Tomasz Napierala 1404bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 140515db3c07SEdward Tomasz Napierala } 140615db3c07SEdward Tomasz Napierala 140715db3c07SEdward Tomasz Napierala static void 140815db3c07SEdward Tomasz Napierala rctl_rule_post_callback(void) 140915db3c07SEdward Tomasz Napierala { 141015db3c07SEdward Tomasz Napierala 1411bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 141215db3c07SEdward Tomasz Napierala } 141315db3c07SEdward Tomasz Napierala 141415db3c07SEdward Tomasz Napierala static void 1415ec125fbbSEdward Tomasz Napierala rctl_rule_remove_callback(struct racct *racct, void *arg2, void *arg3) 1416ec125fbbSEdward Tomasz Napierala { 1417ec125fbbSEdward Tomasz Napierala struct rctl_rule *filter = (struct rctl_rule *)arg2; 1418ec125fbbSEdward Tomasz Napierala int found = 0; 1419ec125fbbSEdward Tomasz Napierala 14204b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 1421bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 14224b5c9cf6SEdward Tomasz Napierala 1423ec125fbbSEdward Tomasz Napierala found += rctl_racct_remove_rules(racct, filter); 1424ec125fbbSEdward Tomasz Napierala 1425ec125fbbSEdward Tomasz Napierala *((int *)arg3) += found; 1426ec125fbbSEdward Tomasz Napierala } 1427ec125fbbSEdward Tomasz Napierala 1428ec125fbbSEdward Tomasz Napierala /* 1429ec125fbbSEdward Tomasz Napierala * Remove all rules that match the filter. 1430ec125fbbSEdward Tomasz Napierala */ 1431ec125fbbSEdward Tomasz Napierala int 1432ec125fbbSEdward Tomasz Napierala rctl_rule_remove(struct rctl_rule *filter) 1433ec125fbbSEdward Tomasz Napierala { 1434ec125fbbSEdward Tomasz Napierala struct proc *p; 1435c1a43e73SEdward Tomasz Napierala int found = 0; 1436ec125fbbSEdward Tomasz Napierala 14374b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 14384b5c9cf6SEdward Tomasz Napierala 1439ec125fbbSEdward Tomasz Napierala if (filter->rr_subject_type == RCTL_SUBJECT_TYPE_PROCESS && 1440ec125fbbSEdward Tomasz Napierala filter->rr_subject.rs_proc != NULL) { 1441ec125fbbSEdward Tomasz Napierala p = filter->rr_subject.rs_proc; 1442bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 1443ec125fbbSEdward Tomasz Napierala found = rctl_racct_remove_rules(p->p_racct, filter); 1444bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 1445ec125fbbSEdward Tomasz Napierala if (found) 1446ec125fbbSEdward Tomasz Napierala return (0); 1447ec125fbbSEdward Tomasz Napierala return (ESRCH); 1448ec125fbbSEdward Tomasz Napierala } 1449ec125fbbSEdward Tomasz Napierala 145015db3c07SEdward Tomasz Napierala loginclass_racct_foreach(rctl_rule_remove_callback, 145115db3c07SEdward Tomasz Napierala rctl_rule_pre_callback, rctl_rule_post_callback, 145215db3c07SEdward Tomasz Napierala filter, (void *)&found); 145315db3c07SEdward Tomasz Napierala ui_racct_foreach(rctl_rule_remove_callback, 145415db3c07SEdward Tomasz Napierala rctl_rule_pre_callback, rctl_rule_post_callback, 145515db3c07SEdward Tomasz Napierala filter, (void *)&found); 145615db3c07SEdward Tomasz Napierala prison_racct_foreach(rctl_rule_remove_callback, 145715db3c07SEdward Tomasz Napierala rctl_rule_pre_callback, rctl_rule_post_callback, 145815db3c07SEdward Tomasz Napierala filter, (void *)&found); 1459ec125fbbSEdward Tomasz Napierala 1460ec125fbbSEdward Tomasz Napierala sx_assert(&allproc_lock, SA_LOCKED); 1461bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 1462ec125fbbSEdward Tomasz Napierala FOREACH_PROC_IN_SYSTEM(p) { 1463ec125fbbSEdward Tomasz Napierala found += rctl_racct_remove_rules(p->p_racct, filter); 1464ec125fbbSEdward Tomasz Napierala } 1465bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 1466ec125fbbSEdward Tomasz Napierala 1467ec125fbbSEdward Tomasz Napierala if (found) 1468ec125fbbSEdward Tomasz Napierala return (0); 1469ec125fbbSEdward Tomasz Napierala return (ESRCH); 1470ec125fbbSEdward Tomasz Napierala } 1471ec125fbbSEdward Tomasz Napierala 1472ec125fbbSEdward Tomasz Napierala /* 1473ec125fbbSEdward Tomasz Napierala * Appends a rule to the sbuf. 1474ec125fbbSEdward Tomasz Napierala */ 1475ec125fbbSEdward Tomasz Napierala static void 1476ec125fbbSEdward Tomasz Napierala rctl_rule_to_sbuf(struct sbuf *sb, const struct rctl_rule *rule) 1477ec125fbbSEdward Tomasz Napierala { 1478ec125fbbSEdward Tomasz Napierala int64_t amount; 1479ec125fbbSEdward Tomasz Napierala 14804b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 14814b5c9cf6SEdward Tomasz Napierala 1482ec125fbbSEdward Tomasz Napierala sbuf_printf(sb, "%s:", rctl_subject_type_name(rule->rr_subject_type)); 1483ec125fbbSEdward Tomasz Napierala 1484ec125fbbSEdward Tomasz Napierala switch (rule->rr_subject_type) { 1485ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_PROCESS: 1486ec125fbbSEdward Tomasz Napierala if (rule->rr_subject.rs_proc == NULL) 14870a713948SAlexander Motin sbuf_putc(sb, ':'); 1488ec125fbbSEdward Tomasz Napierala else 1489ec125fbbSEdward Tomasz Napierala sbuf_printf(sb, "%d:", 1490ec125fbbSEdward Tomasz Napierala rule->rr_subject.rs_proc->p_pid); 1491ec125fbbSEdward Tomasz Napierala break; 1492ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_USER: 1493ec125fbbSEdward Tomasz Napierala if (rule->rr_subject.rs_uip == NULL) 14940a713948SAlexander Motin sbuf_putc(sb, ':'); 1495ec125fbbSEdward Tomasz Napierala else 1496ec125fbbSEdward Tomasz Napierala sbuf_printf(sb, "%d:", 1497ec125fbbSEdward Tomasz Napierala rule->rr_subject.rs_uip->ui_uid); 1498ec125fbbSEdward Tomasz Napierala break; 1499ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_LOGINCLASS: 1500415896e3SEdward Tomasz Napierala if (rule->rr_subject.rs_loginclass == NULL) 15010a713948SAlexander Motin sbuf_putc(sb, ':'); 1502ec125fbbSEdward Tomasz Napierala else 1503ec125fbbSEdward Tomasz Napierala sbuf_printf(sb, "%s:", 1504415896e3SEdward Tomasz Napierala rule->rr_subject.rs_loginclass->lc_name); 1505ec125fbbSEdward Tomasz Napierala break; 1506ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_JAIL: 1507a7ad07bfSEdward Tomasz Napierala if (rule->rr_subject.rs_prison_racct == NULL) 15080a713948SAlexander Motin sbuf_putc(sb, ':'); 1509ec125fbbSEdward Tomasz Napierala else 1510ec125fbbSEdward Tomasz Napierala sbuf_printf(sb, "%s:", 1511a7ad07bfSEdward Tomasz Napierala rule->rr_subject.rs_prison_racct->prr_name); 1512ec125fbbSEdward Tomasz Napierala break; 1513ec125fbbSEdward Tomasz Napierala default: 1514ec125fbbSEdward Tomasz Napierala panic("rctl_rule_to_sbuf: unknown subject type %d", 1515ec125fbbSEdward Tomasz Napierala rule->rr_subject_type); 1516ec125fbbSEdward Tomasz Napierala } 1517ec125fbbSEdward Tomasz Napierala 1518ec125fbbSEdward Tomasz Napierala amount = rule->rr_amount; 1519ec125fbbSEdward Tomasz Napierala if (amount != RCTL_AMOUNT_UNDEFINED && 152085a2f1b4SEdward Tomasz Napierala RACCT_IS_IN_MILLIONS(rule->rr_resource)) 152185a2f1b4SEdward Tomasz Napierala amount /= 1000000; 1522ec125fbbSEdward Tomasz Napierala 1523ec125fbbSEdward Tomasz Napierala sbuf_printf(sb, "%s:%s=%jd", 1524ec125fbbSEdward Tomasz Napierala rctl_resource_name(rule->rr_resource), 1525ec125fbbSEdward Tomasz Napierala rctl_action_name(rule->rr_action), 1526ec125fbbSEdward Tomasz Napierala amount); 1527ec125fbbSEdward Tomasz Napierala 1528ec125fbbSEdward Tomasz Napierala if (rule->rr_per != rule->rr_subject_type) 1529ec125fbbSEdward Tomasz Napierala sbuf_printf(sb, "/%s", rctl_subject_type_name(rule->rr_per)); 1530ec125fbbSEdward Tomasz Napierala } 1531ec125fbbSEdward Tomasz Napierala 1532ec125fbbSEdward Tomasz Napierala /* 1533ec125fbbSEdward Tomasz Napierala * Routine used by RCTL syscalls to read in input string. 1534ec125fbbSEdward Tomasz Napierala */ 1535ec125fbbSEdward Tomasz Napierala static int 1536ec125fbbSEdward Tomasz Napierala rctl_read_inbuf(char **inputstr, const char *inbufp, size_t inbuflen) 1537ec125fbbSEdward Tomasz Napierala { 1538ec125fbbSEdward Tomasz Napierala char *str; 1539c1a43e73SEdward Tomasz Napierala int error; 1540ec125fbbSEdward Tomasz Napierala 15414b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 15424b5c9cf6SEdward Tomasz Napierala 1543ec125fbbSEdward Tomasz Napierala if (inbuflen <= 0) 1544ec125fbbSEdward Tomasz Napierala return (EINVAL); 1545ea228b48SEdward Tomasz Napierala if (inbuflen > RCTL_MAX_INBUFSIZE) 1546786813aaSEdward Tomasz Napierala return (E2BIG); 1547ec125fbbSEdward Tomasz Napierala 1548ec125fbbSEdward Tomasz Napierala str = malloc(inbuflen + 1, M_RCTL, M_WAITOK); 1549ec125fbbSEdward Tomasz Napierala error = copyinstr(inbufp, str, inbuflen, NULL); 1550ec125fbbSEdward Tomasz Napierala if (error != 0) { 1551ec125fbbSEdward Tomasz Napierala free(str, M_RCTL); 1552ec125fbbSEdward Tomasz Napierala return (error); 1553ec125fbbSEdward Tomasz Napierala } 1554ec125fbbSEdward Tomasz Napierala 1555ec125fbbSEdward Tomasz Napierala *inputstr = str; 1556ec125fbbSEdward Tomasz Napierala 1557ec125fbbSEdward Tomasz Napierala return (0); 1558ec125fbbSEdward Tomasz Napierala } 1559ec125fbbSEdward Tomasz Napierala 1560ec125fbbSEdward Tomasz Napierala /* 1561ec125fbbSEdward Tomasz Napierala * Routine used by RCTL syscalls to write out output string. 1562ec125fbbSEdward Tomasz Napierala */ 1563ec125fbbSEdward Tomasz Napierala static int 1564ec125fbbSEdward Tomasz Napierala rctl_write_outbuf(struct sbuf *outputsbuf, char *outbufp, size_t outbuflen) 1565ec125fbbSEdward Tomasz Napierala { 1566ec125fbbSEdward Tomasz Napierala int error; 1567ec125fbbSEdward Tomasz Napierala 15684b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 15694b5c9cf6SEdward Tomasz Napierala 1570ec125fbbSEdward Tomasz Napierala if (outputsbuf == NULL) 1571ec125fbbSEdward Tomasz Napierala return (0); 1572ec125fbbSEdward Tomasz Napierala 1573ec125fbbSEdward Tomasz Napierala sbuf_finish(outputsbuf); 1574ec125fbbSEdward Tomasz Napierala if (outbuflen < sbuf_len(outputsbuf) + 1) { 1575ec125fbbSEdward Tomasz Napierala sbuf_delete(outputsbuf); 1576ec125fbbSEdward Tomasz Napierala return (ERANGE); 1577ec125fbbSEdward Tomasz Napierala } 1578ec125fbbSEdward Tomasz Napierala error = copyout(sbuf_data(outputsbuf), outbufp, 1579ec125fbbSEdward Tomasz Napierala sbuf_len(outputsbuf) + 1); 1580ec125fbbSEdward Tomasz Napierala sbuf_delete(outputsbuf); 1581ec125fbbSEdward Tomasz Napierala return (error); 1582ec125fbbSEdward Tomasz Napierala } 1583ec125fbbSEdward Tomasz Napierala 1584ec125fbbSEdward Tomasz Napierala static struct sbuf * 1585ec125fbbSEdward Tomasz Napierala rctl_racct_to_sbuf(struct racct *racct, int sloppy) 1586ec125fbbSEdward Tomasz Napierala { 1587ec125fbbSEdward Tomasz Napierala struct sbuf *sb; 1588c1a43e73SEdward Tomasz Napierala int64_t amount; 1589c1a43e73SEdward Tomasz Napierala int i; 1590ec125fbbSEdward Tomasz Napierala 15914b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 15924b5c9cf6SEdward Tomasz Napierala 1593ec125fbbSEdward Tomasz Napierala sb = sbuf_new_auto(); 1594ec125fbbSEdward Tomasz Napierala for (i = 0; i <= RACCT_MAX; i++) { 15954fe84775SEdward Tomasz Napierala if (sloppy == 0 && RACCT_IS_SLOPPY(i)) 1596ec125fbbSEdward Tomasz Napierala continue; 1597bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 1598ec125fbbSEdward Tomasz Napierala amount = racct->r_resources[i]; 1599bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 160085a2f1b4SEdward Tomasz Napierala if (RACCT_IS_IN_MILLIONS(i)) 1601cff08ec0SEdward Tomasz Napierala amount /= 1000000; 1602ec125fbbSEdward Tomasz Napierala sbuf_printf(sb, "%s=%jd,", rctl_resource_name(i), amount); 1603ec125fbbSEdward Tomasz Napierala } 1604ec125fbbSEdward Tomasz Napierala sbuf_setpos(sb, sbuf_len(sb) - 1); 1605ec125fbbSEdward Tomasz Napierala return (sb); 1606ec125fbbSEdward Tomasz Napierala } 1607ec125fbbSEdward Tomasz Napierala 1608ec125fbbSEdward Tomasz Napierala int 16098451d0ddSKip Macy sys_rctl_get_racct(struct thread *td, struct rctl_get_racct_args *uap) 1610ec125fbbSEdward Tomasz Napierala { 1611ec125fbbSEdward Tomasz Napierala struct rctl_rule *filter; 1612ec125fbbSEdward Tomasz Napierala struct sbuf *outputsbuf = NULL; 1613ec125fbbSEdward Tomasz Napierala struct proc *p; 1614ec125fbbSEdward Tomasz Napierala struct uidinfo *uip; 1615ec125fbbSEdward Tomasz Napierala struct loginclass *lc; 1616a7ad07bfSEdward Tomasz Napierala struct prison_racct *prr; 1617c1a43e73SEdward Tomasz Napierala char *inputstr; 1618c1a43e73SEdward Tomasz Napierala int error; 1619ec125fbbSEdward Tomasz Napierala 16204b5c9cf6SEdward Tomasz Napierala if (!racct_enable) 16214b5c9cf6SEdward Tomasz Napierala return (ENOSYS); 16224b5c9cf6SEdward Tomasz Napierala 1623415896e3SEdward Tomasz Napierala error = priv_check(td, PRIV_RCTL_GET_RACCT); 1624ec125fbbSEdward Tomasz Napierala if (error != 0) 1625ec125fbbSEdward Tomasz Napierala return (error); 1626ec125fbbSEdward Tomasz Napierala 1627ec125fbbSEdward Tomasz Napierala error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen); 1628ec125fbbSEdward Tomasz Napierala if (error != 0) 1629ec125fbbSEdward Tomasz Napierala return (error); 1630ec125fbbSEdward Tomasz Napierala 1631ec125fbbSEdward Tomasz Napierala sx_slock(&allproc_lock); 1632ec125fbbSEdward Tomasz Napierala error = rctl_string_to_rule(inputstr, &filter); 1633ec125fbbSEdward Tomasz Napierala free(inputstr, M_RCTL); 1634ec125fbbSEdward Tomasz Napierala if (error != 0) { 1635ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1636ec125fbbSEdward Tomasz Napierala return (error); 1637ec125fbbSEdward Tomasz Napierala } 1638ec125fbbSEdward Tomasz Napierala 1639ec125fbbSEdward Tomasz Napierala switch (filter->rr_subject_type) { 1640ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_PROCESS: 1641ec125fbbSEdward Tomasz Napierala p = filter->rr_subject.rs_proc; 1642ec125fbbSEdward Tomasz Napierala if (p == NULL) { 1643ec125fbbSEdward Tomasz Napierala error = EINVAL; 1644ec125fbbSEdward Tomasz Napierala goto out; 1645ec125fbbSEdward Tomasz Napierala } 1646ec125fbbSEdward Tomasz Napierala outputsbuf = rctl_racct_to_sbuf(p->p_racct, 0); 1647ec125fbbSEdward Tomasz Napierala break; 1648ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_USER: 1649ec125fbbSEdward Tomasz Napierala uip = filter->rr_subject.rs_uip; 1650ec125fbbSEdward Tomasz Napierala if (uip == NULL) { 1651ec125fbbSEdward Tomasz Napierala error = EINVAL; 1652ec125fbbSEdward Tomasz Napierala goto out; 1653ec125fbbSEdward Tomasz Napierala } 1654ec125fbbSEdward Tomasz Napierala outputsbuf = rctl_racct_to_sbuf(uip->ui_racct, 1); 1655ec125fbbSEdward Tomasz Napierala break; 1656ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_LOGINCLASS: 1657415896e3SEdward Tomasz Napierala lc = filter->rr_subject.rs_loginclass; 1658ec125fbbSEdward Tomasz Napierala if (lc == NULL) { 1659ec125fbbSEdward Tomasz Napierala error = EINVAL; 1660ec125fbbSEdward Tomasz Napierala goto out; 1661ec125fbbSEdward Tomasz Napierala } 1662ec125fbbSEdward Tomasz Napierala outputsbuf = rctl_racct_to_sbuf(lc->lc_racct, 1); 1663ec125fbbSEdward Tomasz Napierala break; 1664ec125fbbSEdward Tomasz Napierala case RCTL_SUBJECT_TYPE_JAIL: 1665a7ad07bfSEdward Tomasz Napierala prr = filter->rr_subject.rs_prison_racct; 1666a7ad07bfSEdward Tomasz Napierala if (prr == NULL) { 1667ec125fbbSEdward Tomasz Napierala error = EINVAL; 1668ec125fbbSEdward Tomasz Napierala goto out; 1669ec125fbbSEdward Tomasz Napierala } 1670a7ad07bfSEdward Tomasz Napierala outputsbuf = rctl_racct_to_sbuf(prr->prr_racct, 1); 1671ec125fbbSEdward Tomasz Napierala break; 1672ec125fbbSEdward Tomasz Napierala default: 1673ec125fbbSEdward Tomasz Napierala error = EINVAL; 1674ec125fbbSEdward Tomasz Napierala } 1675ec125fbbSEdward Tomasz Napierala out: 1676ec125fbbSEdward Tomasz Napierala rctl_rule_release(filter); 1677ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1678ec125fbbSEdward Tomasz Napierala if (error != 0) 1679ec125fbbSEdward Tomasz Napierala return (error); 1680ec125fbbSEdward Tomasz Napierala 1681ec125fbbSEdward Tomasz Napierala error = rctl_write_outbuf(outputsbuf, uap->outbufp, uap->outbuflen); 1682ec125fbbSEdward Tomasz Napierala 1683ec125fbbSEdward Tomasz Napierala return (error); 1684ec125fbbSEdward Tomasz Napierala } 1685ec125fbbSEdward Tomasz Napierala 1686ec125fbbSEdward Tomasz Napierala static void 1687ec125fbbSEdward Tomasz Napierala rctl_get_rules_callback(struct racct *racct, void *arg2, void *arg3) 1688ec125fbbSEdward Tomasz Napierala { 1689ec125fbbSEdward Tomasz Napierala struct rctl_rule *filter = (struct rctl_rule *)arg2; 1690ec125fbbSEdward Tomasz Napierala struct rctl_rule_link *link; 1691ec125fbbSEdward Tomasz Napierala struct sbuf *sb = (struct sbuf *)arg3; 1692ec125fbbSEdward Tomasz Napierala 16934b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 1694bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 16954b5c9cf6SEdward Tomasz Napierala 1696ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &racct->r_rule_links, rrl_next) { 1697ec125fbbSEdward Tomasz Napierala if (!rctl_rule_matches(link->rrl_rule, filter)) 1698ec125fbbSEdward Tomasz Napierala continue; 1699ec125fbbSEdward Tomasz Napierala rctl_rule_to_sbuf(sb, link->rrl_rule); 17000a713948SAlexander Motin sbuf_putc(sb, ','); 1701ec125fbbSEdward Tomasz Napierala } 1702ec125fbbSEdward Tomasz Napierala } 1703ec125fbbSEdward Tomasz Napierala 1704ec125fbbSEdward Tomasz Napierala int 17058451d0ddSKip Macy sys_rctl_get_rules(struct thread *td, struct rctl_get_rules_args *uap) 1706ec125fbbSEdward Tomasz Napierala { 1707ec125fbbSEdward Tomasz Napierala struct sbuf *sb; 1708ec125fbbSEdward Tomasz Napierala struct rctl_rule *filter; 1709ec125fbbSEdward Tomasz Napierala struct rctl_rule_link *link; 1710ec125fbbSEdward Tomasz Napierala struct proc *p; 1711c1a43e73SEdward Tomasz Napierala char *inputstr, *buf; 1712c1a43e73SEdward Tomasz Napierala size_t bufsize; 1713c1a43e73SEdward Tomasz Napierala int error; 1714ec125fbbSEdward Tomasz Napierala 17154b5c9cf6SEdward Tomasz Napierala if (!racct_enable) 17164b5c9cf6SEdward Tomasz Napierala return (ENOSYS); 17174b5c9cf6SEdward Tomasz Napierala 1718ec125fbbSEdward Tomasz Napierala error = priv_check(td, PRIV_RCTL_GET_RULES); 1719ec125fbbSEdward Tomasz Napierala if (error != 0) 1720ec125fbbSEdward Tomasz Napierala return (error); 1721ec125fbbSEdward Tomasz Napierala 1722ec125fbbSEdward Tomasz Napierala error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen); 1723ec125fbbSEdward Tomasz Napierala if (error != 0) 1724ec125fbbSEdward Tomasz Napierala return (error); 1725ec125fbbSEdward Tomasz Napierala 1726ec125fbbSEdward Tomasz Napierala sx_slock(&allproc_lock); 1727ec125fbbSEdward Tomasz Napierala error = rctl_string_to_rule(inputstr, &filter); 1728ec125fbbSEdward Tomasz Napierala free(inputstr, M_RCTL); 1729ec125fbbSEdward Tomasz Napierala if (error != 0) { 1730ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1731ec125fbbSEdward Tomasz Napierala return (error); 1732ec125fbbSEdward Tomasz Napierala } 1733ec125fbbSEdward Tomasz Napierala 17342b4035eeSEdward Tomasz Napierala bufsize = uap->outbuflen; 17352b4035eeSEdward Tomasz Napierala if (bufsize > rctl_maxbufsize) { 17362b4035eeSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 17372b4035eeSEdward Tomasz Napierala return (E2BIG); 17382b4035eeSEdward Tomasz Napierala } 17392b4035eeSEdward Tomasz Napierala 1740ec125fbbSEdward Tomasz Napierala buf = malloc(bufsize, M_RCTL, M_WAITOK); 1741ec125fbbSEdward Tomasz Napierala sb = sbuf_new(NULL, buf, bufsize, SBUF_FIXEDLEN); 1742ec125fbbSEdward Tomasz Napierala KASSERT(sb != NULL, ("sbuf_new failed")); 1743ec125fbbSEdward Tomasz Napierala 1744ec125fbbSEdward Tomasz Napierala FOREACH_PROC_IN_SYSTEM(p) { 1745bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 1746ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) { 1747ec125fbbSEdward Tomasz Napierala /* 1748ec125fbbSEdward Tomasz Napierala * Non-process rules will be added to the buffer later. 1749ec125fbbSEdward Tomasz Napierala * Adding them here would result in duplicated output. 1750ec125fbbSEdward Tomasz Napierala */ 1751ec125fbbSEdward Tomasz Napierala if (link->rrl_rule->rr_subject_type != 1752ec125fbbSEdward Tomasz Napierala RCTL_SUBJECT_TYPE_PROCESS) 1753ec125fbbSEdward Tomasz Napierala continue; 1754ec125fbbSEdward Tomasz Napierala if (!rctl_rule_matches(link->rrl_rule, filter)) 1755ec125fbbSEdward Tomasz Napierala continue; 1756ec125fbbSEdward Tomasz Napierala rctl_rule_to_sbuf(sb, link->rrl_rule); 17570a713948SAlexander Motin sbuf_putc(sb, ','); 1758ec125fbbSEdward Tomasz Napierala } 1759bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 1760ec125fbbSEdward Tomasz Napierala } 1761ec125fbbSEdward Tomasz Napierala 176215db3c07SEdward Tomasz Napierala loginclass_racct_foreach(rctl_get_rules_callback, 176315db3c07SEdward Tomasz Napierala rctl_rule_pre_callback, rctl_rule_post_callback, 176415db3c07SEdward Tomasz Napierala filter, sb); 176515db3c07SEdward Tomasz Napierala ui_racct_foreach(rctl_get_rules_callback, 176615db3c07SEdward Tomasz Napierala rctl_rule_pre_callback, rctl_rule_post_callback, 176715db3c07SEdward Tomasz Napierala filter, sb); 176815db3c07SEdward Tomasz Napierala prison_racct_foreach(rctl_get_rules_callback, 176915db3c07SEdward Tomasz Napierala rctl_rule_pre_callback, rctl_rule_post_callback, 177015db3c07SEdward Tomasz Napierala filter, sb); 1771ec125fbbSEdward Tomasz Napierala if (sbuf_error(sb) == ENOMEM) { 17722b4035eeSEdward Tomasz Napierala error = ERANGE; 17732b4035eeSEdward Tomasz Napierala goto out; 1774ec125fbbSEdward Tomasz Napierala } 1775ec125fbbSEdward Tomasz Napierala 1776ec125fbbSEdward Tomasz Napierala /* 1777ec125fbbSEdward Tomasz Napierala * Remove trailing ",". 1778ec125fbbSEdward Tomasz Napierala */ 1779ec125fbbSEdward Tomasz Napierala if (sbuf_len(sb) > 0) 1780ec125fbbSEdward Tomasz Napierala sbuf_setpos(sb, sbuf_len(sb) - 1); 1781ec125fbbSEdward Tomasz Napierala 1782ec125fbbSEdward Tomasz Napierala error = rctl_write_outbuf(sb, uap->outbufp, uap->outbuflen); 17832b4035eeSEdward Tomasz Napierala out: 1784ec125fbbSEdward Tomasz Napierala rctl_rule_release(filter); 1785ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1786ec125fbbSEdward Tomasz Napierala free(buf, M_RCTL); 1787ec125fbbSEdward Tomasz Napierala return (error); 1788ec125fbbSEdward Tomasz Napierala } 1789ec125fbbSEdward Tomasz Napierala 1790ec125fbbSEdward Tomasz Napierala int 17918451d0ddSKip Macy sys_rctl_get_limits(struct thread *td, struct rctl_get_limits_args *uap) 1792ec125fbbSEdward Tomasz Napierala { 1793ec125fbbSEdward Tomasz Napierala struct sbuf *sb; 1794ec125fbbSEdward Tomasz Napierala struct rctl_rule *filter; 1795ec125fbbSEdward Tomasz Napierala struct rctl_rule_link *link; 1796c1a43e73SEdward Tomasz Napierala char *inputstr, *buf; 1797c1a43e73SEdward Tomasz Napierala size_t bufsize; 1798c1a43e73SEdward Tomasz Napierala int error; 1799ec125fbbSEdward Tomasz Napierala 18004b5c9cf6SEdward Tomasz Napierala if (!racct_enable) 18014b5c9cf6SEdward Tomasz Napierala return (ENOSYS); 18024b5c9cf6SEdward Tomasz Napierala 1803ec125fbbSEdward Tomasz Napierala error = priv_check(td, PRIV_RCTL_GET_LIMITS); 1804ec125fbbSEdward Tomasz Napierala if (error != 0) 1805ec125fbbSEdward Tomasz Napierala return (error); 1806ec125fbbSEdward Tomasz Napierala 1807ec125fbbSEdward Tomasz Napierala error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen); 1808ec125fbbSEdward Tomasz Napierala if (error != 0) 1809ec125fbbSEdward Tomasz Napierala return (error); 1810ec125fbbSEdward Tomasz Napierala 1811ec125fbbSEdward Tomasz Napierala sx_slock(&allproc_lock); 1812ec125fbbSEdward Tomasz Napierala error = rctl_string_to_rule(inputstr, &filter); 1813ec125fbbSEdward Tomasz Napierala free(inputstr, M_RCTL); 1814ec125fbbSEdward Tomasz Napierala if (error != 0) { 1815ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1816ec125fbbSEdward Tomasz Napierala return (error); 1817ec125fbbSEdward Tomasz Napierala } 1818ec125fbbSEdward Tomasz Napierala 1819ec125fbbSEdward Tomasz Napierala if (filter->rr_subject_type == RCTL_SUBJECT_TYPE_UNDEFINED) { 1820ec125fbbSEdward Tomasz Napierala rctl_rule_release(filter); 1821ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1822ec125fbbSEdward Tomasz Napierala return (EINVAL); 1823ec125fbbSEdward Tomasz Napierala } 1824ec125fbbSEdward Tomasz Napierala if (filter->rr_subject_type != RCTL_SUBJECT_TYPE_PROCESS) { 1825ec125fbbSEdward Tomasz Napierala rctl_rule_release(filter); 1826ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1827ec125fbbSEdward Tomasz Napierala return (EOPNOTSUPP); 1828ec125fbbSEdward Tomasz Napierala } 1829ec125fbbSEdward Tomasz Napierala if (filter->rr_subject.rs_proc == NULL) { 1830ec125fbbSEdward Tomasz Napierala rctl_rule_release(filter); 1831ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1832ec125fbbSEdward Tomasz Napierala return (EINVAL); 1833ec125fbbSEdward Tomasz Napierala } 1834ec125fbbSEdward Tomasz Napierala 18352b4035eeSEdward Tomasz Napierala bufsize = uap->outbuflen; 18362b4035eeSEdward Tomasz Napierala if (bufsize > rctl_maxbufsize) { 18372b4035eeSEdward Tomasz Napierala rctl_rule_release(filter); 18382b4035eeSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 18392b4035eeSEdward Tomasz Napierala return (E2BIG); 18402b4035eeSEdward Tomasz Napierala } 18412b4035eeSEdward Tomasz Napierala 1842ec125fbbSEdward Tomasz Napierala buf = malloc(bufsize, M_RCTL, M_WAITOK); 1843ec125fbbSEdward Tomasz Napierala sb = sbuf_new(NULL, buf, bufsize, SBUF_FIXEDLEN); 1844ec125fbbSEdward Tomasz Napierala KASSERT(sb != NULL, ("sbuf_new failed")); 1845ec125fbbSEdward Tomasz Napierala 1846bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 1847ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &filter->rr_subject.rs_proc->p_racct->r_rule_links, 1848ec125fbbSEdward Tomasz Napierala rrl_next) { 1849ec125fbbSEdward Tomasz Napierala rctl_rule_to_sbuf(sb, link->rrl_rule); 18500a713948SAlexander Motin sbuf_putc(sb, ','); 1851ec125fbbSEdward Tomasz Napierala } 1852bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 1853ec125fbbSEdward Tomasz Napierala if (sbuf_error(sb) == ENOMEM) { 18542b4035eeSEdward Tomasz Napierala error = ERANGE; 1855b483e111SConrad Meyer sbuf_delete(sb); 18562b4035eeSEdward Tomasz Napierala goto out; 1857ec125fbbSEdward Tomasz Napierala } 1858ec125fbbSEdward Tomasz Napierala 1859ec125fbbSEdward Tomasz Napierala /* 1860ec125fbbSEdward Tomasz Napierala * Remove trailing ",". 1861ec125fbbSEdward Tomasz Napierala */ 1862ec125fbbSEdward Tomasz Napierala if (sbuf_len(sb) > 0) 1863ec125fbbSEdward Tomasz Napierala sbuf_setpos(sb, sbuf_len(sb) - 1); 1864ec125fbbSEdward Tomasz Napierala 1865ec125fbbSEdward Tomasz Napierala error = rctl_write_outbuf(sb, uap->outbufp, uap->outbuflen); 18662b4035eeSEdward Tomasz Napierala out: 1867ec125fbbSEdward Tomasz Napierala rctl_rule_release(filter); 1868ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1869ec125fbbSEdward Tomasz Napierala free(buf, M_RCTL); 1870ec125fbbSEdward Tomasz Napierala return (error); 1871ec125fbbSEdward Tomasz Napierala } 1872ec125fbbSEdward Tomasz Napierala 1873ec125fbbSEdward Tomasz Napierala int 18748451d0ddSKip Macy sys_rctl_add_rule(struct thread *td, struct rctl_add_rule_args *uap) 1875ec125fbbSEdward Tomasz Napierala { 1876ec125fbbSEdward Tomasz Napierala struct rctl_rule *rule; 1877ec125fbbSEdward Tomasz Napierala char *inputstr; 1878c1a43e73SEdward Tomasz Napierala int error; 1879ec125fbbSEdward Tomasz Napierala 18804b5c9cf6SEdward Tomasz Napierala if (!racct_enable) 18814b5c9cf6SEdward Tomasz Napierala return (ENOSYS); 18824b5c9cf6SEdward Tomasz Napierala 1883ec125fbbSEdward Tomasz Napierala error = priv_check(td, PRIV_RCTL_ADD_RULE); 1884ec125fbbSEdward Tomasz Napierala if (error != 0) 1885ec125fbbSEdward Tomasz Napierala return (error); 1886ec125fbbSEdward Tomasz Napierala 1887ec125fbbSEdward Tomasz Napierala error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen); 1888ec125fbbSEdward Tomasz Napierala if (error != 0) 1889ec125fbbSEdward Tomasz Napierala return (error); 1890ec125fbbSEdward Tomasz Napierala 1891ec125fbbSEdward Tomasz Napierala sx_slock(&allproc_lock); 1892ec125fbbSEdward Tomasz Napierala error = rctl_string_to_rule(inputstr, &rule); 1893ec125fbbSEdward Tomasz Napierala free(inputstr, M_RCTL); 1894ec125fbbSEdward Tomasz Napierala if (error != 0) { 1895ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1896ec125fbbSEdward Tomasz Napierala return (error); 1897ec125fbbSEdward Tomasz Napierala } 1898ec125fbbSEdward Tomasz Napierala /* 1899ec125fbbSEdward Tomasz Napierala * The 'per' part of a rule is optional. 1900ec125fbbSEdward Tomasz Napierala */ 1901ec125fbbSEdward Tomasz Napierala if (rule->rr_per == RCTL_SUBJECT_TYPE_UNDEFINED && 1902ec125fbbSEdward Tomasz Napierala rule->rr_subject_type != RCTL_SUBJECT_TYPE_UNDEFINED) 1903ec125fbbSEdward Tomasz Napierala rule->rr_per = rule->rr_subject_type; 1904ec125fbbSEdward Tomasz Napierala 1905ec125fbbSEdward Tomasz Napierala if (!rctl_rule_fully_specified(rule)) { 1906ec125fbbSEdward Tomasz Napierala error = EINVAL; 1907ec125fbbSEdward Tomasz Napierala goto out; 1908ec125fbbSEdward Tomasz Napierala } 1909ec125fbbSEdward Tomasz Napierala 1910ec125fbbSEdward Tomasz Napierala error = rctl_rule_add(rule); 1911ec125fbbSEdward Tomasz Napierala 1912ec125fbbSEdward Tomasz Napierala out: 1913ec125fbbSEdward Tomasz Napierala rctl_rule_release(rule); 1914ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1915ec125fbbSEdward Tomasz Napierala return (error); 1916ec125fbbSEdward Tomasz Napierala } 1917ec125fbbSEdward Tomasz Napierala 1918ec125fbbSEdward Tomasz Napierala int 19198451d0ddSKip Macy sys_rctl_remove_rule(struct thread *td, struct rctl_remove_rule_args *uap) 1920ec125fbbSEdward Tomasz Napierala { 1921ec125fbbSEdward Tomasz Napierala struct rctl_rule *filter; 1922ec125fbbSEdward Tomasz Napierala char *inputstr; 1923c1a43e73SEdward Tomasz Napierala int error; 1924ec125fbbSEdward Tomasz Napierala 19254b5c9cf6SEdward Tomasz Napierala if (!racct_enable) 19264b5c9cf6SEdward Tomasz Napierala return (ENOSYS); 19274b5c9cf6SEdward Tomasz Napierala 1928ec125fbbSEdward Tomasz Napierala error = priv_check(td, PRIV_RCTL_REMOVE_RULE); 1929ec125fbbSEdward Tomasz Napierala if (error != 0) 1930ec125fbbSEdward Tomasz Napierala return (error); 1931ec125fbbSEdward Tomasz Napierala 1932ec125fbbSEdward Tomasz Napierala error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen); 1933ec125fbbSEdward Tomasz Napierala if (error != 0) 1934ec125fbbSEdward Tomasz Napierala return (error); 1935ec125fbbSEdward Tomasz Napierala 1936ec125fbbSEdward Tomasz Napierala sx_slock(&allproc_lock); 1937ec125fbbSEdward Tomasz Napierala error = rctl_string_to_rule(inputstr, &filter); 1938ec125fbbSEdward Tomasz Napierala free(inputstr, M_RCTL); 1939ec125fbbSEdward Tomasz Napierala if (error != 0) { 1940ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1941ec125fbbSEdward Tomasz Napierala return (error); 1942ec125fbbSEdward Tomasz Napierala } 1943ec125fbbSEdward Tomasz Napierala 1944ec125fbbSEdward Tomasz Napierala error = rctl_rule_remove(filter); 1945ec125fbbSEdward Tomasz Napierala rctl_rule_release(filter); 1946ec125fbbSEdward Tomasz Napierala sx_sunlock(&allproc_lock); 1947ec125fbbSEdward Tomasz Napierala 1948ec125fbbSEdward Tomasz Napierala return (error); 1949ec125fbbSEdward Tomasz Napierala } 1950ec125fbbSEdward Tomasz Napierala 1951ec125fbbSEdward Tomasz Napierala /* 1952ec125fbbSEdward Tomasz Napierala * Update RCTL rule list after credential change. 1953ec125fbbSEdward Tomasz Napierala */ 1954ec125fbbSEdward Tomasz Napierala void 1955ec125fbbSEdward Tomasz Napierala rctl_proc_ucred_changed(struct proc *p, struct ucred *newcred) 1956ec125fbbSEdward Tomasz Napierala { 1957c1a43e73SEdward Tomasz Napierala LIST_HEAD(, rctl_rule_link) newrules; 1958ec125fbbSEdward Tomasz Napierala struct rctl_rule_link *link, *newlink; 1959ec125fbbSEdward Tomasz Napierala struct uidinfo *newuip; 1960ec125fbbSEdward Tomasz Napierala struct loginclass *newlc; 1961a7ad07bfSEdward Tomasz Napierala struct prison_racct *newprr; 1962c1a43e73SEdward Tomasz Napierala int rulecnt, i; 1963ec125fbbSEdward Tomasz Napierala 1964f87beb93SAndriy Gapon if (!racct_enable) 1965f87beb93SAndriy Gapon return; 1966f87beb93SAndriy Gapon 1967f87beb93SAndriy Gapon PROC_LOCK_ASSERT(p, MA_NOTOWNED); 19684b5c9cf6SEdward Tomasz Napierala 1969ec125fbbSEdward Tomasz Napierala newuip = newcred->cr_ruidinfo; 1970ec125fbbSEdward Tomasz Napierala newlc = newcred->cr_loginclass; 1971a7ad07bfSEdward Tomasz Napierala newprr = newcred->cr_prison->pr_prison_racct; 1972ec125fbbSEdward Tomasz Napierala 1973ec125fbbSEdward Tomasz Napierala LIST_INIT(&newrules); 1974ec125fbbSEdward Tomasz Napierala 1975ec125fbbSEdward Tomasz Napierala again: 1976ec125fbbSEdward Tomasz Napierala /* 1977ec125fbbSEdward Tomasz Napierala * First, count the rules that apply to the process with new 1978ec125fbbSEdward Tomasz Napierala * credentials. 1979ec125fbbSEdward Tomasz Napierala */ 1980ec125fbbSEdward Tomasz Napierala rulecnt = 0; 1981bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 1982ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) { 1983ec125fbbSEdward Tomasz Napierala if (link->rrl_rule->rr_subject_type == 1984ec125fbbSEdward Tomasz Napierala RCTL_SUBJECT_TYPE_PROCESS) 1985ec125fbbSEdward Tomasz Napierala rulecnt++; 1986ec125fbbSEdward Tomasz Napierala } 1987ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &newuip->ui_racct->r_rule_links, rrl_next) 1988ec125fbbSEdward Tomasz Napierala rulecnt++; 1989ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &newlc->lc_racct->r_rule_links, rrl_next) 1990ec125fbbSEdward Tomasz Napierala rulecnt++; 1991a7ad07bfSEdward Tomasz Napierala LIST_FOREACH(link, &newprr->prr_racct->r_rule_links, rrl_next) 1992ec125fbbSEdward Tomasz Napierala rulecnt++; 1993bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 1994ec125fbbSEdward Tomasz Napierala 1995ec125fbbSEdward Tomasz Napierala /* 1996ec125fbbSEdward Tomasz Napierala * Create temporary list. We've dropped the rctl_lock in order 1997ec125fbbSEdward Tomasz Napierala * to use M_WAITOK. 1998ec125fbbSEdward Tomasz Napierala */ 1999ec125fbbSEdward Tomasz Napierala for (i = 0; i < rulecnt; i++) { 2000ec125fbbSEdward Tomasz Napierala newlink = uma_zalloc(rctl_rule_link_zone, M_WAITOK); 2001ec125fbbSEdward Tomasz Napierala newlink->rrl_rule = NULL; 2002ed810200SEdward Tomasz Napierala newlink->rrl_exceeded = 0; 2003ec125fbbSEdward Tomasz Napierala LIST_INSERT_HEAD(&newrules, newlink, rrl_next); 2004ec125fbbSEdward Tomasz Napierala } 2005ec125fbbSEdward Tomasz Napierala 2006ec125fbbSEdward Tomasz Napierala newlink = LIST_FIRST(&newrules); 2007ec125fbbSEdward Tomasz Napierala 2008ec125fbbSEdward Tomasz Napierala /* 2009ec125fbbSEdward Tomasz Napierala * Assign rules to the newly allocated list entries. 2010ec125fbbSEdward Tomasz Napierala */ 2011bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK(); 2012ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) { 2013ec125fbbSEdward Tomasz Napierala if (link->rrl_rule->rr_subject_type == 2014ec125fbbSEdward Tomasz Napierala RCTL_SUBJECT_TYPE_PROCESS) { 2015ec125fbbSEdward Tomasz Napierala if (newlink == NULL) 2016ec125fbbSEdward Tomasz Napierala goto goaround; 2017ec125fbbSEdward Tomasz Napierala rctl_rule_acquire(link->rrl_rule); 2018ec125fbbSEdward Tomasz Napierala newlink->rrl_rule = link->rrl_rule; 2019ed810200SEdward Tomasz Napierala newlink->rrl_exceeded = link->rrl_exceeded; 2020ec125fbbSEdward Tomasz Napierala newlink = LIST_NEXT(newlink, rrl_next); 2021ec125fbbSEdward Tomasz Napierala rulecnt--; 2022ec125fbbSEdward Tomasz Napierala } 2023ec125fbbSEdward Tomasz Napierala } 2024ec125fbbSEdward Tomasz Napierala 2025ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &newuip->ui_racct->r_rule_links, rrl_next) { 2026ec125fbbSEdward Tomasz Napierala if (newlink == NULL) 2027ec125fbbSEdward Tomasz Napierala goto goaround; 2028ec125fbbSEdward Tomasz Napierala rctl_rule_acquire(link->rrl_rule); 2029ec125fbbSEdward Tomasz Napierala newlink->rrl_rule = link->rrl_rule; 2030ed810200SEdward Tomasz Napierala newlink->rrl_exceeded = link->rrl_exceeded; 2031ec125fbbSEdward Tomasz Napierala newlink = LIST_NEXT(newlink, rrl_next); 2032ec125fbbSEdward Tomasz Napierala rulecnt--; 2033ec125fbbSEdward Tomasz Napierala } 2034ec125fbbSEdward Tomasz Napierala 2035ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &newlc->lc_racct->r_rule_links, rrl_next) { 2036ec125fbbSEdward Tomasz Napierala if (newlink == NULL) 2037ec125fbbSEdward Tomasz Napierala goto goaround; 2038ec125fbbSEdward Tomasz Napierala rctl_rule_acquire(link->rrl_rule); 2039ec125fbbSEdward Tomasz Napierala newlink->rrl_rule = link->rrl_rule; 2040ed810200SEdward Tomasz Napierala newlink->rrl_exceeded = link->rrl_exceeded; 2041ec125fbbSEdward Tomasz Napierala newlink = LIST_NEXT(newlink, rrl_next); 2042ec125fbbSEdward Tomasz Napierala rulecnt--; 2043ec125fbbSEdward Tomasz Napierala } 2044ec125fbbSEdward Tomasz Napierala 2045a7ad07bfSEdward Tomasz Napierala LIST_FOREACH(link, &newprr->prr_racct->r_rule_links, rrl_next) { 2046ec125fbbSEdward Tomasz Napierala if (newlink == NULL) 2047ec125fbbSEdward Tomasz Napierala goto goaround; 2048ec125fbbSEdward Tomasz Napierala rctl_rule_acquire(link->rrl_rule); 2049ec125fbbSEdward Tomasz Napierala newlink->rrl_rule = link->rrl_rule; 2050ed810200SEdward Tomasz Napierala newlink->rrl_exceeded = link->rrl_exceeded; 2051ec125fbbSEdward Tomasz Napierala newlink = LIST_NEXT(newlink, rrl_next); 2052ec125fbbSEdward Tomasz Napierala rulecnt--; 2053ec125fbbSEdward Tomasz Napierala } 2054ec125fbbSEdward Tomasz Napierala 2055ec125fbbSEdward Tomasz Napierala if (rulecnt == 0) { 2056ec125fbbSEdward Tomasz Napierala /* 2057ec125fbbSEdward Tomasz Napierala * Free the old rule list. 2058ec125fbbSEdward Tomasz Napierala */ 2059ec125fbbSEdward Tomasz Napierala while (!LIST_EMPTY(&p->p_racct->r_rule_links)) { 2060ec125fbbSEdward Tomasz Napierala link = LIST_FIRST(&p->p_racct->r_rule_links); 2061ec125fbbSEdward Tomasz Napierala LIST_REMOVE(link, rrl_next); 2062ec125fbbSEdward Tomasz Napierala rctl_rule_release(link->rrl_rule); 2063ec125fbbSEdward Tomasz Napierala uma_zfree(rctl_rule_link_zone, link); 2064ec125fbbSEdward Tomasz Napierala } 2065ec125fbbSEdward Tomasz Napierala 2066ec125fbbSEdward Tomasz Napierala /* 2067ec125fbbSEdward Tomasz Napierala * Replace lists and we're done. 2068ec125fbbSEdward Tomasz Napierala * 2069ec125fbbSEdward Tomasz Napierala * XXX: Is there any way to switch list heads instead 2070ec125fbbSEdward Tomasz Napierala * of iterating here? 2071ec125fbbSEdward Tomasz Napierala */ 2072ec125fbbSEdward Tomasz Napierala while (!LIST_EMPTY(&newrules)) { 2073ec125fbbSEdward Tomasz Napierala newlink = LIST_FIRST(&newrules); 2074ec125fbbSEdward Tomasz Napierala LIST_REMOVE(newlink, rrl_next); 2075ec125fbbSEdward Tomasz Napierala LIST_INSERT_HEAD(&p->p_racct->r_rule_links, 2076ec125fbbSEdward Tomasz Napierala newlink, rrl_next); 2077ec125fbbSEdward Tomasz Napierala } 2078ec125fbbSEdward Tomasz Napierala 2079bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 2080ec125fbbSEdward Tomasz Napierala 2081ec125fbbSEdward Tomasz Napierala return; 2082ec125fbbSEdward Tomasz Napierala } 2083ec125fbbSEdward Tomasz Napierala 2084ec125fbbSEdward Tomasz Napierala goaround: 2085bbe4eb6dSEdward Tomasz Napierala RACCT_UNLOCK(); 2086ec125fbbSEdward Tomasz Napierala 2087ec125fbbSEdward Tomasz Napierala /* 2088ec125fbbSEdward Tomasz Napierala * Rule list changed while we were not holding the rctl_lock. 2089ec125fbbSEdward Tomasz Napierala * Free the new list and try again. 2090ec125fbbSEdward Tomasz Napierala */ 2091ec125fbbSEdward Tomasz Napierala while (!LIST_EMPTY(&newrules)) { 2092ec125fbbSEdward Tomasz Napierala newlink = LIST_FIRST(&newrules); 2093ec125fbbSEdward Tomasz Napierala LIST_REMOVE(newlink, rrl_next); 2094ec125fbbSEdward Tomasz Napierala if (newlink->rrl_rule != NULL) 2095ec125fbbSEdward Tomasz Napierala rctl_rule_release(newlink->rrl_rule); 2096ec125fbbSEdward Tomasz Napierala uma_zfree(rctl_rule_link_zone, newlink); 2097ec125fbbSEdward Tomasz Napierala } 2098ec125fbbSEdward Tomasz Napierala 2099ec125fbbSEdward Tomasz Napierala goto again; 2100ec125fbbSEdward Tomasz Napierala } 2101ec125fbbSEdward Tomasz Napierala 2102ec125fbbSEdward Tomasz Napierala /* 2103ec125fbbSEdward Tomasz Napierala * Assign RCTL rules to the newly created process. 2104ec125fbbSEdward Tomasz Napierala */ 2105ec125fbbSEdward Tomasz Napierala int 2106ec125fbbSEdward Tomasz Napierala rctl_proc_fork(struct proc *parent, struct proc *child) 2107ec125fbbSEdward Tomasz Napierala { 2108ec125fbbSEdward Tomasz Napierala struct rctl_rule *rule; 2109c1a43e73SEdward Tomasz Napierala struct rctl_rule_link *link; 2110c1a43e73SEdward Tomasz Napierala int error; 2111ec125fbbSEdward Tomasz Napierala 21124b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 2113bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 21140b18eb6dSEdward Tomasz Napierala KASSERT(parent->p_racct != NULL, ("process without racct; p = %p", parent)); 2115ec125fbbSEdward Tomasz Napierala 2116bbe4eb6dSEdward Tomasz Napierala LIST_INIT(&child->p_racct->r_rule_links); 2117ec125fbbSEdward Tomasz Napierala 2118ec125fbbSEdward Tomasz Napierala /* 2119ec125fbbSEdward Tomasz Napierala * Go through limits applicable to the parent and assign them 2120ec125fbbSEdward Tomasz Napierala * to the child. Rules with 'process' subject have to be duplicated 2121ec125fbbSEdward Tomasz Napierala * in order to make their rr_subject point to the new process. 2122ec125fbbSEdward Tomasz Napierala */ 2123ec125fbbSEdward Tomasz Napierala LIST_FOREACH(link, &parent->p_racct->r_rule_links, rrl_next) { 2124ec125fbbSEdward Tomasz Napierala if (link->rrl_rule->rr_subject_type == 2125ec125fbbSEdward Tomasz Napierala RCTL_SUBJECT_TYPE_PROCESS) { 2126ec125fbbSEdward Tomasz Napierala rule = rctl_rule_duplicate(link->rrl_rule, M_NOWAIT); 2127ec125fbbSEdward Tomasz Napierala if (rule == NULL) 2128ec125fbbSEdward Tomasz Napierala goto fail; 2129ec125fbbSEdward Tomasz Napierala KASSERT(rule->rr_subject.rs_proc == parent, 2130ec125fbbSEdward Tomasz Napierala ("rule->rr_subject.rs_proc != parent")); 2131ec125fbbSEdward Tomasz Napierala rule->rr_subject.rs_proc = child; 2132ec125fbbSEdward Tomasz Napierala error = rctl_racct_add_rule_locked(child->p_racct, 2133ec125fbbSEdward Tomasz Napierala rule); 2134ec125fbbSEdward Tomasz Napierala rctl_rule_release(rule); 2135ec125fbbSEdward Tomasz Napierala if (error != 0) 2136ec125fbbSEdward Tomasz Napierala goto fail; 2137ec125fbbSEdward Tomasz Napierala } else { 2138ec125fbbSEdward Tomasz Napierala error = rctl_racct_add_rule_locked(child->p_racct, 2139ec125fbbSEdward Tomasz Napierala link->rrl_rule); 2140ec125fbbSEdward Tomasz Napierala if (error != 0) 2141ec125fbbSEdward Tomasz Napierala goto fail; 2142ec125fbbSEdward Tomasz Napierala } 2143ec125fbbSEdward Tomasz Napierala } 2144ec125fbbSEdward Tomasz Napierala 2145ec125fbbSEdward Tomasz Napierala return (0); 2146ec125fbbSEdward Tomasz Napierala 2147ec125fbbSEdward Tomasz Napierala fail: 2148ec125fbbSEdward Tomasz Napierala while (!LIST_EMPTY(&child->p_racct->r_rule_links)) { 2149ec125fbbSEdward Tomasz Napierala link = LIST_FIRST(&child->p_racct->r_rule_links); 2150ec125fbbSEdward Tomasz Napierala LIST_REMOVE(link, rrl_next); 2151ec125fbbSEdward Tomasz Napierala rctl_rule_release(link->rrl_rule); 2152ec125fbbSEdward Tomasz Napierala uma_zfree(rctl_rule_link_zone, link); 2153ec125fbbSEdward Tomasz Napierala } 2154bbe4eb6dSEdward Tomasz Napierala 2155ec125fbbSEdward Tomasz Napierala return (EAGAIN); 2156ec125fbbSEdward Tomasz Napierala } 2157ec125fbbSEdward Tomasz Napierala 2158ec125fbbSEdward Tomasz Napierala /* 2159ec125fbbSEdward Tomasz Napierala * Release rules attached to the racct. 2160ec125fbbSEdward Tomasz Napierala */ 2161ec125fbbSEdward Tomasz Napierala void 2162ec125fbbSEdward Tomasz Napierala rctl_racct_release(struct racct *racct) 2163ec125fbbSEdward Tomasz Napierala { 2164ec125fbbSEdward Tomasz Napierala struct rctl_rule_link *link; 2165ec125fbbSEdward Tomasz Napierala 21664b5c9cf6SEdward Tomasz Napierala ASSERT_RACCT_ENABLED(); 2167bbe4eb6dSEdward Tomasz Napierala RACCT_LOCK_ASSERT(); 21684b5c9cf6SEdward Tomasz Napierala 2169ec125fbbSEdward Tomasz Napierala while (!LIST_EMPTY(&racct->r_rule_links)) { 2170ec125fbbSEdward Tomasz Napierala link = LIST_FIRST(&racct->r_rule_links); 2171ec125fbbSEdward Tomasz Napierala LIST_REMOVE(link, rrl_next); 2172ec125fbbSEdward Tomasz Napierala rctl_rule_release(link->rrl_rule); 2173ec125fbbSEdward Tomasz Napierala uma_zfree(rctl_rule_link_zone, link); 2174ec125fbbSEdward Tomasz Napierala } 2175ec125fbbSEdward Tomasz Napierala } 2176ec125fbbSEdward Tomasz Napierala 2177ec125fbbSEdward Tomasz Napierala static void 2178ec125fbbSEdward Tomasz Napierala rctl_init(void) 2179ec125fbbSEdward Tomasz Napierala { 2180ec125fbbSEdward Tomasz Napierala 21814b5c9cf6SEdward Tomasz Napierala if (!racct_enable) 21824b5c9cf6SEdward Tomasz Napierala return; 21834b5c9cf6SEdward Tomasz Napierala 2184c1a43e73SEdward Tomasz Napierala rctl_rule_zone = uma_zcreate("rctl_rule", sizeof(struct rctl_rule), 218523e6fff2SEdward Tomasz Napierala NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 2186ec125fbbSEdward Tomasz Napierala rctl_rule_link_zone = uma_zcreate("rctl_rule_link", 2187ec125fbbSEdward Tomasz Napierala sizeof(struct rctl_rule_link), NULL, NULL, NULL, NULL, 218823e6fff2SEdward Tomasz Napierala UMA_ALIGN_PTR, 0); 2189ae34b6ffSEdward Tomasz Napierala 21908bd8c8f1SEdward Tomasz Napierala /* 21918bd8c8f1SEdward Tomasz Napierala * Set default values, making sure not to overwrite the ones 21928bd8c8f1SEdward Tomasz Napierala * fetched from tunables. Most of those could be set at the 21938bd8c8f1SEdward Tomasz Napierala * declaration, except for the rctl_throttle_max - we cannot 21948bd8c8f1SEdward Tomasz Napierala * set it there due to hz not being compile time constant. 21958bd8c8f1SEdward Tomasz Napierala */ 21968bd8c8f1SEdward Tomasz Napierala if (rctl_throttle_min < 1) 2197ae34b6ffSEdward Tomasz Napierala rctl_throttle_min = 1; 21988bd8c8f1SEdward Tomasz Napierala if (rctl_throttle_max < rctl_throttle_min) 2199ae34b6ffSEdward Tomasz Napierala rctl_throttle_max = 2 * hz; 22008bd8c8f1SEdward Tomasz Napierala if (rctl_throttle_pct < 0) 2201ae34b6ffSEdward Tomasz Napierala rctl_throttle_pct = 100; 22028bd8c8f1SEdward Tomasz Napierala if (rctl_throttle_pct2 < 0) 2203ae34b6ffSEdward Tomasz Napierala rctl_throttle_pct2 = 100; 2204ec125fbbSEdward Tomasz Napierala } 2205ec125fbbSEdward Tomasz Napierala 2206ec125fbbSEdward Tomasz Napierala #else /* !RCTL */ 2207ec125fbbSEdward Tomasz Napierala 2208e0205aa3SOlivier Certner #include <sys/types.h> 2209*6bb132baSBrooks Davis #include <sys/errno.h> 2210e0205aa3SOlivier Certner #include <sys/sysproto.h> 2211e0205aa3SOlivier Certner 2212ec125fbbSEdward Tomasz Napierala int 22138451d0ddSKip Macy sys_rctl_get_racct(struct thread *td, struct rctl_get_racct_args *uap) 2214ec125fbbSEdward Tomasz Napierala { 2215ec125fbbSEdward Tomasz Napierala 2216ec125fbbSEdward Tomasz Napierala return (ENOSYS); 2217ec125fbbSEdward Tomasz Napierala } 2218ec125fbbSEdward Tomasz Napierala 2219ec125fbbSEdward Tomasz Napierala int 22208451d0ddSKip Macy sys_rctl_get_rules(struct thread *td, struct rctl_get_rules_args *uap) 2221ec125fbbSEdward Tomasz Napierala { 2222ec125fbbSEdward Tomasz Napierala 2223ec125fbbSEdward Tomasz Napierala return (ENOSYS); 2224ec125fbbSEdward Tomasz Napierala } 2225ec125fbbSEdward Tomasz Napierala 2226ec125fbbSEdward Tomasz Napierala int 22278451d0ddSKip Macy sys_rctl_get_limits(struct thread *td, struct rctl_get_limits_args *uap) 2228ec125fbbSEdward Tomasz Napierala { 2229ec125fbbSEdward Tomasz Napierala 2230ec125fbbSEdward Tomasz Napierala return (ENOSYS); 2231ec125fbbSEdward Tomasz Napierala } 2232ec125fbbSEdward Tomasz Napierala 2233ec125fbbSEdward Tomasz Napierala int 22348451d0ddSKip Macy sys_rctl_add_rule(struct thread *td, struct rctl_add_rule_args *uap) 2235ec125fbbSEdward Tomasz Napierala { 2236ec125fbbSEdward Tomasz Napierala 2237ec125fbbSEdward Tomasz Napierala return (ENOSYS); 2238ec125fbbSEdward Tomasz Napierala } 2239ec125fbbSEdward Tomasz Napierala 2240ec125fbbSEdward Tomasz Napierala int 22418451d0ddSKip Macy sys_rctl_remove_rule(struct thread *td, struct rctl_remove_rule_args *uap) 2242ec125fbbSEdward Tomasz Napierala { 2243ec125fbbSEdward Tomasz Napierala 2244ec125fbbSEdward Tomasz Napierala return (ENOSYS); 2245ec125fbbSEdward Tomasz Napierala } 2246ec125fbbSEdward Tomasz Napierala 2247e0205aa3SOlivier Certner #endif /* RCTL */ 2248