1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/id_space.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/log.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/modhash.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/mutex.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/proc.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/procset.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/project.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/resource.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/rctl.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/siginfo.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/strlog.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/task.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/zone.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate /* 51*7c478bd9Sstevel@tonic-gate * Resource controls (rctls) 52*7c478bd9Sstevel@tonic-gate * 53*7c478bd9Sstevel@tonic-gate * The rctl subsystem provides a mechanism for kernel components to 54*7c478bd9Sstevel@tonic-gate * register their individual resource controls with the system as a whole, 55*7c478bd9Sstevel@tonic-gate * such that those controls can subscribe to specific actions while being 56*7c478bd9Sstevel@tonic-gate * associated with the various process-model entities provided by the kernel: 57*7c478bd9Sstevel@tonic-gate * the process, the task, the project, and the zone. (In principle, only 58*7c478bd9Sstevel@tonic-gate * minor modifications would be required to connect the resource control 59*7c478bd9Sstevel@tonic-gate * functionality to non-process-model entities associated with the system.) 60*7c478bd9Sstevel@tonic-gate * 61*7c478bd9Sstevel@tonic-gate * Subsystems register their rctls via rctl_register(). Subsystems 62*7c478bd9Sstevel@tonic-gate * also wishing to provide additional limits on a given rctl can modify 63*7c478bd9Sstevel@tonic-gate * them once they have the rctl handle. Each subsystem should store the 64*7c478bd9Sstevel@tonic-gate * handle to their rctl for direct access. 65*7c478bd9Sstevel@tonic-gate * 66*7c478bd9Sstevel@tonic-gate * A primary dictionary, rctl_dict, contains a hash of id to the default 67*7c478bd9Sstevel@tonic-gate * control definition for each controlled resource-entity pair on the system. 68*7c478bd9Sstevel@tonic-gate * A secondary dictionary, rctl_dict_by_name, contains a hash of name to 69*7c478bd9Sstevel@tonic-gate * resource control handles. The resource control handles are distributed by 70*7c478bd9Sstevel@tonic-gate * the rctl_ids ID space. The handles are private and not to be 71*7c478bd9Sstevel@tonic-gate * advertised to userland; all userland interactions are via the rctl 72*7c478bd9Sstevel@tonic-gate * names. 73*7c478bd9Sstevel@tonic-gate * 74*7c478bd9Sstevel@tonic-gate * Entities inherit their rctls from their predecessor. Since projects have 75*7c478bd9Sstevel@tonic-gate * no ancestor, they inherit their rctls from the rctl dict for project 76*7c478bd9Sstevel@tonic-gate * rctls. It is expected that project controls will be set to their 77*7c478bd9Sstevel@tonic-gate * appropriate values shortly after project creation, presumably from a 78*7c478bd9Sstevel@tonic-gate * policy source such as the project database. 79*7c478bd9Sstevel@tonic-gate * 80*7c478bd9Sstevel@tonic-gate * Data structures 81*7c478bd9Sstevel@tonic-gate * The rctl_set_t attached to each of the process model entities is a simple 82*7c478bd9Sstevel@tonic-gate * hash table keyed on the rctl handle assigned at registration. The entries 83*7c478bd9Sstevel@tonic-gate * in the hash table are rctl_t's, whose relationship with the active control 84*7c478bd9Sstevel@tonic-gate * values on that resource and with the global state of the resource we 85*7c478bd9Sstevel@tonic-gate * illustrate below: 86*7c478bd9Sstevel@tonic-gate * 87*7c478bd9Sstevel@tonic-gate * rctl_dict[key] --> rctl_dict_entry 88*7c478bd9Sstevel@tonic-gate * ^ 89*7c478bd9Sstevel@tonic-gate * | 90*7c478bd9Sstevel@tonic-gate * +--+---+ 91*7c478bd9Sstevel@tonic-gate * rctl_set[key] ---> | rctl | --> value <-> value <-> system value --> NULL 92*7c478bd9Sstevel@tonic-gate * +--+---+ ^ 93*7c478bd9Sstevel@tonic-gate * | | 94*7c478bd9Sstevel@tonic-gate * +------- cursor ------+ 95*7c478bd9Sstevel@tonic-gate * 96*7c478bd9Sstevel@tonic-gate * That is, the rctl contains a back pointer to the global resource control 97*7c478bd9Sstevel@tonic-gate * state for this resource, which is also available in the rctl_dict hash 98*7c478bd9Sstevel@tonic-gate * table mentioned earlier. The rctl contains two pointers to resource 99*7c478bd9Sstevel@tonic-gate * control values: one, values, indicates the entire sequence of control 100*7c478bd9Sstevel@tonic-gate * values; the other, cursor, indicates the currently active control 101*7c478bd9Sstevel@tonic-gate * value--the next value to be enforced. The value list itself is an open, 102*7c478bd9Sstevel@tonic-gate * doubly-linked list, the last non-NULL member of which is the system value 103*7c478bd9Sstevel@tonic-gate * for that resource (being the theoretical/conventional maximum allowable 104*7c478bd9Sstevel@tonic-gate * value for the resource on this OS instance). 105*7c478bd9Sstevel@tonic-gate * 106*7c478bd9Sstevel@tonic-gate * Ops Vector 107*7c478bd9Sstevel@tonic-gate * Subsystems publishing rctls need not provide instances of all of the 108*7c478bd9Sstevel@tonic-gate * functions specified by the ops vector. In particular, if general 109*7c478bd9Sstevel@tonic-gate * rctl_*() entry points are not being called, certain functions can be 110*7c478bd9Sstevel@tonic-gate * omitted. These align as follows: 111*7c478bd9Sstevel@tonic-gate * 112*7c478bd9Sstevel@tonic-gate * rctl_set() 113*7c478bd9Sstevel@tonic-gate * You may wish to provide a set callback if locking circumstances prevent 114*7c478bd9Sstevel@tonic-gate * it or if the performance cost of requesting the enforced value from the 115*7c478bd9Sstevel@tonic-gate * resource control is prohibitively expensive. For instance, the currently 116*7c478bd9Sstevel@tonic-gate * enforced file size limit is stored on the process in the p_fsz_ctl to 117*7c478bd9Sstevel@tonic-gate * maintain read()/write() performance. 118*7c478bd9Sstevel@tonic-gate * 119*7c478bd9Sstevel@tonic-gate * rctl_test() 120*7c478bd9Sstevel@tonic-gate * You must provide a test callback if you are using the rctl_test() 121*7c478bd9Sstevel@tonic-gate * interface. An action callback is optional. 122*7c478bd9Sstevel@tonic-gate * 123*7c478bd9Sstevel@tonic-gate * rctl_action() 124*7c478bd9Sstevel@tonic-gate * You may wish to provide an action callback. 125*7c478bd9Sstevel@tonic-gate * 126*7c478bd9Sstevel@tonic-gate * Registration 127*7c478bd9Sstevel@tonic-gate * New resource controls can be added to a running instance by loaded modules 128*7c478bd9Sstevel@tonic-gate * via registration. (The current implementation does not support unloadable 129*7c478bd9Sstevel@tonic-gate * modules; this functionality can be added if needed, via an 130*7c478bd9Sstevel@tonic-gate * activation/deactivation interface involving the manipulation of the 131*7c478bd9Sstevel@tonic-gate * ops vector for the resource control(s) needing to support unloading.) 132*7c478bd9Sstevel@tonic-gate * 133*7c478bd9Sstevel@tonic-gate * Control value ordering 134*7c478bd9Sstevel@tonic-gate * Because the rctl_val chain on each rctl must be navigable in a 135*7c478bd9Sstevel@tonic-gate * deterministic way, we have to define an ordering on the rctl_val_t's. The 136*7c478bd9Sstevel@tonic-gate * defined order is (flags & [maximal], value, flags & [deny-action], 137*7c478bd9Sstevel@tonic-gate * privilege). 138*7c478bd9Sstevel@tonic-gate * 139*7c478bd9Sstevel@tonic-gate * Locking 140*7c478bd9Sstevel@tonic-gate * rctl_dict_lock must be acquired prior to rctl_lists_lock. Since 141*7c478bd9Sstevel@tonic-gate * rctl_dict_lock or rctl_lists_lock can be called at the enforcement point 142*7c478bd9Sstevel@tonic-gate * of any subsystem, holding subsystem locks, it is at all times inappropriate 143*7c478bd9Sstevel@tonic-gate * to call kmem_alloc(., KM_SLEEP) while holding either of these locks. 144*7c478bd9Sstevel@tonic-gate * Traversing any of the various resource control entity lists requires 145*7c478bd9Sstevel@tonic-gate * holding rctl_lists_lock. 146*7c478bd9Sstevel@tonic-gate * 147*7c478bd9Sstevel@tonic-gate * Each individual resource control set associated with an entity must have 148*7c478bd9Sstevel@tonic-gate * its rcs_lock held for the duration of any operations that would add 149*7c478bd9Sstevel@tonic-gate * resource controls or control values to the set. 150*7c478bd9Sstevel@tonic-gate * 151*7c478bd9Sstevel@tonic-gate * The locking subsequence of interest is: p_lock, rctl_dict_lock, 152*7c478bd9Sstevel@tonic-gate * rctl_lists_lock, entity->rcs_lock. 153*7c478bd9Sstevel@tonic-gate */ 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate id_t max_rctl_hndl = 32768; 156*7c478bd9Sstevel@tonic-gate int rctl_dict_size = 64; 157*7c478bd9Sstevel@tonic-gate int rctl_set_size = 8; 158*7c478bd9Sstevel@tonic-gate kmutex_t rctl_dict_lock; 159*7c478bd9Sstevel@tonic-gate mod_hash_t *rctl_dict; 160*7c478bd9Sstevel@tonic-gate mod_hash_t *rctl_dict_by_name; 161*7c478bd9Sstevel@tonic-gate id_space_t *rctl_ids; 162*7c478bd9Sstevel@tonic-gate kmem_cache_t *rctl_cache; /* kmem cache for rctl structures */ 163*7c478bd9Sstevel@tonic-gate kmem_cache_t *rctl_val_cache; /* kmem cache for rctl values */ 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate kmutex_t rctl_lists_lock; 166*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rctl_lists[RC_MAX_ENTITY + 1]; 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate /* 169*7c478bd9Sstevel@tonic-gate * Default resource control operations and ops vector 170*7c478bd9Sstevel@tonic-gate * To be used if the particular rcontrol has no specific actions defined, or 171*7c478bd9Sstevel@tonic-gate * if the subsystem providing the control is quiescing (in preparation for 172*7c478bd9Sstevel@tonic-gate * unloading, presumably.) 173*7c478bd9Sstevel@tonic-gate * 174*7c478bd9Sstevel@tonic-gate * Resource controls with callbacks should fill the unused operations with the 175*7c478bd9Sstevel@tonic-gate * appropriate default impotent callback. 176*7c478bd9Sstevel@tonic-gate */ 177*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 178*7c478bd9Sstevel@tonic-gate void 179*7c478bd9Sstevel@tonic-gate rcop_no_action(struct rctl *r, struct proc *p, rctl_entity_p_t *e) 180*7c478bd9Sstevel@tonic-gate { 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 184*7c478bd9Sstevel@tonic-gate rctl_qty_t 185*7c478bd9Sstevel@tonic-gate rcop_no_usage(struct rctl *r, struct proc *p) 186*7c478bd9Sstevel@tonic-gate { 187*7c478bd9Sstevel@tonic-gate return (0); 188*7c478bd9Sstevel@tonic-gate } 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 191*7c478bd9Sstevel@tonic-gate int 192*7c478bd9Sstevel@tonic-gate rcop_no_set(struct rctl *r, struct proc *p, rctl_entity_p_t *e, rctl_qty_t l) 193*7c478bd9Sstevel@tonic-gate { 194*7c478bd9Sstevel@tonic-gate return (0); 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 198*7c478bd9Sstevel@tonic-gate int 199*7c478bd9Sstevel@tonic-gate rcop_no_test(struct rctl *r, struct proc *p, rctl_entity_p_t *e, 200*7c478bd9Sstevel@tonic-gate struct rctl_val *rv, rctl_qty_t i, uint_t f) 201*7c478bd9Sstevel@tonic-gate { 202*7c478bd9Sstevel@tonic-gate return (0); 203*7c478bd9Sstevel@tonic-gate } 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate rctl_ops_t rctl_default_ops = { 206*7c478bd9Sstevel@tonic-gate rcop_no_action, 207*7c478bd9Sstevel@tonic-gate rcop_no_usage, 208*7c478bd9Sstevel@tonic-gate rcop_no_set, 209*7c478bd9Sstevel@tonic-gate rcop_no_test 210*7c478bd9Sstevel@tonic-gate }; 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate /* 213*7c478bd9Sstevel@tonic-gate * Default "absolute" resource control operation and ops vector 214*7c478bd9Sstevel@tonic-gate * Useful if there is no usage associated with the 215*7c478bd9Sstevel@tonic-gate * resource control. 216*7c478bd9Sstevel@tonic-gate */ 217*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 218*7c478bd9Sstevel@tonic-gate int 219*7c478bd9Sstevel@tonic-gate rcop_absolute_test(struct rctl *r, struct proc *p, rctl_entity_p_t *e, 220*7c478bd9Sstevel@tonic-gate struct rctl_val *rv, rctl_qty_t i, uint_t f) 221*7c478bd9Sstevel@tonic-gate { 222*7c478bd9Sstevel@tonic-gate return (i > rv->rcv_value); 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate rctl_ops_t rctl_absolute_ops = { 226*7c478bd9Sstevel@tonic-gate rcop_no_action, 227*7c478bd9Sstevel@tonic-gate rcop_no_usage, 228*7c478bd9Sstevel@tonic-gate rcop_no_set, 229*7c478bd9Sstevel@tonic-gate rcop_absolute_test 230*7c478bd9Sstevel@tonic-gate }; 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 233*7c478bd9Sstevel@tonic-gate static uint_t 234*7c478bd9Sstevel@tonic-gate rctl_dict_hash_by_id(void *hash_data, mod_hash_key_t key) 235*7c478bd9Sstevel@tonic-gate { 236*7c478bd9Sstevel@tonic-gate return ((uint_t)(uintptr_t)key % rctl_dict_size); 237*7c478bd9Sstevel@tonic-gate } 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate static int 240*7c478bd9Sstevel@tonic-gate rctl_dict_id_cmp(mod_hash_key_t key1, mod_hash_key_t key2) 241*7c478bd9Sstevel@tonic-gate { 242*7c478bd9Sstevel@tonic-gate uint_t u1 = (uint_t)(uintptr_t)key1; 243*7c478bd9Sstevel@tonic-gate uint_t u2 = (uint_t)(uintptr_t)key2; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate if (u1 > u2) 246*7c478bd9Sstevel@tonic-gate return (1); 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate if (u1 == u2) 249*7c478bd9Sstevel@tonic-gate return (0); 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate return (-1); 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate static void 255*7c478bd9Sstevel@tonic-gate rctl_dict_val_dtor(mod_hash_val_t val) 256*7c478bd9Sstevel@tonic-gate { 257*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *kr = (rctl_dict_entry_t *)val; 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate kmem_free(kr, sizeof (rctl_dict_entry_t)); 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate /* 263*7c478bd9Sstevel@tonic-gate * size_t rctl_build_name_buf() 264*7c478bd9Sstevel@tonic-gate * 265*7c478bd9Sstevel@tonic-gate * Overview 266*7c478bd9Sstevel@tonic-gate * rctl_build_name_buf() walks all active resource controls in the dictionary, 267*7c478bd9Sstevel@tonic-gate * building a buffer of continguous NUL-terminated strings. 268*7c478bd9Sstevel@tonic-gate * 269*7c478bd9Sstevel@tonic-gate * Return values 270*7c478bd9Sstevel@tonic-gate * The size of the buffer is returned, the passed pointer's contents are 271*7c478bd9Sstevel@tonic-gate * modified to that of the location of the buffer. 272*7c478bd9Sstevel@tonic-gate * 273*7c478bd9Sstevel@tonic-gate * Caller's context 274*7c478bd9Sstevel@tonic-gate * Caller must be in a context suitable for KM_SLEEP allocations. 275*7c478bd9Sstevel@tonic-gate */ 276*7c478bd9Sstevel@tonic-gate size_t 277*7c478bd9Sstevel@tonic-gate rctl_build_name_buf(char **rbufp) 278*7c478bd9Sstevel@tonic-gate { 279*7c478bd9Sstevel@tonic-gate size_t req_size, cpy_size; 280*7c478bd9Sstevel@tonic-gate char *rbufloc; 281*7c478bd9Sstevel@tonic-gate int i; 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate rctl_rebuild_name_buf: 284*7c478bd9Sstevel@tonic-gate req_size = cpy_size = 0; 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate /* 287*7c478bd9Sstevel@tonic-gate * Calculate needed buffer length. 288*7c478bd9Sstevel@tonic-gate */ 289*7c478bd9Sstevel@tonic-gate mutex_enter(&rctl_lists_lock); 290*7c478bd9Sstevel@tonic-gate for (i = 0; i < RC_MAX_ENTITY + 1; i++) { 291*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde; 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate for (rde = rctl_lists[i]; 294*7c478bd9Sstevel@tonic-gate rde != NULL; 295*7c478bd9Sstevel@tonic-gate rde = rde->rcd_next) 296*7c478bd9Sstevel@tonic-gate req_size += strlen(rde->rcd_name) + 1; 297*7c478bd9Sstevel@tonic-gate } 298*7c478bd9Sstevel@tonic-gate mutex_exit(&rctl_lists_lock); 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate rbufloc = *rbufp = kmem_alloc(req_size, KM_SLEEP); 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate /* 303*7c478bd9Sstevel@tonic-gate * Copy rctl names into our buffer. If the copy length exceeds the 304*7c478bd9Sstevel@tonic-gate * allocate length (due to registration changes), stop copying, free the 305*7c478bd9Sstevel@tonic-gate * buffer, and start again. 306*7c478bd9Sstevel@tonic-gate */ 307*7c478bd9Sstevel@tonic-gate mutex_enter(&rctl_lists_lock); 308*7c478bd9Sstevel@tonic-gate for (i = 0; i < RC_MAX_ENTITY + 1; i++) { 309*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde; 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate for (rde = rctl_lists[i]; 312*7c478bd9Sstevel@tonic-gate rde != NULL; 313*7c478bd9Sstevel@tonic-gate rde = rde->rcd_next) { 314*7c478bd9Sstevel@tonic-gate size_t length = strlen(rde->rcd_name) + 1; 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate cpy_size += length; 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate if (cpy_size > req_size) { 319*7c478bd9Sstevel@tonic-gate kmem_free(*rbufp, req_size); 320*7c478bd9Sstevel@tonic-gate mutex_exit(&rctl_lists_lock); 321*7c478bd9Sstevel@tonic-gate goto rctl_rebuild_name_buf; 322*7c478bd9Sstevel@tonic-gate } 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate bcopy(rde->rcd_name, rbufloc, length); 325*7c478bd9Sstevel@tonic-gate rbufloc += length; 326*7c478bd9Sstevel@tonic-gate } 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate mutex_exit(&rctl_lists_lock); 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate return (req_size); 331*7c478bd9Sstevel@tonic-gate } 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate /* 334*7c478bd9Sstevel@tonic-gate * rctl_dict_entry_t *rctl_dict_lookup(const char *) 335*7c478bd9Sstevel@tonic-gate * 336*7c478bd9Sstevel@tonic-gate * Overview 337*7c478bd9Sstevel@tonic-gate * rctl_dict_lookup() returns the resource control dictionary entry for the 338*7c478bd9Sstevel@tonic-gate * named resource control. 339*7c478bd9Sstevel@tonic-gate * 340*7c478bd9Sstevel@tonic-gate * Return values 341*7c478bd9Sstevel@tonic-gate * A pointer to the appropriate resource control dictionary entry, or NULL if 342*7c478bd9Sstevel@tonic-gate * no such named entry exists. 343*7c478bd9Sstevel@tonic-gate * 344*7c478bd9Sstevel@tonic-gate * Caller's context 345*7c478bd9Sstevel@tonic-gate * Caller must not be holding rctl_dict_lock. 346*7c478bd9Sstevel@tonic-gate */ 347*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t * 348*7c478bd9Sstevel@tonic-gate rctl_dict_lookup(const char *name) 349*7c478bd9Sstevel@tonic-gate { 350*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde; 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate mutex_enter(&rctl_dict_lock); 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate if (mod_hash_find(rctl_dict_by_name, (mod_hash_key_t)name, 355*7c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&rde) == MH_ERR_NOTFOUND) { 356*7c478bd9Sstevel@tonic-gate mutex_exit(&rctl_dict_lock); 357*7c478bd9Sstevel@tonic-gate return (NULL); 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate mutex_exit(&rctl_dict_lock); 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate return (rde); 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate /* 366*7c478bd9Sstevel@tonic-gate * rctl_hndl_t rctl_hndl_lookup(const char *) 367*7c478bd9Sstevel@tonic-gate * 368*7c478bd9Sstevel@tonic-gate * Overview 369*7c478bd9Sstevel@tonic-gate * rctl_hndl_lookup() returns the resource control id (the "handle") for the 370*7c478bd9Sstevel@tonic-gate * named resource control. 371*7c478bd9Sstevel@tonic-gate * 372*7c478bd9Sstevel@tonic-gate * Return values 373*7c478bd9Sstevel@tonic-gate * The appropriate id, or -1 if no such named entry exists. 374*7c478bd9Sstevel@tonic-gate * 375*7c478bd9Sstevel@tonic-gate * Caller's context 376*7c478bd9Sstevel@tonic-gate * Caller must not be holding rctl_dict_lock. 377*7c478bd9Sstevel@tonic-gate */ 378*7c478bd9Sstevel@tonic-gate rctl_hndl_t 379*7c478bd9Sstevel@tonic-gate rctl_hndl_lookup(const char *name) 380*7c478bd9Sstevel@tonic-gate { 381*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde; 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate if ((rde = rctl_dict_lookup(name)) == NULL) 384*7c478bd9Sstevel@tonic-gate return (-1); 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate return (rde->rcd_id); 387*7c478bd9Sstevel@tonic-gate } 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate /* 390*7c478bd9Sstevel@tonic-gate * rctl_dict_entry_t * rctl_dict_lookup_hndl(rctl_hndl_t) 391*7c478bd9Sstevel@tonic-gate * 392*7c478bd9Sstevel@tonic-gate * Overview 393*7c478bd9Sstevel@tonic-gate * rctl_dict_lookup_hndl() completes the public lookup functions, by returning 394*7c478bd9Sstevel@tonic-gate * the resource control dictionary entry matching a given resource control id. 395*7c478bd9Sstevel@tonic-gate * 396*7c478bd9Sstevel@tonic-gate * Return values 397*7c478bd9Sstevel@tonic-gate * A pointer to the matching resource control dictionary entry, or NULL if the 398*7c478bd9Sstevel@tonic-gate * id does not match any existing entries. 399*7c478bd9Sstevel@tonic-gate * 400*7c478bd9Sstevel@tonic-gate * Caller's context 401*7c478bd9Sstevel@tonic-gate * Caller must not be holding rctl_lists_lock. 402*7c478bd9Sstevel@tonic-gate */ 403*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t * 404*7c478bd9Sstevel@tonic-gate rctl_dict_lookup_hndl(rctl_hndl_t hndl) 405*7c478bd9Sstevel@tonic-gate { 406*7c478bd9Sstevel@tonic-gate uint_t i; 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate mutex_enter(&rctl_lists_lock); 409*7c478bd9Sstevel@tonic-gate for (i = 0; i < RC_MAX_ENTITY + 1; i++) { 410*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde; 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate for (rde = rctl_lists[i]; 413*7c478bd9Sstevel@tonic-gate rde != NULL; 414*7c478bd9Sstevel@tonic-gate rde = rde->rcd_next) 415*7c478bd9Sstevel@tonic-gate if (rde->rcd_id == hndl) { 416*7c478bd9Sstevel@tonic-gate mutex_exit(&rctl_lists_lock); 417*7c478bd9Sstevel@tonic-gate return (rde); 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate mutex_exit(&rctl_lists_lock); 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate return (NULL); 423*7c478bd9Sstevel@tonic-gate } 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate /* 426*7c478bd9Sstevel@tonic-gate * void rctl_add_default_limit(const char *name, rctl_qty_t value, 427*7c478bd9Sstevel@tonic-gate * rctl_priv_t privilege, uint_t action) 428*7c478bd9Sstevel@tonic-gate * 429*7c478bd9Sstevel@tonic-gate * Overview 430*7c478bd9Sstevel@tonic-gate * Create a default limit with specified value, privilege, and action. 431*7c478bd9Sstevel@tonic-gate * 432*7c478bd9Sstevel@tonic-gate * Return value 433*7c478bd9Sstevel@tonic-gate * No value returned. 434*7c478bd9Sstevel@tonic-gate */ 435*7c478bd9Sstevel@tonic-gate void 436*7c478bd9Sstevel@tonic-gate rctl_add_default_limit(const char *name, rctl_qty_t value, 437*7c478bd9Sstevel@tonic-gate rctl_priv_t privilege, uint_t action) 438*7c478bd9Sstevel@tonic-gate { 439*7c478bd9Sstevel@tonic-gate rctl_val_t *dval; 440*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde; 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate dval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP); 443*7c478bd9Sstevel@tonic-gate bzero(dval, sizeof (rctl_val_t)); 444*7c478bd9Sstevel@tonic-gate dval->rcv_value = value; 445*7c478bd9Sstevel@tonic-gate dval->rcv_privilege = privilege; 446*7c478bd9Sstevel@tonic-gate dval->rcv_flagaction = action; 447*7c478bd9Sstevel@tonic-gate dval->rcv_action_recip_pid = -1; 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate rde = rctl_dict_lookup(name); 450*7c478bd9Sstevel@tonic-gate (void) rctl_val_list_insert(&rde->rcd_default_value, dval); 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate /* 454*7c478bd9Sstevel@tonic-gate * void rctl_add_legacy_limit(const char *name, const char *mname, 455*7c478bd9Sstevel@tonic-gate * const char *lname, rctl_qty_t dflt) 456*7c478bd9Sstevel@tonic-gate * 457*7c478bd9Sstevel@tonic-gate * Overview 458*7c478bd9Sstevel@tonic-gate * Create a default privileged limit, using the value obtained from 459*7c478bd9Sstevel@tonic-gate * /etc/system if it exists and is greater than the specified default 460*7c478bd9Sstevel@tonic-gate * value. Exists primarily for System V IPC. 461*7c478bd9Sstevel@tonic-gate * 462*7c478bd9Sstevel@tonic-gate * Return value 463*7c478bd9Sstevel@tonic-gate * No value returned. 464*7c478bd9Sstevel@tonic-gate */ 465*7c478bd9Sstevel@tonic-gate void 466*7c478bd9Sstevel@tonic-gate rctl_add_legacy_limit(const char *name, const char *mname, const char *lname, 467*7c478bd9Sstevel@tonic-gate rctl_qty_t dflt, rctl_qty_t max) 468*7c478bd9Sstevel@tonic-gate { 469*7c478bd9Sstevel@tonic-gate rctl_qty_t qty; 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate if (!mod_sysvar(mname, lname, &qty) || (qty < dflt)) 472*7c478bd9Sstevel@tonic-gate qty = dflt; 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate if (qty > max) 475*7c478bd9Sstevel@tonic-gate qty = max; 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate rctl_add_default_limit(name, qty, RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY); 478*7c478bd9Sstevel@tonic-gate } 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate static rctl_set_t * 481*7c478bd9Sstevel@tonic-gate rctl_entity_obtain_rset(rctl_dict_entry_t *rcd, struct proc *p) 482*7c478bd9Sstevel@tonic-gate { 483*7c478bd9Sstevel@tonic-gate rctl_set_t *rset = NULL; 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate if (rcd == NULL) 486*7c478bd9Sstevel@tonic-gate return (NULL); 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate switch (rcd->rcd_entity) { 489*7c478bd9Sstevel@tonic-gate case RCENTITY_PROCESS: 490*7c478bd9Sstevel@tonic-gate rset = p->p_rctls; 491*7c478bd9Sstevel@tonic-gate break; 492*7c478bd9Sstevel@tonic-gate case RCENTITY_TASK: 493*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 494*7c478bd9Sstevel@tonic-gate if (p->p_task != NULL) 495*7c478bd9Sstevel@tonic-gate rset = p->p_task->tk_rctls; 496*7c478bd9Sstevel@tonic-gate break; 497*7c478bd9Sstevel@tonic-gate case RCENTITY_PROJECT: 498*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 499*7c478bd9Sstevel@tonic-gate if (p->p_task != NULL && 500*7c478bd9Sstevel@tonic-gate p->p_task->tk_proj != NULL) 501*7c478bd9Sstevel@tonic-gate rset = p->p_task->tk_proj->kpj_rctls; 502*7c478bd9Sstevel@tonic-gate break; 503*7c478bd9Sstevel@tonic-gate case RCENTITY_ZONE: 504*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 505*7c478bd9Sstevel@tonic-gate if (p->p_zone != NULL) 506*7c478bd9Sstevel@tonic-gate rset = p->p_zone->zone_rctls; 507*7c478bd9Sstevel@tonic-gate break; 508*7c478bd9Sstevel@tonic-gate default: 509*7c478bd9Sstevel@tonic-gate panic("unknown rctl entity type %d seen", rcd->rcd_entity); 510*7c478bd9Sstevel@tonic-gate break; 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate 513*7c478bd9Sstevel@tonic-gate return (rset); 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate static void 517*7c478bd9Sstevel@tonic-gate rctl_entity_obtain_entity_p(rctl_entity_t entity, struct proc *p, 518*7c478bd9Sstevel@tonic-gate rctl_entity_p_t *e) 519*7c478bd9Sstevel@tonic-gate { 520*7c478bd9Sstevel@tonic-gate e->rcep_p.proc = NULL; 521*7c478bd9Sstevel@tonic-gate e->rcep_t = entity; 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate switch (entity) { 524*7c478bd9Sstevel@tonic-gate case RCENTITY_PROCESS: 525*7c478bd9Sstevel@tonic-gate e->rcep_p.proc = p; 526*7c478bd9Sstevel@tonic-gate break; 527*7c478bd9Sstevel@tonic-gate case RCENTITY_TASK: 528*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 529*7c478bd9Sstevel@tonic-gate if (p->p_task != NULL) 530*7c478bd9Sstevel@tonic-gate e->rcep_p.task = p->p_task; 531*7c478bd9Sstevel@tonic-gate break; 532*7c478bd9Sstevel@tonic-gate case RCENTITY_PROJECT: 533*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 534*7c478bd9Sstevel@tonic-gate if (p->p_task != NULL && 535*7c478bd9Sstevel@tonic-gate p->p_task->tk_proj != NULL) 536*7c478bd9Sstevel@tonic-gate e->rcep_p.proj = p->p_task->tk_proj; 537*7c478bd9Sstevel@tonic-gate break; 538*7c478bd9Sstevel@tonic-gate case RCENTITY_ZONE: 539*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 540*7c478bd9Sstevel@tonic-gate if (p->p_zone != NULL) 541*7c478bd9Sstevel@tonic-gate e->rcep_p.zone = p->p_zone; 542*7c478bd9Sstevel@tonic-gate break; 543*7c478bd9Sstevel@tonic-gate default: 544*7c478bd9Sstevel@tonic-gate panic("unknown rctl entity type %d seen", entity); 545*7c478bd9Sstevel@tonic-gate break; 546*7c478bd9Sstevel@tonic-gate } 547*7c478bd9Sstevel@tonic-gate } 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate static void 550*7c478bd9Sstevel@tonic-gate rctl_gp_alloc(rctl_alloc_gp_t *rcgp) 551*7c478bd9Sstevel@tonic-gate { 552*7c478bd9Sstevel@tonic-gate uint_t i; 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate if (rcgp->rcag_nctls > 0) { 555*7c478bd9Sstevel@tonic-gate rctl_t *prev = kmem_cache_alloc(rctl_cache, KM_SLEEP); 556*7c478bd9Sstevel@tonic-gate rctl_t *rctl = prev; 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate rcgp->rcag_ctls = prev; 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate for (i = 1; i < rcgp->rcag_nctls; i++) { 561*7c478bd9Sstevel@tonic-gate rctl = kmem_cache_alloc(rctl_cache, KM_SLEEP); 562*7c478bd9Sstevel@tonic-gate prev->rc_next = rctl; 563*7c478bd9Sstevel@tonic-gate prev = rctl; 564*7c478bd9Sstevel@tonic-gate } 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate rctl->rc_next = NULL; 567*7c478bd9Sstevel@tonic-gate } 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate if (rcgp->rcag_nvals > 0) { 570*7c478bd9Sstevel@tonic-gate rctl_val_t *prev = kmem_cache_alloc(rctl_val_cache, KM_SLEEP); 571*7c478bd9Sstevel@tonic-gate rctl_val_t *rval = prev; 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate rcgp->rcag_vals = prev; 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate for (i = 1; i < rcgp->rcag_nvals; i++) { 576*7c478bd9Sstevel@tonic-gate rval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP); 577*7c478bd9Sstevel@tonic-gate prev->rcv_next = rval; 578*7c478bd9Sstevel@tonic-gate prev = rval; 579*7c478bd9Sstevel@tonic-gate } 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate rval->rcv_next = NULL; 582*7c478bd9Sstevel@tonic-gate } 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate static rctl_val_t * 587*7c478bd9Sstevel@tonic-gate rctl_gp_detach_val(rctl_alloc_gp_t *rcgp) 588*7c478bd9Sstevel@tonic-gate { 589*7c478bd9Sstevel@tonic-gate rctl_val_t *rval = rcgp->rcag_vals; 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate ASSERT(rcgp->rcag_nvals > 0); 592*7c478bd9Sstevel@tonic-gate rcgp->rcag_nvals--; 593*7c478bd9Sstevel@tonic-gate rcgp->rcag_vals = rval->rcv_next; 594*7c478bd9Sstevel@tonic-gate 595*7c478bd9Sstevel@tonic-gate rval->rcv_next = NULL; 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate return (rval); 598*7c478bd9Sstevel@tonic-gate } 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate static rctl_t * 601*7c478bd9Sstevel@tonic-gate rctl_gp_detach_ctl(rctl_alloc_gp_t *rcgp) 602*7c478bd9Sstevel@tonic-gate { 603*7c478bd9Sstevel@tonic-gate rctl_t *rctl = rcgp->rcag_ctls; 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate ASSERT(rcgp->rcag_nctls > 0); 606*7c478bd9Sstevel@tonic-gate rcgp->rcag_nctls--; 607*7c478bd9Sstevel@tonic-gate rcgp->rcag_ctls = rctl->rc_next; 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate rctl->rc_next = NULL; 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate return (rctl); 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate } 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate static void 616*7c478bd9Sstevel@tonic-gate rctl_gp_free(rctl_alloc_gp_t *rcgp) 617*7c478bd9Sstevel@tonic-gate { 618*7c478bd9Sstevel@tonic-gate rctl_val_t *rval = rcgp->rcag_vals; 619*7c478bd9Sstevel@tonic-gate rctl_t *rctl = rcgp->rcag_ctls; 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate while (rval != NULL) { 622*7c478bd9Sstevel@tonic-gate rctl_val_t *next = rval->rcv_next; 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, rval); 625*7c478bd9Sstevel@tonic-gate rval = next; 626*7c478bd9Sstevel@tonic-gate } 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate while (rctl != NULL) { 629*7c478bd9Sstevel@tonic-gate rctl_t *next = rctl->rc_next; 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_cache, rctl); 632*7c478bd9Sstevel@tonic-gate rctl = next; 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate } 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate /* 637*7c478bd9Sstevel@tonic-gate * void rctl_prealloc_destroy(rctl_alloc_gp_t *) 638*7c478bd9Sstevel@tonic-gate * 639*7c478bd9Sstevel@tonic-gate * Overview 640*7c478bd9Sstevel@tonic-gate * Release all unused memory allocated via one of the "prealloc" functions: 641*7c478bd9Sstevel@tonic-gate * rctl_set_init_prealloc, rctl_set_dup_prealloc, or rctl_rlimit_set_prealloc. 642*7c478bd9Sstevel@tonic-gate * 643*7c478bd9Sstevel@tonic-gate * Return values 644*7c478bd9Sstevel@tonic-gate * None. 645*7c478bd9Sstevel@tonic-gate * 646*7c478bd9Sstevel@tonic-gate * Caller's context 647*7c478bd9Sstevel@tonic-gate * No restrictions on context. 648*7c478bd9Sstevel@tonic-gate */ 649*7c478bd9Sstevel@tonic-gate void 650*7c478bd9Sstevel@tonic-gate rctl_prealloc_destroy(rctl_alloc_gp_t *gp) 651*7c478bd9Sstevel@tonic-gate { 652*7c478bd9Sstevel@tonic-gate rctl_gp_free(gp); 653*7c478bd9Sstevel@tonic-gate kmem_free(gp, sizeof (rctl_alloc_gp_t)); 654*7c478bd9Sstevel@tonic-gate } 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate /* 657*7c478bd9Sstevel@tonic-gate * int rctl_val_cmp(rctl_val_t *, rctl_val_t *, int) 658*7c478bd9Sstevel@tonic-gate * 659*7c478bd9Sstevel@tonic-gate * Overview 660*7c478bd9Sstevel@tonic-gate * This function defines an ordering to rctl_val_t's in order to allow 661*7c478bd9Sstevel@tonic-gate * for correct placement in value lists. When the imprecise flag is set, 662*7c478bd9Sstevel@tonic-gate * the action recipient is ignored. This is to facilitate insert, 663*7c478bd9Sstevel@tonic-gate * delete, and replace operations by rctlsys. 664*7c478bd9Sstevel@tonic-gate * 665*7c478bd9Sstevel@tonic-gate * Return values 666*7c478bd9Sstevel@tonic-gate * 0 if the val_t's are are considered identical 667*7c478bd9Sstevel@tonic-gate * -1 if a is ordered lower than b 668*7c478bd9Sstevel@tonic-gate * 1 if a is lowered higher than b 669*7c478bd9Sstevel@tonic-gate * 670*7c478bd9Sstevel@tonic-gate * Caller's context 671*7c478bd9Sstevel@tonic-gate * No restrictions on context. 672*7c478bd9Sstevel@tonic-gate */ 673*7c478bd9Sstevel@tonic-gate int 674*7c478bd9Sstevel@tonic-gate rctl_val_cmp(rctl_val_t *a, rctl_val_t *b, int imprecise) 675*7c478bd9Sstevel@tonic-gate { 676*7c478bd9Sstevel@tonic-gate if ((a->rcv_flagaction & RCTL_LOCAL_MAXIMAL) < 677*7c478bd9Sstevel@tonic-gate (b->rcv_flagaction & RCTL_LOCAL_MAXIMAL)) 678*7c478bd9Sstevel@tonic-gate return (-1); 679*7c478bd9Sstevel@tonic-gate 680*7c478bd9Sstevel@tonic-gate if ((a->rcv_flagaction & RCTL_LOCAL_MAXIMAL) > 681*7c478bd9Sstevel@tonic-gate (b->rcv_flagaction & RCTL_LOCAL_MAXIMAL)) 682*7c478bd9Sstevel@tonic-gate return (1); 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate if (a->rcv_value < b->rcv_value) 685*7c478bd9Sstevel@tonic-gate return (-1); 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate if (a->rcv_value > b->rcv_value) 688*7c478bd9Sstevel@tonic-gate return (1); 689*7c478bd9Sstevel@tonic-gate 690*7c478bd9Sstevel@tonic-gate if ((a->rcv_flagaction & RCTL_LOCAL_DENY) < 691*7c478bd9Sstevel@tonic-gate (b->rcv_flagaction & RCTL_LOCAL_DENY)) 692*7c478bd9Sstevel@tonic-gate return (-1); 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate if ((a->rcv_flagaction & RCTL_LOCAL_DENY) > 695*7c478bd9Sstevel@tonic-gate (b->rcv_flagaction & RCTL_LOCAL_DENY)) 696*7c478bd9Sstevel@tonic-gate return (1); 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate if (a->rcv_privilege < b->rcv_privilege) 699*7c478bd9Sstevel@tonic-gate return (-1); 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate if (a->rcv_privilege > b->rcv_privilege) 702*7c478bd9Sstevel@tonic-gate return (1); 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate if (imprecise) 705*7c478bd9Sstevel@tonic-gate return (0); 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate if (a->rcv_action_recip_pid < b->rcv_action_recip_pid) 708*7c478bd9Sstevel@tonic-gate return (-1); 709*7c478bd9Sstevel@tonic-gate 710*7c478bd9Sstevel@tonic-gate if (a->rcv_action_recip_pid > b->rcv_action_recip_pid) 711*7c478bd9Sstevel@tonic-gate return (1); 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate return (0); 714*7c478bd9Sstevel@tonic-gate } 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate static rctl_val_t * 717*7c478bd9Sstevel@tonic-gate rctl_val_list_find(rctl_val_t **head, rctl_val_t *cval) 718*7c478bd9Sstevel@tonic-gate { 719*7c478bd9Sstevel@tonic-gate rctl_val_t *rval = *head; 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate while (rval != NULL) { 722*7c478bd9Sstevel@tonic-gate if (rctl_val_cmp(cval, rval, 0) == 0) 723*7c478bd9Sstevel@tonic-gate return (rval); 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate rval = rval->rcv_next; 726*7c478bd9Sstevel@tonic-gate } 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate return (NULL); 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate } 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate /* 733*7c478bd9Sstevel@tonic-gate * int rctl_val_list_insert(rctl_val_t **, rctl_val_t *) 734*7c478bd9Sstevel@tonic-gate * 735*7c478bd9Sstevel@tonic-gate * Overview 736*7c478bd9Sstevel@tonic-gate * This function inserts the rctl_val_t into the value list provided. 737*7c478bd9Sstevel@tonic-gate * The insert is always successful unless if the value is a duplicate 738*7c478bd9Sstevel@tonic-gate * of one already in the list. 739*7c478bd9Sstevel@tonic-gate * 740*7c478bd9Sstevel@tonic-gate * Return values 741*7c478bd9Sstevel@tonic-gate * 1 if the value was a duplicate of an existing value in the list. 742*7c478bd9Sstevel@tonic-gate * 0 if the insert was successful. 743*7c478bd9Sstevel@tonic-gate */ 744*7c478bd9Sstevel@tonic-gate int 745*7c478bd9Sstevel@tonic-gate rctl_val_list_insert(rctl_val_t **root, rctl_val_t *rval) 746*7c478bd9Sstevel@tonic-gate { 747*7c478bd9Sstevel@tonic-gate rctl_val_t *prev; 748*7c478bd9Sstevel@tonic-gate int equiv; 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate rval->rcv_next = NULL; 751*7c478bd9Sstevel@tonic-gate rval->rcv_prev = NULL; 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate if (*root == NULL) { 754*7c478bd9Sstevel@tonic-gate *root = rval; 755*7c478bd9Sstevel@tonic-gate return (0); 756*7c478bd9Sstevel@tonic-gate } 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate equiv = rctl_val_cmp(rval, *root, 0); 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate if (equiv == 0) 761*7c478bd9Sstevel@tonic-gate return (1); 762*7c478bd9Sstevel@tonic-gate 763*7c478bd9Sstevel@tonic-gate if (equiv < 0) { 764*7c478bd9Sstevel@tonic-gate rval->rcv_next = *root; 765*7c478bd9Sstevel@tonic-gate rval->rcv_next->rcv_prev = rval; 766*7c478bd9Sstevel@tonic-gate *root = rval; 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate return (0); 769*7c478bd9Sstevel@tonic-gate } 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate prev = *root; 772*7c478bd9Sstevel@tonic-gate while (prev->rcv_next != NULL && 773*7c478bd9Sstevel@tonic-gate (equiv = rctl_val_cmp(rval, prev->rcv_next, 0)) > 0) { 774*7c478bd9Sstevel@tonic-gate prev = prev->rcv_next; 775*7c478bd9Sstevel@tonic-gate } 776*7c478bd9Sstevel@tonic-gate 777*7c478bd9Sstevel@tonic-gate if (equiv == 0) 778*7c478bd9Sstevel@tonic-gate return (1); 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate rval->rcv_next = prev->rcv_next; 781*7c478bd9Sstevel@tonic-gate if (rval->rcv_next != NULL) 782*7c478bd9Sstevel@tonic-gate rval->rcv_next->rcv_prev = rval; 783*7c478bd9Sstevel@tonic-gate prev->rcv_next = rval; 784*7c478bd9Sstevel@tonic-gate rval->rcv_prev = prev; 785*7c478bd9Sstevel@tonic-gate 786*7c478bd9Sstevel@tonic-gate return (0); 787*7c478bd9Sstevel@tonic-gate } 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate static int 790*7c478bd9Sstevel@tonic-gate rctl_val_list_delete(rctl_val_t **root, rctl_val_t *rval) 791*7c478bd9Sstevel@tonic-gate { 792*7c478bd9Sstevel@tonic-gate rctl_val_t *prev; 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate if (*root == NULL) 795*7c478bd9Sstevel@tonic-gate return (-1); 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate prev = *root; 798*7c478bd9Sstevel@tonic-gate if (rctl_val_cmp(rval, prev, 0) == 0) { 799*7c478bd9Sstevel@tonic-gate *root = prev->rcv_next; 800*7c478bd9Sstevel@tonic-gate (*root)->rcv_prev = NULL; 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, prev); 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate return (0); 805*7c478bd9Sstevel@tonic-gate } 806*7c478bd9Sstevel@tonic-gate 807*7c478bd9Sstevel@tonic-gate while (prev->rcv_next != NULL && 808*7c478bd9Sstevel@tonic-gate rctl_val_cmp(rval, prev->rcv_next, 0) != 0) { 809*7c478bd9Sstevel@tonic-gate prev = prev->rcv_next; 810*7c478bd9Sstevel@tonic-gate } 811*7c478bd9Sstevel@tonic-gate 812*7c478bd9Sstevel@tonic-gate if (prev->rcv_next == NULL) { 813*7c478bd9Sstevel@tonic-gate /* 814*7c478bd9Sstevel@tonic-gate * If we navigate the entire list and cannot find a match, then 815*7c478bd9Sstevel@tonic-gate * return failure. 816*7c478bd9Sstevel@tonic-gate */ 817*7c478bd9Sstevel@tonic-gate return (-1); 818*7c478bd9Sstevel@tonic-gate } 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate prev = prev->rcv_next; 821*7c478bd9Sstevel@tonic-gate prev->rcv_prev->rcv_next = prev->rcv_next; 822*7c478bd9Sstevel@tonic-gate if (prev->rcv_next != NULL) 823*7c478bd9Sstevel@tonic-gate prev->rcv_next->rcv_prev = prev->rcv_prev; 824*7c478bd9Sstevel@tonic-gate 825*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, prev); 826*7c478bd9Sstevel@tonic-gate 827*7c478bd9Sstevel@tonic-gate return (0); 828*7c478bd9Sstevel@tonic-gate } 829*7c478bd9Sstevel@tonic-gate 830*7c478bd9Sstevel@tonic-gate static rctl_val_t * 831*7c478bd9Sstevel@tonic-gate rctl_val_list_dup(rctl_val_t *rval, rctl_alloc_gp_t *ragp, struct proc *oldp, 832*7c478bd9Sstevel@tonic-gate struct proc *newp) 833*7c478bd9Sstevel@tonic-gate { 834*7c478bd9Sstevel@tonic-gate rctl_val_t *head = NULL; 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate for (; rval != NULL; rval = rval->rcv_next) { 837*7c478bd9Sstevel@tonic-gate rctl_val_t *dval = rctl_gp_detach_val(ragp); 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate bcopy(rval, dval, sizeof (rctl_val_t)); 840*7c478bd9Sstevel@tonic-gate dval->rcv_prev = dval->rcv_next = NULL; 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate if (oldp == NULL || 843*7c478bd9Sstevel@tonic-gate rval->rcv_action_recipient == NULL || 844*7c478bd9Sstevel@tonic-gate rval->rcv_action_recipient == oldp) { 845*7c478bd9Sstevel@tonic-gate if (rval->rcv_privilege == RCPRIV_BASIC) { 846*7c478bd9Sstevel@tonic-gate dval->rcv_action_recipient = newp; 847*7c478bd9Sstevel@tonic-gate dval->rcv_action_recip_pid = newp->p_pid; 848*7c478bd9Sstevel@tonic-gate } else { 849*7c478bd9Sstevel@tonic-gate dval->rcv_action_recipient = NULL; 850*7c478bd9Sstevel@tonic-gate dval->rcv_action_recip_pid = -1; 851*7c478bd9Sstevel@tonic-gate } 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate (void) rctl_val_list_insert(&head, dval); 854*7c478bd9Sstevel@tonic-gate } else { 855*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, dval); 856*7c478bd9Sstevel@tonic-gate } 857*7c478bd9Sstevel@tonic-gate } 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate return (head); 860*7c478bd9Sstevel@tonic-gate } 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate static void 863*7c478bd9Sstevel@tonic-gate rctl_val_list_reset(rctl_val_t *rval) 864*7c478bd9Sstevel@tonic-gate { 865*7c478bd9Sstevel@tonic-gate for (; rval != NULL; rval = rval->rcv_next) 866*7c478bd9Sstevel@tonic-gate rval->rcv_firing_time = 0; 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate 869*7c478bd9Sstevel@tonic-gate static uint_t 870*7c478bd9Sstevel@tonic-gate rctl_val_list_count(rctl_val_t *rval) 871*7c478bd9Sstevel@tonic-gate { 872*7c478bd9Sstevel@tonic-gate uint_t n = 0; 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate for (; rval != NULL; rval = rval->rcv_next) 875*7c478bd9Sstevel@tonic-gate n++; 876*7c478bd9Sstevel@tonic-gate 877*7c478bd9Sstevel@tonic-gate return (n); 878*7c478bd9Sstevel@tonic-gate } 879*7c478bd9Sstevel@tonic-gate 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate static void 882*7c478bd9Sstevel@tonic-gate rctl_val_list_free(rctl_val_t *rval) 883*7c478bd9Sstevel@tonic-gate { 884*7c478bd9Sstevel@tonic-gate while (rval != NULL) { 885*7c478bd9Sstevel@tonic-gate rctl_val_t *next = rval->rcv_next; 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_val_cache, rval); 888*7c478bd9Sstevel@tonic-gate 889*7c478bd9Sstevel@tonic-gate rval = next; 890*7c478bd9Sstevel@tonic-gate } 891*7c478bd9Sstevel@tonic-gate } 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate /* 894*7c478bd9Sstevel@tonic-gate * rctl_qty_t rctl_model_maximum(rctl_dict_entry_t *, struct proc *) 895*7c478bd9Sstevel@tonic-gate * 896*7c478bd9Sstevel@tonic-gate * Overview 897*7c478bd9Sstevel@tonic-gate * In cases where the operating system supports more than one process 898*7c478bd9Sstevel@tonic-gate * addressing model, the operating system capabilities will exceed those of 899*7c478bd9Sstevel@tonic-gate * one or more of these models. Processes in a less capable model must have 900*7c478bd9Sstevel@tonic-gate * their resources accurately controlled, without diluting those of their 901*7c478bd9Sstevel@tonic-gate * descendants reached via exec(). rctl_model_maximum() returns the governing 902*7c478bd9Sstevel@tonic-gate * value for the specified process with respect to a resource control, such 903*7c478bd9Sstevel@tonic-gate * that the value can used for the RCTLOP_SET callback or compatability 904*7c478bd9Sstevel@tonic-gate * support. 905*7c478bd9Sstevel@tonic-gate * 906*7c478bd9Sstevel@tonic-gate * Return values 907*7c478bd9Sstevel@tonic-gate * The maximum value for the given process for the specified resource control. 908*7c478bd9Sstevel@tonic-gate * 909*7c478bd9Sstevel@tonic-gate * Caller's context 910*7c478bd9Sstevel@tonic-gate * No restrictions on context. 911*7c478bd9Sstevel@tonic-gate */ 912*7c478bd9Sstevel@tonic-gate rctl_qty_t 913*7c478bd9Sstevel@tonic-gate rctl_model_maximum(rctl_dict_entry_t *rde, struct proc *p) 914*7c478bd9Sstevel@tonic-gate { 915*7c478bd9Sstevel@tonic-gate if (p->p_model == DATAMODEL_NATIVE) 916*7c478bd9Sstevel@tonic-gate return (rde->rcd_max_native); 917*7c478bd9Sstevel@tonic-gate 918*7c478bd9Sstevel@tonic-gate return (rde->rcd_max_ilp32); 919*7c478bd9Sstevel@tonic-gate } 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate /* 922*7c478bd9Sstevel@tonic-gate * rctl_qty_t rctl_model_value(rctl_dict_entry_t *, struct proc *, rctl_qty_t) 923*7c478bd9Sstevel@tonic-gate * 924*7c478bd9Sstevel@tonic-gate * Overview 925*7c478bd9Sstevel@tonic-gate * Convenience function wrapping the rctl_model_maximum() functionality. 926*7c478bd9Sstevel@tonic-gate * 927*7c478bd9Sstevel@tonic-gate * Return values 928*7c478bd9Sstevel@tonic-gate * The lesser of the process's maximum value and the given value for the 929*7c478bd9Sstevel@tonic-gate * specified resource control. 930*7c478bd9Sstevel@tonic-gate * 931*7c478bd9Sstevel@tonic-gate * Caller's context 932*7c478bd9Sstevel@tonic-gate * No restrictions on context. 933*7c478bd9Sstevel@tonic-gate */ 934*7c478bd9Sstevel@tonic-gate rctl_qty_t 935*7c478bd9Sstevel@tonic-gate rctl_model_value(rctl_dict_entry_t *rde, struct proc *p, rctl_qty_t value) 936*7c478bd9Sstevel@tonic-gate { 937*7c478bd9Sstevel@tonic-gate rctl_qty_t max = rctl_model_maximum(rde, p); 938*7c478bd9Sstevel@tonic-gate 939*7c478bd9Sstevel@tonic-gate return (value < max ? value : max); 940*7c478bd9Sstevel@tonic-gate } 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate static void 943*7c478bd9Sstevel@tonic-gate rctl_set_insert(rctl_set_t *set, rctl_hndl_t hndl, rctl_t *rctl) 944*7c478bd9Sstevel@tonic-gate { 945*7c478bd9Sstevel@tonic-gate uint_t index = hndl % rctl_set_size; 946*7c478bd9Sstevel@tonic-gate rctl_t *next_ctl, *prev_ctl; 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&set->rcs_lock)); 949*7c478bd9Sstevel@tonic-gate 950*7c478bd9Sstevel@tonic-gate rctl->rc_next = NULL; 951*7c478bd9Sstevel@tonic-gate 952*7c478bd9Sstevel@tonic-gate if (set->rcs_ctls[index] == NULL) { 953*7c478bd9Sstevel@tonic-gate set->rcs_ctls[index] = rctl; 954*7c478bd9Sstevel@tonic-gate return; 955*7c478bd9Sstevel@tonic-gate } 956*7c478bd9Sstevel@tonic-gate 957*7c478bd9Sstevel@tonic-gate if (hndl < set->rcs_ctls[index]->rc_id) { 958*7c478bd9Sstevel@tonic-gate rctl->rc_next = set->rcs_ctls[index]; 959*7c478bd9Sstevel@tonic-gate set->rcs_ctls[index] = rctl; 960*7c478bd9Sstevel@tonic-gate 961*7c478bd9Sstevel@tonic-gate return; 962*7c478bd9Sstevel@tonic-gate } 963*7c478bd9Sstevel@tonic-gate 964*7c478bd9Sstevel@tonic-gate for (next_ctl = set->rcs_ctls[index]->rc_next, 965*7c478bd9Sstevel@tonic-gate prev_ctl = set->rcs_ctls[index]; 966*7c478bd9Sstevel@tonic-gate next_ctl != NULL; 967*7c478bd9Sstevel@tonic-gate prev_ctl = next_ctl, 968*7c478bd9Sstevel@tonic-gate next_ctl = next_ctl->rc_next) { 969*7c478bd9Sstevel@tonic-gate if (next_ctl->rc_id > hndl) { 970*7c478bd9Sstevel@tonic-gate rctl->rc_next = next_ctl; 971*7c478bd9Sstevel@tonic-gate prev_ctl->rc_next = rctl; 972*7c478bd9Sstevel@tonic-gate 973*7c478bd9Sstevel@tonic-gate return; 974*7c478bd9Sstevel@tonic-gate } 975*7c478bd9Sstevel@tonic-gate } 976*7c478bd9Sstevel@tonic-gate 977*7c478bd9Sstevel@tonic-gate rctl->rc_next = next_ctl; 978*7c478bd9Sstevel@tonic-gate prev_ctl->rc_next = rctl; 979*7c478bd9Sstevel@tonic-gate } 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate /* 982*7c478bd9Sstevel@tonic-gate * rctl_set_t *rctl_set_create() 983*7c478bd9Sstevel@tonic-gate * 984*7c478bd9Sstevel@tonic-gate * Overview 985*7c478bd9Sstevel@tonic-gate * Create an empty resource control set, suitable for attaching to a 986*7c478bd9Sstevel@tonic-gate * controlled entity. 987*7c478bd9Sstevel@tonic-gate * 988*7c478bd9Sstevel@tonic-gate * Return values 989*7c478bd9Sstevel@tonic-gate * A pointer to the newly created set. 990*7c478bd9Sstevel@tonic-gate * 991*7c478bd9Sstevel@tonic-gate * Caller's context 992*7c478bd9Sstevel@tonic-gate * Safe for KM_SLEEP allocations. 993*7c478bd9Sstevel@tonic-gate */ 994*7c478bd9Sstevel@tonic-gate rctl_set_t * 995*7c478bd9Sstevel@tonic-gate rctl_set_create() 996*7c478bd9Sstevel@tonic-gate { 997*7c478bd9Sstevel@tonic-gate rctl_set_t *rset = kmem_zalloc(sizeof (rctl_set_t), KM_SLEEP); 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate mutex_init(&rset->rcs_lock, NULL, MUTEX_DEFAULT, NULL); 1000*7c478bd9Sstevel@tonic-gate rset->rcs_ctls = kmem_zalloc(rctl_set_size * sizeof (rctl_t *), 1001*7c478bd9Sstevel@tonic-gate KM_SLEEP); 1002*7c478bd9Sstevel@tonic-gate rset->rcs_entity = -1; 1003*7c478bd9Sstevel@tonic-gate 1004*7c478bd9Sstevel@tonic-gate return (rset); 1005*7c478bd9Sstevel@tonic-gate } 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate /* 1008*7c478bd9Sstevel@tonic-gate * rctl_gp_alloc_t *rctl_set_init_prealloc(rctl_entity_t) 1009*7c478bd9Sstevel@tonic-gate * 1010*7c478bd9Sstevel@tonic-gate * Overview 1011*7c478bd9Sstevel@tonic-gate * rctl_set_init_prealloc() examines the globally defined resource controls 1012*7c478bd9Sstevel@tonic-gate * and their default values and returns a resource control allocation group 1013*7c478bd9Sstevel@tonic-gate * populated with sufficient controls and values to form a representative 1014*7c478bd9Sstevel@tonic-gate * resource control set for the specified entity. 1015*7c478bd9Sstevel@tonic-gate * 1016*7c478bd9Sstevel@tonic-gate * Return values 1017*7c478bd9Sstevel@tonic-gate * A pointer to the newly created allocation group. 1018*7c478bd9Sstevel@tonic-gate * 1019*7c478bd9Sstevel@tonic-gate * Caller's context 1020*7c478bd9Sstevel@tonic-gate * Caller must be in a context suitable for KM_SLEEP allocations. 1021*7c478bd9Sstevel@tonic-gate */ 1022*7c478bd9Sstevel@tonic-gate rctl_alloc_gp_t * 1023*7c478bd9Sstevel@tonic-gate rctl_set_init_prealloc(rctl_entity_t entity) 1024*7c478bd9Sstevel@tonic-gate { 1025*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde; 1026*7c478bd9Sstevel@tonic-gate rctl_alloc_gp_t *ragp = kmem_zalloc(sizeof (rctl_alloc_gp_t), KM_SLEEP); 1027*7c478bd9Sstevel@tonic-gate 1028*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&curproc->p_lock)); 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate if (rctl_lists[entity] == NULL) 1031*7c478bd9Sstevel@tonic-gate return (ragp); 1032*7c478bd9Sstevel@tonic-gate 1033*7c478bd9Sstevel@tonic-gate mutex_enter(&rctl_lists_lock); 1034*7c478bd9Sstevel@tonic-gate 1035*7c478bd9Sstevel@tonic-gate for (rde = rctl_lists[entity]; rde != NULL; rde = rde->rcd_next) { 1036*7c478bd9Sstevel@tonic-gate ragp->rcag_nctls++; 1037*7c478bd9Sstevel@tonic-gate ragp->rcag_nvals += rctl_val_list_count(rde->rcd_default_value); 1038*7c478bd9Sstevel@tonic-gate } 1039*7c478bd9Sstevel@tonic-gate 1040*7c478bd9Sstevel@tonic-gate mutex_exit(&rctl_lists_lock); 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate rctl_gp_alloc(ragp); 1043*7c478bd9Sstevel@tonic-gate 1044*7c478bd9Sstevel@tonic-gate return (ragp); 1045*7c478bd9Sstevel@tonic-gate } 1046*7c478bd9Sstevel@tonic-gate 1047*7c478bd9Sstevel@tonic-gate /* 1048*7c478bd9Sstevel@tonic-gate * rctl_set_t *rctl_set_init(rctl_entity_t) 1049*7c478bd9Sstevel@tonic-gate * 1050*7c478bd9Sstevel@tonic-gate * Overview 1051*7c478bd9Sstevel@tonic-gate * rctl_set_create() creates a resource control set, initialized with the 1052*7c478bd9Sstevel@tonic-gate * system infinite values on all registered controls, for attachment to a 1053*7c478bd9Sstevel@tonic-gate * system entity requiring resource controls, such as a process or a task. 1054*7c478bd9Sstevel@tonic-gate * 1055*7c478bd9Sstevel@tonic-gate * Return values 1056*7c478bd9Sstevel@tonic-gate * A pointer to the newly filled set. 1057*7c478bd9Sstevel@tonic-gate * 1058*7c478bd9Sstevel@tonic-gate * Caller's context 1059*7c478bd9Sstevel@tonic-gate * Caller must be holding p_lock on entry so that RCTLOP_SET() functions 1060*7c478bd9Sstevel@tonic-gate * may modify task and project members based on the proc structure 1061*7c478bd9Sstevel@tonic-gate * they are passed. 1062*7c478bd9Sstevel@tonic-gate */ 1063*7c478bd9Sstevel@tonic-gate rctl_set_t * 1064*7c478bd9Sstevel@tonic-gate rctl_set_init(rctl_entity_t entity, struct proc *p, rctl_entity_p_t *e, 1065*7c478bd9Sstevel@tonic-gate rctl_set_t *rset, rctl_alloc_gp_t *ragp) 1066*7c478bd9Sstevel@tonic-gate { 1067*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde; 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 1070*7c478bd9Sstevel@tonic-gate ASSERT(e); 1071*7c478bd9Sstevel@tonic-gate rset->rcs_entity = entity; 1072*7c478bd9Sstevel@tonic-gate 1073*7c478bd9Sstevel@tonic-gate if (rctl_lists[entity] == NULL) 1074*7c478bd9Sstevel@tonic-gate return (rset); 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate mutex_enter(&rctl_lists_lock); 1077*7c478bd9Sstevel@tonic-gate mutex_enter(&rset->rcs_lock); 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate for (rde = rctl_lists[entity]; rde != NULL; rde = rde->rcd_next) { 1080*7c478bd9Sstevel@tonic-gate rctl_t *rctl = rctl_gp_detach_ctl(ragp); 1081*7c478bd9Sstevel@tonic-gate 1082*7c478bd9Sstevel@tonic-gate rctl->rc_dict_entry = rde; 1083*7c478bd9Sstevel@tonic-gate rctl->rc_id = rde->rcd_id; 1084*7c478bd9Sstevel@tonic-gate 1085*7c478bd9Sstevel@tonic-gate rctl->rc_values = rctl_val_list_dup(rde->rcd_default_value, 1086*7c478bd9Sstevel@tonic-gate ragp, NULL, p); 1087*7c478bd9Sstevel@tonic-gate rctl->rc_cursor = rctl->rc_values; 1088*7c478bd9Sstevel@tonic-gate 1089*7c478bd9Sstevel@tonic-gate ASSERT(rctl->rc_cursor != NULL); 1090*7c478bd9Sstevel@tonic-gate 1091*7c478bd9Sstevel@tonic-gate rctl_set_insert(rset, rde->rcd_id, rctl); 1092*7c478bd9Sstevel@tonic-gate 1093*7c478bd9Sstevel@tonic-gate RCTLOP_SET(rctl, p, e, rctl_model_value(rctl->rc_dict_entry, p, 1094*7c478bd9Sstevel@tonic-gate rctl->rc_cursor->rcv_value)); 1095*7c478bd9Sstevel@tonic-gate } 1096*7c478bd9Sstevel@tonic-gate 1097*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 1098*7c478bd9Sstevel@tonic-gate mutex_exit(&rctl_lists_lock); 1099*7c478bd9Sstevel@tonic-gate 1100*7c478bd9Sstevel@tonic-gate return (rset); 1101*7c478bd9Sstevel@tonic-gate } 1102*7c478bd9Sstevel@tonic-gate 1103*7c478bd9Sstevel@tonic-gate static rctl_t * 1104*7c478bd9Sstevel@tonic-gate rctl_dup(rctl_t *rctl, rctl_alloc_gp_t *ragp, struct proc *oldp, 1105*7c478bd9Sstevel@tonic-gate struct proc *newp) 1106*7c478bd9Sstevel@tonic-gate { 1107*7c478bd9Sstevel@tonic-gate rctl_t *dup = rctl_gp_detach_ctl(ragp); 1108*7c478bd9Sstevel@tonic-gate rctl_val_t *dval; 1109*7c478bd9Sstevel@tonic-gate 1110*7c478bd9Sstevel@tonic-gate dup->rc_id = rctl->rc_id; 1111*7c478bd9Sstevel@tonic-gate dup->rc_dict_entry = rctl->rc_dict_entry; 1112*7c478bd9Sstevel@tonic-gate dup->rc_next = NULL; 1113*7c478bd9Sstevel@tonic-gate dup->rc_cursor = NULL; 1114*7c478bd9Sstevel@tonic-gate dup->rc_values = rctl_val_list_dup(rctl->rc_values, ragp, oldp, newp); 1115*7c478bd9Sstevel@tonic-gate 1116*7c478bd9Sstevel@tonic-gate for (dval = dup->rc_values; 1117*7c478bd9Sstevel@tonic-gate dval != NULL; dval = dval->rcv_next) { 1118*7c478bd9Sstevel@tonic-gate if (rctl_val_cmp(rctl->rc_cursor, dval, 0) >= 0) { 1119*7c478bd9Sstevel@tonic-gate dup->rc_cursor = dval; 1120*7c478bd9Sstevel@tonic-gate break; 1121*7c478bd9Sstevel@tonic-gate } 1122*7c478bd9Sstevel@tonic-gate } 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate if (dup->rc_cursor == NULL) 1125*7c478bd9Sstevel@tonic-gate dup->rc_cursor = dup->rc_values; 1126*7c478bd9Sstevel@tonic-gate 1127*7c478bd9Sstevel@tonic-gate return (dup); 1128*7c478bd9Sstevel@tonic-gate } 1129*7c478bd9Sstevel@tonic-gate 1130*7c478bd9Sstevel@tonic-gate static void 1131*7c478bd9Sstevel@tonic-gate rctl_set_fill_alloc_gp(rctl_set_t *set, rctl_alloc_gp_t *ragp) 1132*7c478bd9Sstevel@tonic-gate { 1133*7c478bd9Sstevel@tonic-gate uint_t i; 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate bzero(ragp, sizeof (rctl_alloc_gp_t)); 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate for (i = 0; i < rctl_set_size; i++) { 1138*7c478bd9Sstevel@tonic-gate rctl_t *r = set->rcs_ctls[i]; 1139*7c478bd9Sstevel@tonic-gate 1140*7c478bd9Sstevel@tonic-gate while (r != NULL) { 1141*7c478bd9Sstevel@tonic-gate ragp->rcag_nctls++; 1142*7c478bd9Sstevel@tonic-gate 1143*7c478bd9Sstevel@tonic-gate ragp->rcag_nvals += rctl_val_list_count(r->rc_values); 1144*7c478bd9Sstevel@tonic-gate 1145*7c478bd9Sstevel@tonic-gate r = r->rc_next; 1146*7c478bd9Sstevel@tonic-gate } 1147*7c478bd9Sstevel@tonic-gate } 1148*7c478bd9Sstevel@tonic-gate } 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate /* 1151*7c478bd9Sstevel@tonic-gate * rctl_alloc_gp_t *rctl_set_dup_prealloc(rctl_set_t *) 1152*7c478bd9Sstevel@tonic-gate * 1153*7c478bd9Sstevel@tonic-gate * Overview 1154*7c478bd9Sstevel@tonic-gate * Given a resource control set, allocate a sufficiently large allocation 1155*7c478bd9Sstevel@tonic-gate * group to contain a duplicate of the set. 1156*7c478bd9Sstevel@tonic-gate * 1157*7c478bd9Sstevel@tonic-gate * Return value 1158*7c478bd9Sstevel@tonic-gate * A pointer to the newly created allocation group. 1159*7c478bd9Sstevel@tonic-gate * 1160*7c478bd9Sstevel@tonic-gate * Caller's context 1161*7c478bd9Sstevel@tonic-gate * Safe for KM_SLEEP allocations. 1162*7c478bd9Sstevel@tonic-gate */ 1163*7c478bd9Sstevel@tonic-gate rctl_alloc_gp_t * 1164*7c478bd9Sstevel@tonic-gate rctl_set_dup_prealloc(rctl_set_t *set) 1165*7c478bd9Sstevel@tonic-gate { 1166*7c478bd9Sstevel@tonic-gate rctl_alloc_gp_t *ragp = kmem_zalloc(sizeof (rctl_alloc_gp_t), KM_SLEEP); 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&curproc->p_lock)); 1169*7c478bd9Sstevel@tonic-gate 1170*7c478bd9Sstevel@tonic-gate mutex_enter(&set->rcs_lock); 1171*7c478bd9Sstevel@tonic-gate rctl_set_fill_alloc_gp(set, ragp); 1172*7c478bd9Sstevel@tonic-gate mutex_exit(&set->rcs_lock); 1173*7c478bd9Sstevel@tonic-gate 1174*7c478bd9Sstevel@tonic-gate rctl_gp_alloc(ragp); 1175*7c478bd9Sstevel@tonic-gate 1176*7c478bd9Sstevel@tonic-gate return (ragp); 1177*7c478bd9Sstevel@tonic-gate } 1178*7c478bd9Sstevel@tonic-gate 1179*7c478bd9Sstevel@tonic-gate /* 1180*7c478bd9Sstevel@tonic-gate * int rctl_set_dup_ready(rctl_set_t *, rctl_alloc_gp_t *) 1181*7c478bd9Sstevel@tonic-gate * 1182*7c478bd9Sstevel@tonic-gate * Overview 1183*7c478bd9Sstevel@tonic-gate * Verify that the allocation group provided is large enough to allow a 1184*7c478bd9Sstevel@tonic-gate * duplicate of the given resource control set to be constructed from its 1185*7c478bd9Sstevel@tonic-gate * contents. 1186*7c478bd9Sstevel@tonic-gate * 1187*7c478bd9Sstevel@tonic-gate * Return values 1188*7c478bd9Sstevel@tonic-gate * 1 if the allocation group is sufficiently large, 0 otherwise. 1189*7c478bd9Sstevel@tonic-gate * 1190*7c478bd9Sstevel@tonic-gate * Caller's context 1191*7c478bd9Sstevel@tonic-gate * rcs_lock must be held prior to entry. 1192*7c478bd9Sstevel@tonic-gate */ 1193*7c478bd9Sstevel@tonic-gate int 1194*7c478bd9Sstevel@tonic-gate rctl_set_dup_ready(rctl_set_t *set, rctl_alloc_gp_t *ragp) 1195*7c478bd9Sstevel@tonic-gate { 1196*7c478bd9Sstevel@tonic-gate rctl_alloc_gp_t curr_gp; 1197*7c478bd9Sstevel@tonic-gate 1198*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&set->rcs_lock)); 1199*7c478bd9Sstevel@tonic-gate 1200*7c478bd9Sstevel@tonic-gate rctl_set_fill_alloc_gp(set, &curr_gp); 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate if (curr_gp.rcag_nctls <= ragp->rcag_nctls && 1203*7c478bd9Sstevel@tonic-gate curr_gp.rcag_nvals <= ragp->rcag_nvals) 1204*7c478bd9Sstevel@tonic-gate return (1); 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate return (0); 1207*7c478bd9Sstevel@tonic-gate } 1208*7c478bd9Sstevel@tonic-gate 1209*7c478bd9Sstevel@tonic-gate /* 1210*7c478bd9Sstevel@tonic-gate * rctl_set_t *rctl_set_dup(rctl_set_t *, struct proc *, struct proc *, 1211*7c478bd9Sstevel@tonic-gate * rctl_set_t *, rctl_alloc_gp_t *, int) 1212*7c478bd9Sstevel@tonic-gate * 1213*7c478bd9Sstevel@tonic-gate * Overview 1214*7c478bd9Sstevel@tonic-gate * Make a duplicate of the resource control set. The proc pointers are those 1215*7c478bd9Sstevel@tonic-gate * of the owning process and of the process associated with the entity 1216*7c478bd9Sstevel@tonic-gate * receiving the duplicate. 1217*7c478bd9Sstevel@tonic-gate * 1218*7c478bd9Sstevel@tonic-gate * Duplication is a 3 stage process. Stage 1 is memory allocation for 1219*7c478bd9Sstevel@tonic-gate * the duplicate set, which is taken care of by rctl_set_dup_prealloc(). 1220*7c478bd9Sstevel@tonic-gate * Stage 2 consists of copying all rctls and values from the old set into 1221*7c478bd9Sstevel@tonic-gate * the new. Stage 3 completes the duplication by performing the appropriate 1222*7c478bd9Sstevel@tonic-gate * callbacks for each rctl in the new set. 1223*7c478bd9Sstevel@tonic-gate * 1224*7c478bd9Sstevel@tonic-gate * Stages 2 and 3 are handled by calling rctl_set_dup with the RCD_DUP and 1225*7c478bd9Sstevel@tonic-gate * RCD_CALLBACK functions, respectively. The RCD_CALLBACK flag may only 1226*7c478bd9Sstevel@tonic-gate * be supplied if the newp proc structure reflects the new task and 1227*7c478bd9Sstevel@tonic-gate * project linkage. 1228*7c478bd9Sstevel@tonic-gate * 1229*7c478bd9Sstevel@tonic-gate * Return value 1230*7c478bd9Sstevel@tonic-gate * A pointer to the duplicate set. 1231*7c478bd9Sstevel@tonic-gate * 1232*7c478bd9Sstevel@tonic-gate * Caller's context 1233*7c478bd9Sstevel@tonic-gate * The rcs_lock of the set to be duplicated must be held prior to entry. 1234*7c478bd9Sstevel@tonic-gate */ 1235*7c478bd9Sstevel@tonic-gate rctl_set_t * 1236*7c478bd9Sstevel@tonic-gate rctl_set_dup(rctl_set_t *set, struct proc *oldp, struct proc *newp, 1237*7c478bd9Sstevel@tonic-gate rctl_entity_p_t *e, rctl_set_t *dup, rctl_alloc_gp_t *ragp, int flag) 1238*7c478bd9Sstevel@tonic-gate { 1239*7c478bd9Sstevel@tonic-gate uint_t i; 1240*7c478bd9Sstevel@tonic-gate rctl_set_t *iter; 1241*7c478bd9Sstevel@tonic-gate 1242*7c478bd9Sstevel@tonic-gate ASSERT((flag & RCD_DUP) || (flag & RCD_CALLBACK)); 1243*7c478bd9Sstevel@tonic-gate ASSERT(e); 1244*7c478bd9Sstevel@tonic-gate /* 1245*7c478bd9Sstevel@tonic-gate * When copying the old set, iterate over that. Otherwise, when 1246*7c478bd9Sstevel@tonic-gate * only callbacks have been requested, iterate over the dup set. 1247*7c478bd9Sstevel@tonic-gate */ 1248*7c478bd9Sstevel@tonic-gate if (flag & RCD_DUP) { 1249*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&set->rcs_lock)); 1250*7c478bd9Sstevel@tonic-gate iter = set; 1251*7c478bd9Sstevel@tonic-gate dup->rcs_entity = set->rcs_entity; 1252*7c478bd9Sstevel@tonic-gate } else { 1253*7c478bd9Sstevel@tonic-gate iter = dup; 1254*7c478bd9Sstevel@tonic-gate } 1255*7c478bd9Sstevel@tonic-gate 1256*7c478bd9Sstevel@tonic-gate mutex_enter(&dup->rcs_lock); 1257*7c478bd9Sstevel@tonic-gate 1258*7c478bd9Sstevel@tonic-gate for (i = 0; i < rctl_set_size; i++) { 1259*7c478bd9Sstevel@tonic-gate rctl_t *r = iter->rcs_ctls[i]; 1260*7c478bd9Sstevel@tonic-gate rctl_t *d; 1261*7c478bd9Sstevel@tonic-gate 1262*7c478bd9Sstevel@tonic-gate while (r != NULL) { 1263*7c478bd9Sstevel@tonic-gate if (flag & RCD_DUP) { 1264*7c478bd9Sstevel@tonic-gate d = rctl_dup(r, ragp, oldp, newp); 1265*7c478bd9Sstevel@tonic-gate rctl_set_insert(dup, r->rc_id, d); 1266*7c478bd9Sstevel@tonic-gate } else { 1267*7c478bd9Sstevel@tonic-gate d = r; 1268*7c478bd9Sstevel@tonic-gate } 1269*7c478bd9Sstevel@tonic-gate 1270*7c478bd9Sstevel@tonic-gate if (flag & RCD_CALLBACK) 1271*7c478bd9Sstevel@tonic-gate RCTLOP_SET(d, newp, e, 1272*7c478bd9Sstevel@tonic-gate rctl_model_value(d->rc_dict_entry, newp, 1273*7c478bd9Sstevel@tonic-gate d->rc_cursor->rcv_value)); 1274*7c478bd9Sstevel@tonic-gate 1275*7c478bd9Sstevel@tonic-gate r = r->rc_next; 1276*7c478bd9Sstevel@tonic-gate } 1277*7c478bd9Sstevel@tonic-gate } 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate mutex_exit(&dup->rcs_lock); 1280*7c478bd9Sstevel@tonic-gate 1281*7c478bd9Sstevel@tonic-gate return (dup); 1282*7c478bd9Sstevel@tonic-gate } 1283*7c478bd9Sstevel@tonic-gate 1284*7c478bd9Sstevel@tonic-gate /* 1285*7c478bd9Sstevel@tonic-gate * void rctl_set_free(rctl_set_t *) 1286*7c478bd9Sstevel@tonic-gate * 1287*7c478bd9Sstevel@tonic-gate * Overview 1288*7c478bd9Sstevel@tonic-gate * Delete resource control set and all attached values. 1289*7c478bd9Sstevel@tonic-gate * 1290*7c478bd9Sstevel@tonic-gate * Return values 1291*7c478bd9Sstevel@tonic-gate * No value returned. 1292*7c478bd9Sstevel@tonic-gate * 1293*7c478bd9Sstevel@tonic-gate * Caller's context 1294*7c478bd9Sstevel@tonic-gate * No restrictions on context. 1295*7c478bd9Sstevel@tonic-gate */ 1296*7c478bd9Sstevel@tonic-gate void 1297*7c478bd9Sstevel@tonic-gate rctl_set_free(rctl_set_t *set) 1298*7c478bd9Sstevel@tonic-gate { 1299*7c478bd9Sstevel@tonic-gate uint_t i; 1300*7c478bd9Sstevel@tonic-gate 1301*7c478bd9Sstevel@tonic-gate mutex_enter(&set->rcs_lock); 1302*7c478bd9Sstevel@tonic-gate for (i = 0; i < rctl_set_size; i++) { 1303*7c478bd9Sstevel@tonic-gate rctl_t *r = set->rcs_ctls[i]; 1304*7c478bd9Sstevel@tonic-gate 1305*7c478bd9Sstevel@tonic-gate while (r != NULL) { 1306*7c478bd9Sstevel@tonic-gate rctl_val_t *v = r->rc_values; 1307*7c478bd9Sstevel@tonic-gate rctl_t *n = r->rc_next; 1308*7c478bd9Sstevel@tonic-gate 1309*7c478bd9Sstevel@tonic-gate kmem_cache_free(rctl_cache, r); 1310*7c478bd9Sstevel@tonic-gate 1311*7c478bd9Sstevel@tonic-gate rctl_val_list_free(v); 1312*7c478bd9Sstevel@tonic-gate 1313*7c478bd9Sstevel@tonic-gate r = n; 1314*7c478bd9Sstevel@tonic-gate } 1315*7c478bd9Sstevel@tonic-gate } 1316*7c478bd9Sstevel@tonic-gate mutex_exit(&set->rcs_lock); 1317*7c478bd9Sstevel@tonic-gate 1318*7c478bd9Sstevel@tonic-gate kmem_free(set->rcs_ctls, sizeof (rctl_t *) * rctl_set_size); 1319*7c478bd9Sstevel@tonic-gate kmem_free(set, sizeof (rctl_set_t)); 1320*7c478bd9Sstevel@tonic-gate } 1321*7c478bd9Sstevel@tonic-gate 1322*7c478bd9Sstevel@tonic-gate /* 1323*7c478bd9Sstevel@tonic-gate * void rctl_set_reset(rctl_set_t *) 1324*7c478bd9Sstevel@tonic-gate * 1325*7c478bd9Sstevel@tonic-gate * Overview 1326*7c478bd9Sstevel@tonic-gate * Resets all rctls within the set such that the lowest value becomes active. 1327*7c478bd9Sstevel@tonic-gate * 1328*7c478bd9Sstevel@tonic-gate * Return values 1329*7c478bd9Sstevel@tonic-gate * No value returned. 1330*7c478bd9Sstevel@tonic-gate * 1331*7c478bd9Sstevel@tonic-gate * Caller's context 1332*7c478bd9Sstevel@tonic-gate * No restrictions on context. 1333*7c478bd9Sstevel@tonic-gate */ 1334*7c478bd9Sstevel@tonic-gate void 1335*7c478bd9Sstevel@tonic-gate rctl_set_reset(rctl_set_t *set, struct proc *p, rctl_entity_p_t *e) 1336*7c478bd9Sstevel@tonic-gate { 1337*7c478bd9Sstevel@tonic-gate uint_t i; 1338*7c478bd9Sstevel@tonic-gate 1339*7c478bd9Sstevel@tonic-gate ASSERT(e); 1340*7c478bd9Sstevel@tonic-gate 1341*7c478bd9Sstevel@tonic-gate mutex_enter(&set->rcs_lock); 1342*7c478bd9Sstevel@tonic-gate for (i = 0; i < rctl_set_size; i++) { 1343*7c478bd9Sstevel@tonic-gate rctl_t *r = set->rcs_ctls[i]; 1344*7c478bd9Sstevel@tonic-gate 1345*7c478bd9Sstevel@tonic-gate while (r != NULL) { 1346*7c478bd9Sstevel@tonic-gate r->rc_cursor = r->rc_values; 1347*7c478bd9Sstevel@tonic-gate rctl_val_list_reset(r->rc_cursor); 1348*7c478bd9Sstevel@tonic-gate RCTLOP_SET(r, p, e, rctl_model_value(r->rc_dict_entry, 1349*7c478bd9Sstevel@tonic-gate p, r->rc_cursor->rcv_value)); 1350*7c478bd9Sstevel@tonic-gate 1351*7c478bd9Sstevel@tonic-gate ASSERT(r->rc_cursor != NULL); 1352*7c478bd9Sstevel@tonic-gate 1353*7c478bd9Sstevel@tonic-gate r = r->rc_next; 1354*7c478bd9Sstevel@tonic-gate } 1355*7c478bd9Sstevel@tonic-gate } 1356*7c478bd9Sstevel@tonic-gate 1357*7c478bd9Sstevel@tonic-gate mutex_exit(&set->rcs_lock); 1358*7c478bd9Sstevel@tonic-gate } 1359*7c478bd9Sstevel@tonic-gate 1360*7c478bd9Sstevel@tonic-gate /* 1361*7c478bd9Sstevel@tonic-gate * void rctl_set_tearoff(rctl_set *, struct proc *) 1362*7c478bd9Sstevel@tonic-gate * 1363*7c478bd9Sstevel@tonic-gate * Overview 1364*7c478bd9Sstevel@tonic-gate * Tear off any resource control values on this set with an action recipient 1365*7c478bd9Sstevel@tonic-gate * equal to the specified process (as they are becoming invalid with the 1366*7c478bd9Sstevel@tonic-gate * process's departure from this set as an observer). 1367*7c478bd9Sstevel@tonic-gate * 1368*7c478bd9Sstevel@tonic-gate * Return values 1369*7c478bd9Sstevel@tonic-gate * No value returned. 1370*7c478bd9Sstevel@tonic-gate * 1371*7c478bd9Sstevel@tonic-gate * Caller's context 1372*7c478bd9Sstevel@tonic-gate * No restrictions on context 1373*7c478bd9Sstevel@tonic-gate */ 1374*7c478bd9Sstevel@tonic-gate void 1375*7c478bd9Sstevel@tonic-gate rctl_set_tearoff(rctl_set_t *set, struct proc *p) 1376*7c478bd9Sstevel@tonic-gate { 1377*7c478bd9Sstevel@tonic-gate uint_t i; 1378*7c478bd9Sstevel@tonic-gate 1379*7c478bd9Sstevel@tonic-gate mutex_enter(&set->rcs_lock); 1380*7c478bd9Sstevel@tonic-gate for (i = 0; i < rctl_set_size; i++) { 1381*7c478bd9Sstevel@tonic-gate rctl_t *r = set->rcs_ctls[i]; 1382*7c478bd9Sstevel@tonic-gate 1383*7c478bd9Sstevel@tonic-gate while (r != NULL) { 1384*7c478bd9Sstevel@tonic-gate rctl_val_t *rval; 1385*7c478bd9Sstevel@tonic-gate 1386*7c478bd9Sstevel@tonic-gate tearoff_rewalk_list: 1387*7c478bd9Sstevel@tonic-gate rval = r->rc_values; 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate while (rval != NULL) { 1390*7c478bd9Sstevel@tonic-gate if (rval->rcv_privilege == RCPRIV_BASIC && 1391*7c478bd9Sstevel@tonic-gate rval->rcv_action_recipient == p) { 1392*7c478bd9Sstevel@tonic-gate if (r->rc_cursor == rval) 1393*7c478bd9Sstevel@tonic-gate r->rc_cursor = rval->rcv_next; 1394*7c478bd9Sstevel@tonic-gate 1395*7c478bd9Sstevel@tonic-gate (void) rctl_val_list_delete( 1396*7c478bd9Sstevel@tonic-gate &r->rc_values, rval); 1397*7c478bd9Sstevel@tonic-gate 1398*7c478bd9Sstevel@tonic-gate goto tearoff_rewalk_list; 1399*7c478bd9Sstevel@tonic-gate } 1400*7c478bd9Sstevel@tonic-gate 1401*7c478bd9Sstevel@tonic-gate rval = rval->rcv_next; 1402*7c478bd9Sstevel@tonic-gate } 1403*7c478bd9Sstevel@tonic-gate 1404*7c478bd9Sstevel@tonic-gate ASSERT(r->rc_cursor != NULL); 1405*7c478bd9Sstevel@tonic-gate 1406*7c478bd9Sstevel@tonic-gate r = r->rc_next; 1407*7c478bd9Sstevel@tonic-gate } 1408*7c478bd9Sstevel@tonic-gate } 1409*7c478bd9Sstevel@tonic-gate 1410*7c478bd9Sstevel@tonic-gate mutex_exit(&set->rcs_lock); 1411*7c478bd9Sstevel@tonic-gate } 1412*7c478bd9Sstevel@tonic-gate 1413*7c478bd9Sstevel@tonic-gate static int 1414*7c478bd9Sstevel@tonic-gate rctl_set_find(rctl_set_t *set, rctl_hndl_t hndl, rctl_t **rctl) 1415*7c478bd9Sstevel@tonic-gate { 1416*7c478bd9Sstevel@tonic-gate uint_t index = hndl % rctl_set_size; 1417*7c478bd9Sstevel@tonic-gate rctl_t *curr_ctl; 1418*7c478bd9Sstevel@tonic-gate 1419*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&set->rcs_lock)); 1420*7c478bd9Sstevel@tonic-gate 1421*7c478bd9Sstevel@tonic-gate for (curr_ctl = set->rcs_ctls[index]; curr_ctl != NULL; 1422*7c478bd9Sstevel@tonic-gate curr_ctl = curr_ctl->rc_next) { 1423*7c478bd9Sstevel@tonic-gate if (curr_ctl->rc_id == hndl) { 1424*7c478bd9Sstevel@tonic-gate *rctl = curr_ctl; 1425*7c478bd9Sstevel@tonic-gate 1426*7c478bd9Sstevel@tonic-gate return (0); 1427*7c478bd9Sstevel@tonic-gate } 1428*7c478bd9Sstevel@tonic-gate } 1429*7c478bd9Sstevel@tonic-gate 1430*7c478bd9Sstevel@tonic-gate return (-1); 1431*7c478bd9Sstevel@tonic-gate } 1432*7c478bd9Sstevel@tonic-gate 1433*7c478bd9Sstevel@tonic-gate /* 1434*7c478bd9Sstevel@tonic-gate * rlim64_t rctl_enforced_value(rctl_hndl_t, rctl_set_t *, struct proc *) 1435*7c478bd9Sstevel@tonic-gate * 1436*7c478bd9Sstevel@tonic-gate * Overview 1437*7c478bd9Sstevel@tonic-gate * Given a process, get the next enforced value on the rctl of the specified 1438*7c478bd9Sstevel@tonic-gate * handle. 1439*7c478bd9Sstevel@tonic-gate * 1440*7c478bd9Sstevel@tonic-gate * Return value 1441*7c478bd9Sstevel@tonic-gate * The enforced value. 1442*7c478bd9Sstevel@tonic-gate * 1443*7c478bd9Sstevel@tonic-gate * Caller's context 1444*7c478bd9Sstevel@tonic-gate * For controls on process collectives, p->p_lock must be held across the 1445*7c478bd9Sstevel@tonic-gate * operation. 1446*7c478bd9Sstevel@tonic-gate */ 1447*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1448*7c478bd9Sstevel@tonic-gate rctl_qty_t 1449*7c478bd9Sstevel@tonic-gate rctl_enforced_value(rctl_hndl_t hndl, rctl_set_t *rset, struct proc *p) 1450*7c478bd9Sstevel@tonic-gate { 1451*7c478bd9Sstevel@tonic-gate rctl_t *rctl; 1452*7c478bd9Sstevel@tonic-gate rlim64_t ret; 1453*7c478bd9Sstevel@tonic-gate 1454*7c478bd9Sstevel@tonic-gate mutex_enter(&rset->rcs_lock); 1455*7c478bd9Sstevel@tonic-gate 1456*7c478bd9Sstevel@tonic-gate if (rctl_set_find(rset, hndl, &rctl) == -1) 1457*7c478bd9Sstevel@tonic-gate panic("unknown resource control handle %d requested", hndl); 1458*7c478bd9Sstevel@tonic-gate else 1459*7c478bd9Sstevel@tonic-gate ret = rctl_model_value(rctl->rc_dict_entry, p, 1460*7c478bd9Sstevel@tonic-gate rctl->rc_cursor->rcv_value); 1461*7c478bd9Sstevel@tonic-gate 1462*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 1463*7c478bd9Sstevel@tonic-gate 1464*7c478bd9Sstevel@tonic-gate return (ret); 1465*7c478bd9Sstevel@tonic-gate } 1466*7c478bd9Sstevel@tonic-gate 1467*7c478bd9Sstevel@tonic-gate /* 1468*7c478bd9Sstevel@tonic-gate * int rctl_global_get(const char *, rctl_dict_entry_t *) 1469*7c478bd9Sstevel@tonic-gate * 1470*7c478bd9Sstevel@tonic-gate * Overview 1471*7c478bd9Sstevel@tonic-gate * Copy a sanitized version of the global rctl for a given resource control 1472*7c478bd9Sstevel@tonic-gate * name. (By sanitization, we mean that the unsafe data pointers have been 1473*7c478bd9Sstevel@tonic-gate * zeroed.) 1474*7c478bd9Sstevel@tonic-gate * 1475*7c478bd9Sstevel@tonic-gate * Return value 1476*7c478bd9Sstevel@tonic-gate * -1 if name not defined, 0 otherwise. 1477*7c478bd9Sstevel@tonic-gate * 1478*7c478bd9Sstevel@tonic-gate * Caller's context 1479*7c478bd9Sstevel@tonic-gate * No restrictions on context. rctl_dict_lock must not be held. 1480*7c478bd9Sstevel@tonic-gate */ 1481*7c478bd9Sstevel@tonic-gate int 1482*7c478bd9Sstevel@tonic-gate rctl_global_get(const char *name, rctl_dict_entry_t *drde) 1483*7c478bd9Sstevel@tonic-gate { 1484*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde = rctl_dict_lookup(name); 1485*7c478bd9Sstevel@tonic-gate 1486*7c478bd9Sstevel@tonic-gate if (rde == NULL) 1487*7c478bd9Sstevel@tonic-gate return (-1); 1488*7c478bd9Sstevel@tonic-gate 1489*7c478bd9Sstevel@tonic-gate bcopy(rde, drde, sizeof (rctl_dict_entry_t)); 1490*7c478bd9Sstevel@tonic-gate 1491*7c478bd9Sstevel@tonic-gate drde->rcd_next = NULL; 1492*7c478bd9Sstevel@tonic-gate drde->rcd_ops = NULL; 1493*7c478bd9Sstevel@tonic-gate 1494*7c478bd9Sstevel@tonic-gate return (0); 1495*7c478bd9Sstevel@tonic-gate } 1496*7c478bd9Sstevel@tonic-gate 1497*7c478bd9Sstevel@tonic-gate /* 1498*7c478bd9Sstevel@tonic-gate * int rctl_global_set(const char *, rctl_dict_entry_t *) 1499*7c478bd9Sstevel@tonic-gate * 1500*7c478bd9Sstevel@tonic-gate * Overview 1501*7c478bd9Sstevel@tonic-gate * Transfer the settable fields of the named rctl to the global rctl matching 1502*7c478bd9Sstevel@tonic-gate * the given resource control name. 1503*7c478bd9Sstevel@tonic-gate * 1504*7c478bd9Sstevel@tonic-gate * Return value 1505*7c478bd9Sstevel@tonic-gate * -1 if name not defined, 0 otherwise. 1506*7c478bd9Sstevel@tonic-gate * 1507*7c478bd9Sstevel@tonic-gate * Caller's context 1508*7c478bd9Sstevel@tonic-gate * No restrictions on context. rctl_dict_lock must not be held. 1509*7c478bd9Sstevel@tonic-gate */ 1510*7c478bd9Sstevel@tonic-gate int 1511*7c478bd9Sstevel@tonic-gate rctl_global_set(const char *name, rctl_dict_entry_t *drde) 1512*7c478bd9Sstevel@tonic-gate { 1513*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde = rctl_dict_lookup(name); 1514*7c478bd9Sstevel@tonic-gate 1515*7c478bd9Sstevel@tonic-gate if (rde == NULL) 1516*7c478bd9Sstevel@tonic-gate return (-1); 1517*7c478bd9Sstevel@tonic-gate 1518*7c478bd9Sstevel@tonic-gate rde->rcd_flagaction = drde->rcd_flagaction; 1519*7c478bd9Sstevel@tonic-gate rde->rcd_syslog_level = drde->rcd_syslog_level; 1520*7c478bd9Sstevel@tonic-gate rde->rcd_strlog_flags = drde->rcd_strlog_flags; 1521*7c478bd9Sstevel@tonic-gate 1522*7c478bd9Sstevel@tonic-gate return (0); 1523*7c478bd9Sstevel@tonic-gate } 1524*7c478bd9Sstevel@tonic-gate 1525*7c478bd9Sstevel@tonic-gate static int 1526*7c478bd9Sstevel@tonic-gate rctl_local_op(rctl_hndl_t hndl, rctl_val_t *oval, rctl_val_t *nval, 1527*7c478bd9Sstevel@tonic-gate int (*cbop)(rctl_hndl_t, struct proc *p, rctl_entity_p_t *e, rctl_t *, 1528*7c478bd9Sstevel@tonic-gate rctl_val_t *, rctl_val_t *), struct proc *p) 1529*7c478bd9Sstevel@tonic-gate { 1530*7c478bd9Sstevel@tonic-gate rctl_t *rctl; 1531*7c478bd9Sstevel@tonic-gate rctl_set_t *rset; 1532*7c478bd9Sstevel@tonic-gate rctl_entity_p_t e; 1533*7c478bd9Sstevel@tonic-gate int ret = 0; 1534*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde = rctl_dict_lookup_hndl(hndl); 1535*7c478bd9Sstevel@tonic-gate 1536*7c478bd9Sstevel@tonic-gate local_op_retry: 1537*7c478bd9Sstevel@tonic-gate 1538*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 1539*7c478bd9Sstevel@tonic-gate 1540*7c478bd9Sstevel@tonic-gate rset = rctl_entity_obtain_rset(rde, p); 1541*7c478bd9Sstevel@tonic-gate 1542*7c478bd9Sstevel@tonic-gate if (rset == NULL) { 1543*7c478bd9Sstevel@tonic-gate return (-1); 1544*7c478bd9Sstevel@tonic-gate } 1545*7c478bd9Sstevel@tonic-gate rctl_entity_obtain_entity_p(rset->rcs_entity, p, &e); 1546*7c478bd9Sstevel@tonic-gate 1547*7c478bd9Sstevel@tonic-gate mutex_enter(&rset->rcs_lock); 1548*7c478bd9Sstevel@tonic-gate 1549*7c478bd9Sstevel@tonic-gate /* using rctl's hndl, get rctl from local set */ 1550*7c478bd9Sstevel@tonic-gate if (rctl_set_find(rset, hndl, &rctl) == -1) { 1551*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 1552*7c478bd9Sstevel@tonic-gate return (-1); 1553*7c478bd9Sstevel@tonic-gate } 1554*7c478bd9Sstevel@tonic-gate 1555*7c478bd9Sstevel@tonic-gate ret = cbop(hndl, p, &e, rctl, oval, nval); 1556*7c478bd9Sstevel@tonic-gate 1557*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 1558*7c478bd9Sstevel@tonic-gate return (ret); 1559*7c478bd9Sstevel@tonic-gate } 1560*7c478bd9Sstevel@tonic-gate 1561*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1562*7c478bd9Sstevel@tonic-gate static int 1563*7c478bd9Sstevel@tonic-gate rctl_local_get_cb(rctl_hndl_t hndl, struct proc *p, rctl_entity_p_t *e, 1564*7c478bd9Sstevel@tonic-gate rctl_t *rctl, rctl_val_t *oval, rctl_val_t *nval) 1565*7c478bd9Sstevel@tonic-gate { 1566*7c478bd9Sstevel@tonic-gate if (oval == NULL) { 1567*7c478bd9Sstevel@tonic-gate /* 1568*7c478bd9Sstevel@tonic-gate * RCTL_FIRST 1569*7c478bd9Sstevel@tonic-gate */ 1570*7c478bd9Sstevel@tonic-gate bcopy(rctl->rc_values, nval, sizeof (rctl_val_t)); 1571*7c478bd9Sstevel@tonic-gate } else { 1572*7c478bd9Sstevel@tonic-gate /* 1573*7c478bd9Sstevel@tonic-gate * RCTL_NEXT 1574*7c478bd9Sstevel@tonic-gate */ 1575*7c478bd9Sstevel@tonic-gate rctl_val_t *tval = rctl_val_list_find(&rctl->rc_values, oval); 1576*7c478bd9Sstevel@tonic-gate 1577*7c478bd9Sstevel@tonic-gate if (tval == NULL) 1578*7c478bd9Sstevel@tonic-gate return (ESRCH); 1579*7c478bd9Sstevel@tonic-gate else if (tval->rcv_next == NULL) 1580*7c478bd9Sstevel@tonic-gate return (ENOENT); 1581*7c478bd9Sstevel@tonic-gate else 1582*7c478bd9Sstevel@tonic-gate bcopy(tval->rcv_next, nval, sizeof (rctl_val_t)); 1583*7c478bd9Sstevel@tonic-gate } 1584*7c478bd9Sstevel@tonic-gate 1585*7c478bd9Sstevel@tonic-gate return (0); 1586*7c478bd9Sstevel@tonic-gate } 1587*7c478bd9Sstevel@tonic-gate 1588*7c478bd9Sstevel@tonic-gate /* 1589*7c478bd9Sstevel@tonic-gate * int rctl_local_get(rctl_hndl_t, rctl_val_t *) 1590*7c478bd9Sstevel@tonic-gate * 1591*7c478bd9Sstevel@tonic-gate * Overview 1592*7c478bd9Sstevel@tonic-gate * Get the rctl value for the given flags. 1593*7c478bd9Sstevel@tonic-gate * 1594*7c478bd9Sstevel@tonic-gate * Return values 1595*7c478bd9Sstevel@tonic-gate * 0 for successful get, errno otherwise. 1596*7c478bd9Sstevel@tonic-gate */ 1597*7c478bd9Sstevel@tonic-gate int 1598*7c478bd9Sstevel@tonic-gate rctl_local_get(rctl_hndl_t hndl, rctl_val_t *oval, rctl_val_t *nval, 1599*7c478bd9Sstevel@tonic-gate struct proc *p) 1600*7c478bd9Sstevel@tonic-gate { 1601*7c478bd9Sstevel@tonic-gate return (rctl_local_op(hndl, oval, nval, rctl_local_get_cb, p)); 1602*7c478bd9Sstevel@tonic-gate } 1603*7c478bd9Sstevel@tonic-gate 1604*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1605*7c478bd9Sstevel@tonic-gate static int 1606*7c478bd9Sstevel@tonic-gate rctl_local_delete_cb(rctl_hndl_t hndl, struct proc *p, rctl_entity_p_t *e, 1607*7c478bd9Sstevel@tonic-gate rctl_t *rctl, rctl_val_t *oval, rctl_val_t *nval) 1608*7c478bd9Sstevel@tonic-gate { 1609*7c478bd9Sstevel@tonic-gate if ((oval = rctl_val_list_find(&rctl->rc_values, nval)) == NULL) 1610*7c478bd9Sstevel@tonic-gate return (ESRCH); 1611*7c478bd9Sstevel@tonic-gate 1612*7c478bd9Sstevel@tonic-gate if (rctl->rc_cursor == oval) { 1613*7c478bd9Sstevel@tonic-gate rctl->rc_cursor = oval->rcv_next; 1614*7c478bd9Sstevel@tonic-gate rctl_val_list_reset(rctl->rc_cursor); 1615*7c478bd9Sstevel@tonic-gate RCTLOP_SET(rctl, p, e, rctl_model_value(rctl->rc_dict_entry, p, 1616*7c478bd9Sstevel@tonic-gate rctl->rc_cursor->rcv_value)); 1617*7c478bd9Sstevel@tonic-gate 1618*7c478bd9Sstevel@tonic-gate ASSERT(rctl->rc_cursor != NULL); 1619*7c478bd9Sstevel@tonic-gate } 1620*7c478bd9Sstevel@tonic-gate 1621*7c478bd9Sstevel@tonic-gate (void) rctl_val_list_delete(&rctl->rc_values, oval); 1622*7c478bd9Sstevel@tonic-gate 1623*7c478bd9Sstevel@tonic-gate return (0); 1624*7c478bd9Sstevel@tonic-gate } 1625*7c478bd9Sstevel@tonic-gate 1626*7c478bd9Sstevel@tonic-gate /* 1627*7c478bd9Sstevel@tonic-gate * int rctl_local_delete(rctl_hndl_t, rctl_val_t *) 1628*7c478bd9Sstevel@tonic-gate * 1629*7c478bd9Sstevel@tonic-gate * Overview 1630*7c478bd9Sstevel@tonic-gate * Delete the rctl value for the given flags. 1631*7c478bd9Sstevel@tonic-gate * 1632*7c478bd9Sstevel@tonic-gate * Return values 1633*7c478bd9Sstevel@tonic-gate * 0 for successful delete, errno otherwise. 1634*7c478bd9Sstevel@tonic-gate */ 1635*7c478bd9Sstevel@tonic-gate int 1636*7c478bd9Sstevel@tonic-gate rctl_local_delete(rctl_hndl_t hndl, rctl_val_t *val, struct proc *p) 1637*7c478bd9Sstevel@tonic-gate { 1638*7c478bd9Sstevel@tonic-gate return (rctl_local_op(hndl, NULL, val, rctl_local_delete_cb, p)); 1639*7c478bd9Sstevel@tonic-gate } 1640*7c478bd9Sstevel@tonic-gate 1641*7c478bd9Sstevel@tonic-gate /* 1642*7c478bd9Sstevel@tonic-gate * rctl_local_insert_cb() 1643*7c478bd9Sstevel@tonic-gate * 1644*7c478bd9Sstevel@tonic-gate * Overview 1645*7c478bd9Sstevel@tonic-gate * Insert a new value into the rctl's val list. If an error occurs, 1646*7c478bd9Sstevel@tonic-gate * the val list must be left in the same state as when the function 1647*7c478bd9Sstevel@tonic-gate * was entered. 1648*7c478bd9Sstevel@tonic-gate * 1649*7c478bd9Sstevel@tonic-gate * Return Values 1650*7c478bd9Sstevel@tonic-gate * 0 for successful insert, EINVAL if the value is duplicated in the 1651*7c478bd9Sstevel@tonic-gate * existing list. 1652*7c478bd9Sstevel@tonic-gate */ 1653*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1654*7c478bd9Sstevel@tonic-gate static int 1655*7c478bd9Sstevel@tonic-gate rctl_local_insert_cb(rctl_hndl_t hndl, struct proc *p, rctl_entity_p_t *e, 1656*7c478bd9Sstevel@tonic-gate rctl_t *rctl, rctl_val_t *oval, rctl_val_t *nval) 1657*7c478bd9Sstevel@tonic-gate { 1658*7c478bd9Sstevel@tonic-gate /* 1659*7c478bd9Sstevel@tonic-gate * Before inserting, confirm there are no duplicates of this value 1660*7c478bd9Sstevel@tonic-gate * and flag level. If there is a duplicate, flag an error and do 1661*7c478bd9Sstevel@tonic-gate * nothing. 1662*7c478bd9Sstevel@tonic-gate */ 1663*7c478bd9Sstevel@tonic-gate if (rctl_val_list_insert(&rctl->rc_values, nval) != 0) 1664*7c478bd9Sstevel@tonic-gate return (EINVAL); 1665*7c478bd9Sstevel@tonic-gate 1666*7c478bd9Sstevel@tonic-gate if (rctl_val_cmp(nval, rctl->rc_cursor, 0) < 0) { 1667*7c478bd9Sstevel@tonic-gate rctl->rc_cursor = nval; 1668*7c478bd9Sstevel@tonic-gate rctl_val_list_reset(rctl->rc_cursor); 1669*7c478bd9Sstevel@tonic-gate RCTLOP_SET(rctl, p, e, rctl_model_value(rctl->rc_dict_entry, p, 1670*7c478bd9Sstevel@tonic-gate rctl->rc_cursor->rcv_value)); 1671*7c478bd9Sstevel@tonic-gate 1672*7c478bd9Sstevel@tonic-gate ASSERT(rctl->rc_cursor != NULL); 1673*7c478bd9Sstevel@tonic-gate } 1674*7c478bd9Sstevel@tonic-gate 1675*7c478bd9Sstevel@tonic-gate return (0); 1676*7c478bd9Sstevel@tonic-gate } 1677*7c478bd9Sstevel@tonic-gate 1678*7c478bd9Sstevel@tonic-gate /* 1679*7c478bd9Sstevel@tonic-gate * int rctl_local_insert(rctl_hndl_t, rctl_val_t *) 1680*7c478bd9Sstevel@tonic-gate * 1681*7c478bd9Sstevel@tonic-gate * Overview 1682*7c478bd9Sstevel@tonic-gate * Insert the rctl value into the appropriate rctl set for the calling 1683*7c478bd9Sstevel@tonic-gate * process, given the handle. 1684*7c478bd9Sstevel@tonic-gate */ 1685*7c478bd9Sstevel@tonic-gate int 1686*7c478bd9Sstevel@tonic-gate rctl_local_insert(rctl_hndl_t hndl, rctl_val_t *val, struct proc *p) 1687*7c478bd9Sstevel@tonic-gate { 1688*7c478bd9Sstevel@tonic-gate return (rctl_local_op(hndl, NULL, val, rctl_local_insert_cb, p)); 1689*7c478bd9Sstevel@tonic-gate } 1690*7c478bd9Sstevel@tonic-gate 1691*7c478bd9Sstevel@tonic-gate static int 1692*7c478bd9Sstevel@tonic-gate rctl_local_replace_cb(rctl_hndl_t hndl, struct proc *p, rctl_entity_p_t *e, 1693*7c478bd9Sstevel@tonic-gate rctl_t *rctl, rctl_val_t *oval, rctl_val_t *nval) 1694*7c478bd9Sstevel@tonic-gate { 1695*7c478bd9Sstevel@tonic-gate int ret; 1696*7c478bd9Sstevel@tonic-gate 1697*7c478bd9Sstevel@tonic-gate /* 1698*7c478bd9Sstevel@tonic-gate * rctl_local_insert_cb() does the job of flagging an error 1699*7c478bd9Sstevel@tonic-gate * for any duplicate values. So, call rctl_local_insert_cb() 1700*7c478bd9Sstevel@tonic-gate * for the new value first, then do deletion of the old value. 1701*7c478bd9Sstevel@tonic-gate * Since this is a callback function to rctl_local_op, we can 1702*7c478bd9Sstevel@tonic-gate * count on rcs_lock being held at this point. This guarantees 1703*7c478bd9Sstevel@tonic-gate * that there is at no point a visible list which contains both 1704*7c478bd9Sstevel@tonic-gate * new and old values. 1705*7c478bd9Sstevel@tonic-gate */ 1706*7c478bd9Sstevel@tonic-gate if (ret = rctl_local_insert_cb(hndl, p, e, rctl, NULL, nval)) 1707*7c478bd9Sstevel@tonic-gate return (ret); 1708*7c478bd9Sstevel@tonic-gate 1709*7c478bd9Sstevel@tonic-gate return (rctl_local_delete_cb(hndl, p, e, rctl, NULL, oval)); 1710*7c478bd9Sstevel@tonic-gate } 1711*7c478bd9Sstevel@tonic-gate 1712*7c478bd9Sstevel@tonic-gate /* 1713*7c478bd9Sstevel@tonic-gate * int rctl_local_replace(rctl_hndl_t, void *, int, uint64_t *) 1714*7c478bd9Sstevel@tonic-gate * 1715*7c478bd9Sstevel@tonic-gate * Overview 1716*7c478bd9Sstevel@tonic-gate * Replace the rctl value with a new one. 1717*7c478bd9Sstevel@tonic-gate * 1718*7c478bd9Sstevel@tonic-gate * Return values 1719*7c478bd9Sstevel@tonic-gate * 0 for successful replace, errno otherwise. 1720*7c478bd9Sstevel@tonic-gate */ 1721*7c478bd9Sstevel@tonic-gate int 1722*7c478bd9Sstevel@tonic-gate rctl_local_replace(rctl_hndl_t hndl, rctl_val_t *oval, rctl_val_t *nval, 1723*7c478bd9Sstevel@tonic-gate struct proc *p) 1724*7c478bd9Sstevel@tonic-gate { 1725*7c478bd9Sstevel@tonic-gate return (rctl_local_op(hndl, oval, nval, rctl_local_replace_cb, p)); 1726*7c478bd9Sstevel@tonic-gate } 1727*7c478bd9Sstevel@tonic-gate 1728*7c478bd9Sstevel@tonic-gate /* 1729*7c478bd9Sstevel@tonic-gate * int rctl_rlimit_get(rctl_hndl_t, struct proc *, struct rlimit64 *) 1730*7c478bd9Sstevel@tonic-gate * 1731*7c478bd9Sstevel@tonic-gate * Overview 1732*7c478bd9Sstevel@tonic-gate * To support rlimit compatibility, we need a function which takes a 64-bit 1733*7c478bd9Sstevel@tonic-gate * rlimit and encodes it as appropriate rcontrol values on the given rcontrol. 1734*7c478bd9Sstevel@tonic-gate * This operation is only intended for legacy rlimits. 1735*7c478bd9Sstevel@tonic-gate */ 1736*7c478bd9Sstevel@tonic-gate int 1737*7c478bd9Sstevel@tonic-gate rctl_rlimit_get(rctl_hndl_t rc, struct proc *p, struct rlimit64 *rlp64) 1738*7c478bd9Sstevel@tonic-gate { 1739*7c478bd9Sstevel@tonic-gate rctl_t *rctl; 1740*7c478bd9Sstevel@tonic-gate rctl_val_t *rval; 1741*7c478bd9Sstevel@tonic-gate rctl_set_t *rset = p->p_rctls; 1742*7c478bd9Sstevel@tonic-gate int soft_limit_seen = 0; 1743*7c478bd9Sstevel@tonic-gate int test_for_deny = 1; 1744*7c478bd9Sstevel@tonic-gate 1745*7c478bd9Sstevel@tonic-gate mutex_enter(&rset->rcs_lock); 1746*7c478bd9Sstevel@tonic-gate if (rctl_set_find(rset, rc, &rctl) == -1) { 1747*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 1748*7c478bd9Sstevel@tonic-gate return (-1); 1749*7c478bd9Sstevel@tonic-gate } 1750*7c478bd9Sstevel@tonic-gate 1751*7c478bd9Sstevel@tonic-gate rval = rctl->rc_values; 1752*7c478bd9Sstevel@tonic-gate 1753*7c478bd9Sstevel@tonic-gate if (rctl->rc_dict_entry->rcd_flagaction & (RCTL_GLOBAL_DENY_NEVER | 1754*7c478bd9Sstevel@tonic-gate RCTL_GLOBAL_DENY_ALWAYS)) 1755*7c478bd9Sstevel@tonic-gate test_for_deny = 0; 1756*7c478bd9Sstevel@tonic-gate 1757*7c478bd9Sstevel@tonic-gate /* 1758*7c478bd9Sstevel@tonic-gate * 1. Find the first control value with the RCTL_LOCAL_DENY bit set. 1759*7c478bd9Sstevel@tonic-gate */ 1760*7c478bd9Sstevel@tonic-gate while (rval != NULL && rval->rcv_privilege != RCPRIV_SYSTEM) { 1761*7c478bd9Sstevel@tonic-gate if (test_for_deny && 1762*7c478bd9Sstevel@tonic-gate (rval->rcv_flagaction & RCTL_LOCAL_DENY) == 0) { 1763*7c478bd9Sstevel@tonic-gate rval = rval->rcv_next; 1764*7c478bd9Sstevel@tonic-gate continue; 1765*7c478bd9Sstevel@tonic-gate } 1766*7c478bd9Sstevel@tonic-gate 1767*7c478bd9Sstevel@tonic-gate /* 1768*7c478bd9Sstevel@tonic-gate * 2. If this is an RCPRIV_BASIC value, then we've found the 1769*7c478bd9Sstevel@tonic-gate * effective soft limit and should set rlim_cur. We should then 1770*7c478bd9Sstevel@tonic-gate * continue looking for another control value with the DENY bit 1771*7c478bd9Sstevel@tonic-gate * set. 1772*7c478bd9Sstevel@tonic-gate */ 1773*7c478bd9Sstevel@tonic-gate if (rval->rcv_privilege == RCPRIV_BASIC) { 1774*7c478bd9Sstevel@tonic-gate if (soft_limit_seen) { 1775*7c478bd9Sstevel@tonic-gate rval = rval->rcv_next; 1776*7c478bd9Sstevel@tonic-gate continue; 1777*7c478bd9Sstevel@tonic-gate } 1778*7c478bd9Sstevel@tonic-gate 1779*7c478bd9Sstevel@tonic-gate if ((rval->rcv_flagaction & RCTL_LOCAL_MAXIMAL) == 0 && 1780*7c478bd9Sstevel@tonic-gate rval->rcv_value < rctl_model_maximum( 1781*7c478bd9Sstevel@tonic-gate rctl->rc_dict_entry, p)) 1782*7c478bd9Sstevel@tonic-gate rlp64->rlim_cur = rval->rcv_value; 1783*7c478bd9Sstevel@tonic-gate else 1784*7c478bd9Sstevel@tonic-gate rlp64->rlim_cur = RLIM64_INFINITY; 1785*7c478bd9Sstevel@tonic-gate soft_limit_seen = 1; 1786*7c478bd9Sstevel@tonic-gate 1787*7c478bd9Sstevel@tonic-gate rval = rval->rcv_next; 1788*7c478bd9Sstevel@tonic-gate continue; 1789*7c478bd9Sstevel@tonic-gate } 1790*7c478bd9Sstevel@tonic-gate 1791*7c478bd9Sstevel@tonic-gate /* 1792*7c478bd9Sstevel@tonic-gate * 3. This is an RCPRIV_PRIVILEGED value. If we haven't found 1793*7c478bd9Sstevel@tonic-gate * a soft limit candidate, then we've found the effective hard 1794*7c478bd9Sstevel@tonic-gate * and soft limits and should set both If we had found a soft 1795*7c478bd9Sstevel@tonic-gate * limit, then this is only the hard limit and we need only set 1796*7c478bd9Sstevel@tonic-gate * rlim_max. 1797*7c478bd9Sstevel@tonic-gate */ 1798*7c478bd9Sstevel@tonic-gate if ((rval->rcv_flagaction & RCTL_LOCAL_MAXIMAL) == 0 && 1799*7c478bd9Sstevel@tonic-gate rval->rcv_value < rctl_model_maximum(rctl->rc_dict_entry, 1800*7c478bd9Sstevel@tonic-gate p)) 1801*7c478bd9Sstevel@tonic-gate rlp64->rlim_max = rval->rcv_value; 1802*7c478bd9Sstevel@tonic-gate else 1803*7c478bd9Sstevel@tonic-gate rlp64->rlim_max = RLIM64_INFINITY; 1804*7c478bd9Sstevel@tonic-gate if (!soft_limit_seen) 1805*7c478bd9Sstevel@tonic-gate rlp64->rlim_cur = rlp64->rlim_max; 1806*7c478bd9Sstevel@tonic-gate 1807*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 1808*7c478bd9Sstevel@tonic-gate return (0); 1809*7c478bd9Sstevel@tonic-gate } 1810*7c478bd9Sstevel@tonic-gate 1811*7c478bd9Sstevel@tonic-gate if (rval == NULL) { 1812*7c478bd9Sstevel@tonic-gate /* 1813*7c478bd9Sstevel@tonic-gate * This control sequence is corrupt, as it is not terminated by 1814*7c478bd9Sstevel@tonic-gate * a system privileged control value. 1815*7c478bd9Sstevel@tonic-gate */ 1816*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 1817*7c478bd9Sstevel@tonic-gate return (-1); 1818*7c478bd9Sstevel@tonic-gate } 1819*7c478bd9Sstevel@tonic-gate 1820*7c478bd9Sstevel@tonic-gate /* 1821*7c478bd9Sstevel@tonic-gate * 4. If we run into a RCPRIV_SYSTEM value, then the hard limit (and 1822*7c478bd9Sstevel@tonic-gate * the soft, if we haven't a soft candidate) should be the value of the 1823*7c478bd9Sstevel@tonic-gate * system control value. 1824*7c478bd9Sstevel@tonic-gate */ 1825*7c478bd9Sstevel@tonic-gate if ((rval->rcv_flagaction & RCTL_LOCAL_MAXIMAL) == 0 && 1826*7c478bd9Sstevel@tonic-gate rval->rcv_value < rctl_model_maximum(rctl->rc_dict_entry, p)) 1827*7c478bd9Sstevel@tonic-gate rlp64->rlim_max = rval->rcv_value; 1828*7c478bd9Sstevel@tonic-gate else 1829*7c478bd9Sstevel@tonic-gate rlp64->rlim_max = RLIM64_INFINITY; 1830*7c478bd9Sstevel@tonic-gate 1831*7c478bd9Sstevel@tonic-gate if (!soft_limit_seen) 1832*7c478bd9Sstevel@tonic-gate rlp64->rlim_cur = rlp64->rlim_max; 1833*7c478bd9Sstevel@tonic-gate 1834*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 1835*7c478bd9Sstevel@tonic-gate return (0); 1836*7c478bd9Sstevel@tonic-gate } 1837*7c478bd9Sstevel@tonic-gate 1838*7c478bd9Sstevel@tonic-gate /* 1839*7c478bd9Sstevel@tonic-gate * rctl_alloc_gp_t *rctl_rlimit_set_prealloc(uint_t) 1840*7c478bd9Sstevel@tonic-gate * 1841*7c478bd9Sstevel@tonic-gate * Overview 1842*7c478bd9Sstevel@tonic-gate * Before making a series of calls to rctl_rlimit_set(), we must have a 1843*7c478bd9Sstevel@tonic-gate * preallocated batch of resource control values, as rctl_rlimit_set() can 1844*7c478bd9Sstevel@tonic-gate * potentially consume two resource control values per call. 1845*7c478bd9Sstevel@tonic-gate * 1846*7c478bd9Sstevel@tonic-gate * Return values 1847*7c478bd9Sstevel@tonic-gate * A populated resource control allocation group with 2n resource control 1848*7c478bd9Sstevel@tonic-gate * values. 1849*7c478bd9Sstevel@tonic-gate * 1850*7c478bd9Sstevel@tonic-gate * Caller's context 1851*7c478bd9Sstevel@tonic-gate * Must be safe for KM_SLEEP allocations. 1852*7c478bd9Sstevel@tonic-gate */ 1853*7c478bd9Sstevel@tonic-gate rctl_alloc_gp_t * 1854*7c478bd9Sstevel@tonic-gate rctl_rlimit_set_prealloc(uint_t n) 1855*7c478bd9Sstevel@tonic-gate { 1856*7c478bd9Sstevel@tonic-gate rctl_alloc_gp_t *gp = kmem_zalloc(sizeof (rctl_alloc_gp_t), KM_SLEEP); 1857*7c478bd9Sstevel@tonic-gate 1858*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&curproc->p_lock)); 1859*7c478bd9Sstevel@tonic-gate 1860*7c478bd9Sstevel@tonic-gate gp->rcag_nvals = 2 * n; 1861*7c478bd9Sstevel@tonic-gate 1862*7c478bd9Sstevel@tonic-gate rctl_gp_alloc(gp); 1863*7c478bd9Sstevel@tonic-gate 1864*7c478bd9Sstevel@tonic-gate return (gp); 1865*7c478bd9Sstevel@tonic-gate } 1866*7c478bd9Sstevel@tonic-gate 1867*7c478bd9Sstevel@tonic-gate /* 1868*7c478bd9Sstevel@tonic-gate * int rctl_rlimit_set(rctl_hndl_t, struct proc *, struct rlimit64 *, int, 1869*7c478bd9Sstevel@tonic-gate * int) 1870*7c478bd9Sstevel@tonic-gate * 1871*7c478bd9Sstevel@tonic-gate * Overview 1872*7c478bd9Sstevel@tonic-gate * To support rlimit compatibility, we need a function which takes a 64-bit 1873*7c478bd9Sstevel@tonic-gate * rlimit and encodes it as appropriate rcontrol values on the given rcontrol. 1874*7c478bd9Sstevel@tonic-gate * This operation is only intended for legacy rlimits. 1875*7c478bd9Sstevel@tonic-gate * 1876*7c478bd9Sstevel@tonic-gate * The implementation of rctl_rlimit_set() is a bit clever, as it tries to 1877*7c478bd9Sstevel@tonic-gate * minimize the number of values placed on the value sequence in various 1878*7c478bd9Sstevel@tonic-gate * cases. Furthermore, we don't allow multiple identical privilege-action 1879*7c478bd9Sstevel@tonic-gate * values on the same sequence. (That is, we don't want a sequence like 1880*7c478bd9Sstevel@tonic-gate * "while (1) { rlim.rlim_cur++; setrlimit(..., rlim); }" to exhaust kernel 1881*7c478bd9Sstevel@tonic-gate * memory.) So we want to delete any values with the same privilege value and 1882*7c478bd9Sstevel@tonic-gate * action. 1883*7c478bd9Sstevel@tonic-gate * 1884*7c478bd9Sstevel@tonic-gate * Return values 1885*7c478bd9Sstevel@tonic-gate * 0 for successful set, errno otherwise. Errno will be either EINVAL 1886*7c478bd9Sstevel@tonic-gate * or EPERM, in keeping with defined errnos for ulimit() and setrlimit() 1887*7c478bd9Sstevel@tonic-gate * system calls. 1888*7c478bd9Sstevel@tonic-gate */ 1889*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1890*7c478bd9Sstevel@tonic-gate int 1891*7c478bd9Sstevel@tonic-gate rctl_rlimit_set(rctl_hndl_t rc, struct proc *p, struct rlimit64 *rlp64, 1892*7c478bd9Sstevel@tonic-gate rctl_alloc_gp_t *ragp, int flagaction, int signal, const cred_t *cr) 1893*7c478bd9Sstevel@tonic-gate { 1894*7c478bd9Sstevel@tonic-gate rctl_t *rctl; 1895*7c478bd9Sstevel@tonic-gate rctl_val_t *rval, *rval_priv, *rval_basic; 1896*7c478bd9Sstevel@tonic-gate rctl_set_t *rset = p->p_rctls; 1897*7c478bd9Sstevel@tonic-gate rctl_qty_t max; 1898*7c478bd9Sstevel@tonic-gate rctl_entity_p_t e; 1899*7c478bd9Sstevel@tonic-gate struct rlimit64 cur_rl; 1900*7c478bd9Sstevel@tonic-gate 1901*7c478bd9Sstevel@tonic-gate e.rcep_t = RCENTITY_PROCESS; 1902*7c478bd9Sstevel@tonic-gate e.rcep_p.proc = p; 1903*7c478bd9Sstevel@tonic-gate 1904*7c478bd9Sstevel@tonic-gate if (rlp64->rlim_cur > rlp64->rlim_max) 1905*7c478bd9Sstevel@tonic-gate return (EINVAL); 1906*7c478bd9Sstevel@tonic-gate 1907*7c478bd9Sstevel@tonic-gate if (rctl_rlimit_get(rc, p, &cur_rl) == -1) 1908*7c478bd9Sstevel@tonic-gate return (EINVAL); 1909*7c478bd9Sstevel@tonic-gate 1910*7c478bd9Sstevel@tonic-gate /* 1911*7c478bd9Sstevel@tonic-gate * If we are not privileged, we can only lower the hard limit. 1912*7c478bd9Sstevel@tonic-gate */ 1913*7c478bd9Sstevel@tonic-gate if ((rlp64->rlim_max > cur_rl.rlim_max) && 1914*7c478bd9Sstevel@tonic-gate cur_rl.rlim_max != RLIM64_INFINITY && 1915*7c478bd9Sstevel@tonic-gate secpolicy_resource(cr) != 0) 1916*7c478bd9Sstevel@tonic-gate return (EPERM); 1917*7c478bd9Sstevel@tonic-gate 1918*7c478bd9Sstevel@tonic-gate mutex_enter(&rset->rcs_lock); 1919*7c478bd9Sstevel@tonic-gate 1920*7c478bd9Sstevel@tonic-gate if (rctl_set_find(rset, rc, &rctl) == -1) { 1921*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 1922*7c478bd9Sstevel@tonic-gate return (EINVAL); 1923*7c478bd9Sstevel@tonic-gate } 1924*7c478bd9Sstevel@tonic-gate 1925*7c478bd9Sstevel@tonic-gate rval_priv = rctl_gp_detach_val(ragp); 1926*7c478bd9Sstevel@tonic-gate 1927*7c478bd9Sstevel@tonic-gate rval = rctl->rc_values; 1928*7c478bd9Sstevel@tonic-gate 1929*7c478bd9Sstevel@tonic-gate while (rval != NULL) { 1930*7c478bd9Sstevel@tonic-gate rctl_val_t *next = rval->rcv_next; 1931*7c478bd9Sstevel@tonic-gate 1932*7c478bd9Sstevel@tonic-gate if (rval->rcv_privilege == RCPRIV_SYSTEM) 1933*7c478bd9Sstevel@tonic-gate break; 1934*7c478bd9Sstevel@tonic-gate 1935*7c478bd9Sstevel@tonic-gate if ((rval->rcv_privilege == RCPRIV_BASIC) || 1936*7c478bd9Sstevel@tonic-gate (rval->rcv_flagaction & ~RCTL_LOCAL_ACTION_MASK) == 1937*7c478bd9Sstevel@tonic-gate (flagaction & ~RCTL_LOCAL_ACTION_MASK)) { 1938*7c478bd9Sstevel@tonic-gate if (rctl->rc_cursor == rval) { 1939*7c478bd9Sstevel@tonic-gate rctl->rc_cursor = rval->rcv_next; 1940*7c478bd9Sstevel@tonic-gate rctl_val_list_reset(rctl->rc_cursor); 1941*7c478bd9Sstevel@tonic-gate RCTLOP_SET(rctl, p, &e, rctl_model_value( 1942*7c478bd9Sstevel@tonic-gate rctl->rc_dict_entry, p, 1943*7c478bd9Sstevel@tonic-gate rctl->rc_cursor->rcv_value)); 1944*7c478bd9Sstevel@tonic-gate } 1945*7c478bd9Sstevel@tonic-gate (void) rctl_val_list_delete(&rctl->rc_values, rval); 1946*7c478bd9Sstevel@tonic-gate } 1947*7c478bd9Sstevel@tonic-gate 1948*7c478bd9Sstevel@tonic-gate rval = next; 1949*7c478bd9Sstevel@tonic-gate } 1950*7c478bd9Sstevel@tonic-gate 1951*7c478bd9Sstevel@tonic-gate rval_priv->rcv_privilege = RCPRIV_PRIVILEGED; 1952*7c478bd9Sstevel@tonic-gate rval_priv->rcv_flagaction = flagaction; 1953*7c478bd9Sstevel@tonic-gate if (rlp64->rlim_max == RLIM64_INFINITY) { 1954*7c478bd9Sstevel@tonic-gate rval_priv->rcv_flagaction |= RCTL_LOCAL_MAXIMAL; 1955*7c478bd9Sstevel@tonic-gate max = rctl->rc_dict_entry->rcd_max_native; 1956*7c478bd9Sstevel@tonic-gate } else { 1957*7c478bd9Sstevel@tonic-gate max = rlp64->rlim_max; 1958*7c478bd9Sstevel@tonic-gate } 1959*7c478bd9Sstevel@tonic-gate rval_priv->rcv_value = max; 1960*7c478bd9Sstevel@tonic-gate rval_priv->rcv_action_signal = signal; 1961*7c478bd9Sstevel@tonic-gate rval_priv->rcv_action_recipient = NULL; 1962*7c478bd9Sstevel@tonic-gate rval_priv->rcv_action_recip_pid = -1; 1963*7c478bd9Sstevel@tonic-gate rval_priv->rcv_firing_time = 0; 1964*7c478bd9Sstevel@tonic-gate rval_priv->rcv_prev = rval_priv->rcv_next = NULL; 1965*7c478bd9Sstevel@tonic-gate 1966*7c478bd9Sstevel@tonic-gate (void) rctl_val_list_insert(&rctl->rc_values, rval_priv); 1967*7c478bd9Sstevel@tonic-gate rctl->rc_cursor = rval_priv; 1968*7c478bd9Sstevel@tonic-gate rctl_val_list_reset(rctl->rc_cursor); 1969*7c478bd9Sstevel@tonic-gate RCTLOP_SET(rctl, p, &e, rctl_model_value(rctl->rc_dict_entry, p, 1970*7c478bd9Sstevel@tonic-gate rctl->rc_cursor->rcv_value)); 1971*7c478bd9Sstevel@tonic-gate 1972*7c478bd9Sstevel@tonic-gate if (rlp64->rlim_cur != RLIM64_INFINITY && rlp64->rlim_cur < max) { 1973*7c478bd9Sstevel@tonic-gate rval_basic = rctl_gp_detach_val(ragp); 1974*7c478bd9Sstevel@tonic-gate 1975*7c478bd9Sstevel@tonic-gate rval_basic->rcv_privilege = RCPRIV_BASIC; 1976*7c478bd9Sstevel@tonic-gate rval_basic->rcv_value = rlp64->rlim_cur; 1977*7c478bd9Sstevel@tonic-gate rval_basic->rcv_flagaction = flagaction; 1978*7c478bd9Sstevel@tonic-gate rval_basic->rcv_action_signal = signal; 1979*7c478bd9Sstevel@tonic-gate rval_basic->rcv_action_recipient = p; 1980*7c478bd9Sstevel@tonic-gate rval_basic->rcv_action_recip_pid = p->p_pid; 1981*7c478bd9Sstevel@tonic-gate rval_basic->rcv_firing_time = 0; 1982*7c478bd9Sstevel@tonic-gate rval_basic->rcv_prev = rval_basic->rcv_next = NULL; 1983*7c478bd9Sstevel@tonic-gate 1984*7c478bd9Sstevel@tonic-gate (void) rctl_val_list_insert(&rctl->rc_values, rval_basic); 1985*7c478bd9Sstevel@tonic-gate rctl->rc_cursor = rval_basic; 1986*7c478bd9Sstevel@tonic-gate rctl_val_list_reset(rctl->rc_cursor); 1987*7c478bd9Sstevel@tonic-gate RCTLOP_SET(rctl, p, &e, rctl_model_value(rctl->rc_dict_entry, p, 1988*7c478bd9Sstevel@tonic-gate rctl->rc_cursor->rcv_value)); 1989*7c478bd9Sstevel@tonic-gate } 1990*7c478bd9Sstevel@tonic-gate 1991*7c478bd9Sstevel@tonic-gate ASSERT(rctl->rc_cursor != NULL); 1992*7c478bd9Sstevel@tonic-gate 1993*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 1994*7c478bd9Sstevel@tonic-gate return (0); 1995*7c478bd9Sstevel@tonic-gate } 1996*7c478bd9Sstevel@tonic-gate 1997*7c478bd9Sstevel@tonic-gate 1998*7c478bd9Sstevel@tonic-gate /* 1999*7c478bd9Sstevel@tonic-gate * rctl_hndl_t rctl_register(const char *, rctl_entity_t, int, rlim64_t, 2000*7c478bd9Sstevel@tonic-gate * rlim64_t, rctl_ops_t *) 2001*7c478bd9Sstevel@tonic-gate * 2002*7c478bd9Sstevel@tonic-gate * Overview 2003*7c478bd9Sstevel@tonic-gate * rctl_register() performs a look-up in the dictionary of rctls 2004*7c478bd9Sstevel@tonic-gate * active on the system; if a rctl of that name is absent, an entry is 2005*7c478bd9Sstevel@tonic-gate * made into the dictionary. The rctl is returned with its reference 2006*7c478bd9Sstevel@tonic-gate * count incremented by one. If the rctl name already exists, we panic. 2007*7c478bd9Sstevel@tonic-gate * (Were the resource control system to support dynamic loading and unloading, 2008*7c478bd9Sstevel@tonic-gate * which it is structured for, duplicate registration should lead to load 2009*7c478bd9Sstevel@tonic-gate * failure instead of panicking.) 2010*7c478bd9Sstevel@tonic-gate * 2011*7c478bd9Sstevel@tonic-gate * Each registered rctl has a requirement that a RCPRIV_SYSTEM limit be 2012*7c478bd9Sstevel@tonic-gate * defined. This limit contains the highest possible value for this quantity 2013*7c478bd9Sstevel@tonic-gate * on the system. Furthermore, the registered control must provide infinite 2014*7c478bd9Sstevel@tonic-gate * values for all applicable address space models supported by the operating 2015*7c478bd9Sstevel@tonic-gate * system. Attempts to set resource control values beyond the system limit 2016*7c478bd9Sstevel@tonic-gate * will fail. 2017*7c478bd9Sstevel@tonic-gate * 2018*7c478bd9Sstevel@tonic-gate * Return values 2019*7c478bd9Sstevel@tonic-gate * The rctl's ID. 2020*7c478bd9Sstevel@tonic-gate * 2021*7c478bd9Sstevel@tonic-gate * Caller's context 2022*7c478bd9Sstevel@tonic-gate * Caller must be in a context suitable for KM_SLEEP allocations. 2023*7c478bd9Sstevel@tonic-gate */ 2024*7c478bd9Sstevel@tonic-gate rctl_hndl_t 2025*7c478bd9Sstevel@tonic-gate rctl_register( 2026*7c478bd9Sstevel@tonic-gate const char *name, 2027*7c478bd9Sstevel@tonic-gate rctl_entity_t entity, 2028*7c478bd9Sstevel@tonic-gate int global_flags, 2029*7c478bd9Sstevel@tonic-gate rlim64_t max_native, 2030*7c478bd9Sstevel@tonic-gate rlim64_t max_ilp32, 2031*7c478bd9Sstevel@tonic-gate rctl_ops_t *ops) 2032*7c478bd9Sstevel@tonic-gate { 2033*7c478bd9Sstevel@tonic-gate rctl_t *rctl = kmem_cache_alloc(rctl_cache, KM_SLEEP); 2034*7c478bd9Sstevel@tonic-gate rctl_val_t *rctl_val = kmem_cache_alloc(rctl_val_cache, KM_SLEEP); 2035*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rctl_de = kmem_zalloc(sizeof (rctl_dict_entry_t), 2036*7c478bd9Sstevel@tonic-gate KM_SLEEP); 2037*7c478bd9Sstevel@tonic-gate rctl_t *old_rctl; 2038*7c478bd9Sstevel@tonic-gate rctl_hndl_t rhndl; 2039*7c478bd9Sstevel@tonic-gate int localflags; 2040*7c478bd9Sstevel@tonic-gate 2041*7c478bd9Sstevel@tonic-gate ASSERT(ops != NULL); 2042*7c478bd9Sstevel@tonic-gate 2043*7c478bd9Sstevel@tonic-gate bzero(rctl, sizeof (rctl_t)); 2044*7c478bd9Sstevel@tonic-gate bzero(rctl_val, sizeof (rctl_val_t)); 2045*7c478bd9Sstevel@tonic-gate 2046*7c478bd9Sstevel@tonic-gate if (global_flags & RCTL_GLOBAL_DENY_NEVER) 2047*7c478bd9Sstevel@tonic-gate localflags = RCTL_LOCAL_MAXIMAL; 2048*7c478bd9Sstevel@tonic-gate else 2049*7c478bd9Sstevel@tonic-gate localflags = RCTL_LOCAL_MAXIMAL | RCTL_LOCAL_DENY; 2050*7c478bd9Sstevel@tonic-gate 2051*7c478bd9Sstevel@tonic-gate rctl_val->rcv_privilege = RCPRIV_SYSTEM; 2052*7c478bd9Sstevel@tonic-gate rctl_val->rcv_value = max_native; 2053*7c478bd9Sstevel@tonic-gate rctl_val->rcv_flagaction = localflags; 2054*7c478bd9Sstevel@tonic-gate rctl_val->rcv_action_signal = 0; 2055*7c478bd9Sstevel@tonic-gate rctl_val->rcv_action_recipient = NULL; 2056*7c478bd9Sstevel@tonic-gate rctl_val->rcv_action_recip_pid = -1; 2057*7c478bd9Sstevel@tonic-gate rctl_val->rcv_firing_time = 0; 2058*7c478bd9Sstevel@tonic-gate rctl_val->rcv_next = NULL; 2059*7c478bd9Sstevel@tonic-gate rctl_val->rcv_prev = NULL; 2060*7c478bd9Sstevel@tonic-gate 2061*7c478bd9Sstevel@tonic-gate rctl_de->rcd_name = (char *)name; 2062*7c478bd9Sstevel@tonic-gate rctl_de->rcd_default_value = rctl_val; 2063*7c478bd9Sstevel@tonic-gate rctl_de->rcd_max_native = max_native; 2064*7c478bd9Sstevel@tonic-gate rctl_de->rcd_max_ilp32 = max_ilp32; 2065*7c478bd9Sstevel@tonic-gate rctl_de->rcd_entity = entity; 2066*7c478bd9Sstevel@tonic-gate rctl_de->rcd_ops = ops; 2067*7c478bd9Sstevel@tonic-gate rctl_de->rcd_flagaction = global_flags; 2068*7c478bd9Sstevel@tonic-gate 2069*7c478bd9Sstevel@tonic-gate rctl->rc_dict_entry = rctl_de; 2070*7c478bd9Sstevel@tonic-gate rctl->rc_values = rctl_val; 2071*7c478bd9Sstevel@tonic-gate 2072*7c478bd9Sstevel@tonic-gate /* 2073*7c478bd9Sstevel@tonic-gate * 1. Take global lock, validate nonexistence of name, get ID. 2074*7c478bd9Sstevel@tonic-gate */ 2075*7c478bd9Sstevel@tonic-gate mutex_enter(&rctl_dict_lock); 2076*7c478bd9Sstevel@tonic-gate 2077*7c478bd9Sstevel@tonic-gate if (mod_hash_find(rctl_dict_by_name, (mod_hash_key_t)name, 2078*7c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&rhndl) != MH_ERR_NOTFOUND) 2079*7c478bd9Sstevel@tonic-gate panic("duplicate registration of rctl %s", name); 2080*7c478bd9Sstevel@tonic-gate 2081*7c478bd9Sstevel@tonic-gate rhndl = rctl_de->rcd_id = rctl->rc_id = 2082*7c478bd9Sstevel@tonic-gate (rctl_hndl_t)id_alloc(rctl_ids); 2083*7c478bd9Sstevel@tonic-gate 2084*7c478bd9Sstevel@tonic-gate /* 2085*7c478bd9Sstevel@tonic-gate * 2. Insert name-entry pair in rctl_dict_by_name. 2086*7c478bd9Sstevel@tonic-gate */ 2087*7c478bd9Sstevel@tonic-gate if (mod_hash_insert(rctl_dict_by_name, (mod_hash_key_t)name, 2088*7c478bd9Sstevel@tonic-gate (mod_hash_val_t)rctl_de)) 2089*7c478bd9Sstevel@tonic-gate panic("unable to insert rctl dict entry for %s (%u)", name, 2090*7c478bd9Sstevel@tonic-gate (uint_t)rctl->rc_id); 2091*7c478bd9Sstevel@tonic-gate 2092*7c478bd9Sstevel@tonic-gate /* 2093*7c478bd9Sstevel@tonic-gate * 3. Insert ID-rctl_t * pair in rctl_dict. 2094*7c478bd9Sstevel@tonic-gate */ 2095*7c478bd9Sstevel@tonic-gate if (mod_hash_find(rctl_dict, (mod_hash_key_t)(uintptr_t)rctl->rc_id, 2096*7c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&old_rctl) != MH_ERR_NOTFOUND) 2097*7c478bd9Sstevel@tonic-gate panic("duplicate rctl ID %u registered", rctl->rc_id); 2098*7c478bd9Sstevel@tonic-gate 2099*7c478bd9Sstevel@tonic-gate if (mod_hash_insert(rctl_dict, (mod_hash_key_t)(uintptr_t)rctl->rc_id, 2100*7c478bd9Sstevel@tonic-gate (mod_hash_val_t)rctl)) 2101*7c478bd9Sstevel@tonic-gate panic("unable to insert rctl %s/%u (%p)", name, 2102*7c478bd9Sstevel@tonic-gate (uint_t)rctl->rc_id, rctl); 2103*7c478bd9Sstevel@tonic-gate 2104*7c478bd9Sstevel@tonic-gate /* 2105*7c478bd9Sstevel@tonic-gate * 3a. Insert rctl_dict_entry_t * in appropriate entity list. 2106*7c478bd9Sstevel@tonic-gate */ 2107*7c478bd9Sstevel@tonic-gate 2108*7c478bd9Sstevel@tonic-gate mutex_enter(&rctl_lists_lock); 2109*7c478bd9Sstevel@tonic-gate 2110*7c478bd9Sstevel@tonic-gate switch (entity) { 2111*7c478bd9Sstevel@tonic-gate case RCENTITY_ZONE: 2112*7c478bd9Sstevel@tonic-gate case RCENTITY_PROJECT: 2113*7c478bd9Sstevel@tonic-gate case RCENTITY_TASK: 2114*7c478bd9Sstevel@tonic-gate case RCENTITY_PROCESS: 2115*7c478bd9Sstevel@tonic-gate rctl_de->rcd_next = rctl_lists[entity]; 2116*7c478bd9Sstevel@tonic-gate rctl_lists[entity] = rctl_de; 2117*7c478bd9Sstevel@tonic-gate break; 2118*7c478bd9Sstevel@tonic-gate default: 2119*7c478bd9Sstevel@tonic-gate panic("registering unknown rctl entity %d (%s)", entity, 2120*7c478bd9Sstevel@tonic-gate name); 2121*7c478bd9Sstevel@tonic-gate break; 2122*7c478bd9Sstevel@tonic-gate } 2123*7c478bd9Sstevel@tonic-gate 2124*7c478bd9Sstevel@tonic-gate mutex_exit(&rctl_lists_lock); 2125*7c478bd9Sstevel@tonic-gate 2126*7c478bd9Sstevel@tonic-gate /* 2127*7c478bd9Sstevel@tonic-gate * 4. Drop lock. 2128*7c478bd9Sstevel@tonic-gate */ 2129*7c478bd9Sstevel@tonic-gate mutex_exit(&rctl_dict_lock); 2130*7c478bd9Sstevel@tonic-gate 2131*7c478bd9Sstevel@tonic-gate return (rhndl); 2132*7c478bd9Sstevel@tonic-gate } 2133*7c478bd9Sstevel@tonic-gate 2134*7c478bd9Sstevel@tonic-gate /* 2135*7c478bd9Sstevel@tonic-gate * static int rctl_global_action(rctl_t *r, rctl_set_t *rset, struct proc *p, 2136*7c478bd9Sstevel@tonic-gate * rctl_val_t *v) 2137*7c478bd9Sstevel@tonic-gate * 2138*7c478bd9Sstevel@tonic-gate * Overview 2139*7c478bd9Sstevel@tonic-gate * rctl_global_action() takes, in according with the flags on the rctl_dict 2140*7c478bd9Sstevel@tonic-gate * entry for the given control, the appropriate actions on the exceeded 2141*7c478bd9Sstevel@tonic-gate * control value. Additionally, rctl_global_action() updates the firing time 2142*7c478bd9Sstevel@tonic-gate * on the exceeded value. 2143*7c478bd9Sstevel@tonic-gate * 2144*7c478bd9Sstevel@tonic-gate * Return values 2145*7c478bd9Sstevel@tonic-gate * A bitmask reflecting the actions actually taken. 2146*7c478bd9Sstevel@tonic-gate * 2147*7c478bd9Sstevel@tonic-gate * Caller's context 2148*7c478bd9Sstevel@tonic-gate * No restrictions on context. 2149*7c478bd9Sstevel@tonic-gate */ 2150*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2151*7c478bd9Sstevel@tonic-gate static int 2152*7c478bd9Sstevel@tonic-gate rctl_global_action(rctl_t *r, rctl_set_t *rset, struct proc *p, rctl_val_t *v) 2153*7c478bd9Sstevel@tonic-gate { 2154*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde = r->rc_dict_entry; 2155*7c478bd9Sstevel@tonic-gate const char *pr, *en; 2156*7c478bd9Sstevel@tonic-gate id_t id; 2157*7c478bd9Sstevel@tonic-gate int ret = 0; 2158*7c478bd9Sstevel@tonic-gate 2159*7c478bd9Sstevel@tonic-gate v->rcv_firing_time = gethrtime(); 2160*7c478bd9Sstevel@tonic-gate 2161*7c478bd9Sstevel@tonic-gate switch (v->rcv_privilege) { 2162*7c478bd9Sstevel@tonic-gate case RCPRIV_BASIC: 2163*7c478bd9Sstevel@tonic-gate pr = "basic"; 2164*7c478bd9Sstevel@tonic-gate break; 2165*7c478bd9Sstevel@tonic-gate case RCPRIV_PRIVILEGED: 2166*7c478bd9Sstevel@tonic-gate pr = "privileged"; 2167*7c478bd9Sstevel@tonic-gate break; 2168*7c478bd9Sstevel@tonic-gate case RCPRIV_SYSTEM: 2169*7c478bd9Sstevel@tonic-gate pr = "system"; 2170*7c478bd9Sstevel@tonic-gate break; 2171*7c478bd9Sstevel@tonic-gate default: 2172*7c478bd9Sstevel@tonic-gate pr = "unknown"; 2173*7c478bd9Sstevel@tonic-gate break; 2174*7c478bd9Sstevel@tonic-gate } 2175*7c478bd9Sstevel@tonic-gate 2176*7c478bd9Sstevel@tonic-gate switch (rde->rcd_entity) { 2177*7c478bd9Sstevel@tonic-gate case RCENTITY_PROCESS: 2178*7c478bd9Sstevel@tonic-gate en = "process"; 2179*7c478bd9Sstevel@tonic-gate id = p->p_pid; 2180*7c478bd9Sstevel@tonic-gate break; 2181*7c478bd9Sstevel@tonic-gate case RCENTITY_TASK: 2182*7c478bd9Sstevel@tonic-gate en = "task"; 2183*7c478bd9Sstevel@tonic-gate id = p->p_task->tk_tkid; 2184*7c478bd9Sstevel@tonic-gate break; 2185*7c478bd9Sstevel@tonic-gate case RCENTITY_PROJECT: 2186*7c478bd9Sstevel@tonic-gate en = "project"; 2187*7c478bd9Sstevel@tonic-gate id = p->p_task->tk_proj->kpj_id; 2188*7c478bd9Sstevel@tonic-gate break; 2189*7c478bd9Sstevel@tonic-gate case RCENTITY_ZONE: 2190*7c478bd9Sstevel@tonic-gate en = "zone"; 2191*7c478bd9Sstevel@tonic-gate id = p->p_zone->zone_id; 2192*7c478bd9Sstevel@tonic-gate break; 2193*7c478bd9Sstevel@tonic-gate default: 2194*7c478bd9Sstevel@tonic-gate en = "unknown entity associated with pid"; 2195*7c478bd9Sstevel@tonic-gate id = p->p_pid; 2196*7c478bd9Sstevel@tonic-gate break; 2197*7c478bd9Sstevel@tonic-gate } 2198*7c478bd9Sstevel@tonic-gate 2199*7c478bd9Sstevel@tonic-gate if (rde->rcd_flagaction & RCTL_GLOBAL_SYSLOG) { 2200*7c478bd9Sstevel@tonic-gate (void) strlog(0, 0, 0, 2201*7c478bd9Sstevel@tonic-gate rde->rcd_strlog_flags | log_global.lz_active, 2202*7c478bd9Sstevel@tonic-gate "%s rctl %s (value %llu) exceeded by %s %d", pr, 2203*7c478bd9Sstevel@tonic-gate rde->rcd_name, v->rcv_value, en, id); 2204*7c478bd9Sstevel@tonic-gate } 2205*7c478bd9Sstevel@tonic-gate 2206*7c478bd9Sstevel@tonic-gate if (rde->rcd_flagaction & RCTL_GLOBAL_DENY_ALWAYS) 2207*7c478bd9Sstevel@tonic-gate ret |= RCT_DENY; 2208*7c478bd9Sstevel@tonic-gate 2209*7c478bd9Sstevel@tonic-gate return (ret); 2210*7c478bd9Sstevel@tonic-gate } 2211*7c478bd9Sstevel@tonic-gate 2212*7c478bd9Sstevel@tonic-gate static int 2213*7c478bd9Sstevel@tonic-gate rctl_local_action(rctl_t *r, rctl_set_t *rset, struct proc *p, rctl_val_t *v, 2214*7c478bd9Sstevel@tonic-gate uint_t safety) 2215*7c478bd9Sstevel@tonic-gate { 2216*7c478bd9Sstevel@tonic-gate int ret = 0; 2217*7c478bd9Sstevel@tonic-gate sigqueue_t *sqp = NULL; 2218*7c478bd9Sstevel@tonic-gate rctl_dict_entry_t *rde = r->rc_dict_entry; 2219*7c478bd9Sstevel@tonic-gate int unobservable = (rde->rcd_flagaction & RCTL_GLOBAL_UNOBSERVABLE); 2220*7c478bd9Sstevel@tonic-gate 2221*7c478bd9Sstevel@tonic-gate proc_t *recipient = v->rcv_action_recipient; 2222*7c478bd9Sstevel@tonic-gate id_t recip_pid = v->rcv_action_recip_pid; 2223*7c478bd9Sstevel@tonic-gate int recip_signal = v->rcv_action_signal; 2224*7c478bd9Sstevel@tonic-gate uint_t flagaction = v->rcv_flagaction; 2225*7c478bd9Sstevel@tonic-gate 2226*7c478bd9Sstevel@tonic-gate if (safety == RCA_UNSAFE_ALL) { 2227*7c478bd9Sstevel@tonic-gate if (flagaction & RCTL_LOCAL_DENY) { 2228*7c478bd9Sstevel@tonic-gate ret |= RCT_DENY; 2229*7c478bd9Sstevel@tonic-gate } 2230*7c478bd9Sstevel@tonic-gate return (ret); 2231*7c478bd9Sstevel@tonic-gate } 2232*7c478bd9Sstevel@tonic-gate 2233*7c478bd9Sstevel@tonic-gate if (flagaction & RCTL_LOCAL_SIGNAL) { 2234*7c478bd9Sstevel@tonic-gate /* 2235*7c478bd9Sstevel@tonic-gate * We can build a siginfo only in the case that it is 2236*7c478bd9Sstevel@tonic-gate * safe for us to drop p_lock. (For asynchronous 2237*7c478bd9Sstevel@tonic-gate * checks this is currently not true.) 2238*7c478bd9Sstevel@tonic-gate */ 2239*7c478bd9Sstevel@tonic-gate if (safety == RCA_SAFE) { 2240*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 2241*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 2242*7c478bd9Sstevel@tonic-gate sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP); 2243*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 2244*7c478bd9Sstevel@tonic-gate mutex_enter(&rset->rcs_lock); 2245*7c478bd9Sstevel@tonic-gate 2246*7c478bd9Sstevel@tonic-gate sqp->sq_info.si_signo = recip_signal; 2247*7c478bd9Sstevel@tonic-gate sqp->sq_info.si_code = SI_RCTL; 2248*7c478bd9Sstevel@tonic-gate sqp->sq_info.si_errno = 0; 2249*7c478bd9Sstevel@tonic-gate sqp->sq_info.si_entity = (int)rde->rcd_entity; 2250*7c478bd9Sstevel@tonic-gate } 2251*7c478bd9Sstevel@tonic-gate 2252*7c478bd9Sstevel@tonic-gate if (recipient == NULL || recipient == p) { 2253*7c478bd9Sstevel@tonic-gate ret |= RCT_SIGNAL; 2254*7c478bd9Sstevel@tonic-gate 2255*7c478bd9Sstevel@tonic-gate if (sqp == NULL) { 2256*7c478bd9Sstevel@tonic-gate sigtoproc(p, NULL, recip_signal); 2257*7c478bd9Sstevel@tonic-gate } else if (p == curproc) { 2258*7c478bd9Sstevel@tonic-gate /* 2259*7c478bd9Sstevel@tonic-gate * Then this is a synchronous test and we can 2260*7c478bd9Sstevel@tonic-gate * direct the signal at the violating thread. 2261*7c478bd9Sstevel@tonic-gate */ 2262*7c478bd9Sstevel@tonic-gate sigaddqa(curproc, curthread, sqp); 2263*7c478bd9Sstevel@tonic-gate } else { 2264*7c478bd9Sstevel@tonic-gate sigaddqa(p, NULL, sqp); 2265*7c478bd9Sstevel@tonic-gate } 2266*7c478bd9Sstevel@tonic-gate } else if (!unobservable) { 2267*7c478bd9Sstevel@tonic-gate proc_t *rp; 2268*7c478bd9Sstevel@tonic-gate 2269*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 2270*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 2271*7c478bd9Sstevel@tonic-gate 2272*7c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 2273*7c478bd9Sstevel@tonic-gate if ((rp = prfind(recip_pid)) == recipient) { 2274*7c478bd9Sstevel@tonic-gate /* 2275*7c478bd9Sstevel@tonic-gate * Recipient process is still alive, but may not 2276*7c478bd9Sstevel@tonic-gate * be in this task or project any longer. In 2277*7c478bd9Sstevel@tonic-gate * this case, the recipient's resource control 2278*7c478bd9Sstevel@tonic-gate * set pertinent to this control will have 2279*7c478bd9Sstevel@tonic-gate * changed--and we will not deliver the signal, 2280*7c478bd9Sstevel@tonic-gate * as the recipient process is trying to tear 2281*7c478bd9Sstevel@tonic-gate * itself off of its former set. 2282*7c478bd9Sstevel@tonic-gate */ 2283*7c478bd9Sstevel@tonic-gate mutex_enter(&rp->p_lock); 2284*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 2285*7c478bd9Sstevel@tonic-gate 2286*7c478bd9Sstevel@tonic-gate if (rctl_entity_obtain_rset(rde, rp) == rset) { 2287*7c478bd9Sstevel@tonic-gate ret |= RCT_SIGNAL; 2288*7c478bd9Sstevel@tonic-gate 2289*7c478bd9Sstevel@tonic-gate if (sqp == NULL) 2290*7c478bd9Sstevel@tonic-gate sigtoproc(rp, NULL, 2291*7c478bd9Sstevel@tonic-gate recip_signal); 2292*7c478bd9Sstevel@tonic-gate else 2293*7c478bd9Sstevel@tonic-gate sigaddqa(rp, NULL, sqp); 2294*7c478bd9Sstevel@tonic-gate } else if (sqp) { 2295*7c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t)); 2296*7c478bd9Sstevel@tonic-gate } 2297*7c478bd9Sstevel@tonic-gate mutex_exit(&rp->p_lock); 2298*7c478bd9Sstevel@tonic-gate } else { 2299*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 2300*7c478bd9Sstevel@tonic-gate if (sqp) 2301*7c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t)); 2302*7c478bd9Sstevel@tonic-gate } 2303*7c478bd9Sstevel@tonic-gate 2304*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 2305*7c478bd9Sstevel@tonic-gate /* 2306*7c478bd9Sstevel@tonic-gate * Since we dropped p_lock, we may no longer be in the 2307*7c478bd9Sstevel@tonic-gate * same task or project as we were at entry. It is thus 2308*7c478bd9Sstevel@tonic-gate * unsafe for us to reacquire the set lock at this 2309*7c478bd9Sstevel@tonic-gate * point; callers of rctl_local_action() must handle 2310*7c478bd9Sstevel@tonic-gate * this possibility. 2311*7c478bd9Sstevel@tonic-gate */ 2312*7c478bd9Sstevel@tonic-gate ret |= RCT_LK_ABANDONED; 2313*7c478bd9Sstevel@tonic-gate } else if (sqp) { 2314*7c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t)); 2315*7c478bd9Sstevel@tonic-gate } 2316*7c478bd9Sstevel@tonic-gate } 2317*7c478bd9Sstevel@tonic-gate 2318*7c478bd9Sstevel@tonic-gate if ((flagaction & RCTL_LOCAL_DENY) && 2319*7c478bd9Sstevel@tonic-gate (recipient == NULL || recipient == p)) { 2320*7c478bd9Sstevel@tonic-gate ret |= RCT_DENY; 2321*7c478bd9Sstevel@tonic-gate } 2322*7c478bd9Sstevel@tonic-gate 2323*7c478bd9Sstevel@tonic-gate return (ret); 2324*7c478bd9Sstevel@tonic-gate } 2325*7c478bd9Sstevel@tonic-gate 2326*7c478bd9Sstevel@tonic-gate /* 2327*7c478bd9Sstevel@tonic-gate * int rctl_action(rctl_hndl_t, rctl_set_t *, struct proc *, uint_t) 2328*7c478bd9Sstevel@tonic-gate * 2329*7c478bd9Sstevel@tonic-gate * Overview 2330*7c478bd9Sstevel@tonic-gate * Take the action associated with the enforced value (as defined by 2331*7c478bd9Sstevel@tonic-gate * rctl_get_enforced_value()) being exceeded or encountered. Possibly perform 2332*7c478bd9Sstevel@tonic-gate * a restricted subset of the available actions, if circumstances dictate that 2333*7c478bd9Sstevel@tonic-gate * we cannot safely allocate memory (for a sigqueue_t) or guarantee process 2334*7c478bd9Sstevel@tonic-gate * persistence across the duration of the function (an asynchronous action). 2335*7c478bd9Sstevel@tonic-gate * 2336*7c478bd9Sstevel@tonic-gate * Return values 2337*7c478bd9Sstevel@tonic-gate * Actions taken, according to the rctl_test bitmask. 2338*7c478bd9Sstevel@tonic-gate * 2339*7c478bd9Sstevel@tonic-gate * Caller's context 2340*7c478bd9Sstevel@tonic-gate * Safe to acquire rcs_lock. 2341*7c478bd9Sstevel@tonic-gate */ 2342*7c478bd9Sstevel@tonic-gate int 2343*7c478bd9Sstevel@tonic-gate rctl_action(rctl_hndl_t hndl, rctl_set_t *rset, struct proc *p, uint_t safety) 2344*7c478bd9Sstevel@tonic-gate { 2345*7c478bd9Sstevel@tonic-gate return (rctl_action_entity(hndl, rset, p, NULL, safety)); 2346*7c478bd9Sstevel@tonic-gate } 2347*7c478bd9Sstevel@tonic-gate 2348*7c478bd9Sstevel@tonic-gate int 2349*7c478bd9Sstevel@tonic-gate rctl_action_entity(rctl_hndl_t hndl, rctl_set_t *rset, struct proc *p, 2350*7c478bd9Sstevel@tonic-gate rctl_entity_p_t *e, uint_t safety) 2351*7c478bd9Sstevel@tonic-gate { 2352*7c478bd9Sstevel@tonic-gate int ret = RCT_NONE; 2353*7c478bd9Sstevel@tonic-gate rctl_t *lrctl; 2354*7c478bd9Sstevel@tonic-gate rctl_entity_p_t e_tmp; 2355*7c478bd9Sstevel@tonic-gate 2356*7c478bd9Sstevel@tonic-gate rctl_action_acquire: 2357*7c478bd9Sstevel@tonic-gate mutex_enter(&rset->rcs_lock); 2358*7c478bd9Sstevel@tonic-gate if (rctl_set_find(rset, hndl, &lrctl) == -1) { 2359*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 2360*7c478bd9Sstevel@tonic-gate return (ret); 2361*7c478bd9Sstevel@tonic-gate } 2362*7c478bd9Sstevel@tonic-gate 2363*7c478bd9Sstevel@tonic-gate if (e == NULL) { 2364*7c478bd9Sstevel@tonic-gate rctl_entity_obtain_entity_p(lrctl->rc_dict_entry->rcd_entity, 2365*7c478bd9Sstevel@tonic-gate p, &e_tmp); 2366*7c478bd9Sstevel@tonic-gate e = &e_tmp; 2367*7c478bd9Sstevel@tonic-gate } 2368*7c478bd9Sstevel@tonic-gate 2369*7c478bd9Sstevel@tonic-gate if ((ret & RCT_LK_ABANDONED) == 0) { 2370*7c478bd9Sstevel@tonic-gate ret |= rctl_global_action(lrctl, rset, p, lrctl->rc_cursor); 2371*7c478bd9Sstevel@tonic-gate 2372*7c478bd9Sstevel@tonic-gate RCTLOP_ACTION(lrctl, p, e); 2373*7c478bd9Sstevel@tonic-gate 2374*7c478bd9Sstevel@tonic-gate ret |= rctl_local_action(lrctl, rset, p, 2375*7c478bd9Sstevel@tonic-gate lrctl->rc_cursor, safety); 2376*7c478bd9Sstevel@tonic-gate 2377*7c478bd9Sstevel@tonic-gate if (ret & RCT_LK_ABANDONED) 2378*7c478bd9Sstevel@tonic-gate goto rctl_action_acquire; 2379*7c478bd9Sstevel@tonic-gate } 2380*7c478bd9Sstevel@tonic-gate 2381*7c478bd9Sstevel@tonic-gate ret &= ~RCT_LK_ABANDONED; 2382*7c478bd9Sstevel@tonic-gate 2383*7c478bd9Sstevel@tonic-gate if (!(ret & RCT_DENY) && 2384*7c478bd9Sstevel@tonic-gate lrctl->rc_cursor->rcv_next != NULL) { 2385*7c478bd9Sstevel@tonic-gate lrctl->rc_cursor = lrctl->rc_cursor->rcv_next; 2386*7c478bd9Sstevel@tonic-gate 2387*7c478bd9Sstevel@tonic-gate RCTLOP_SET(lrctl, p, e, rctl_model_value(lrctl->rc_dict_entry, 2388*7c478bd9Sstevel@tonic-gate p, lrctl->rc_cursor->rcv_value)); 2389*7c478bd9Sstevel@tonic-gate 2390*7c478bd9Sstevel@tonic-gate } 2391*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 2392*7c478bd9Sstevel@tonic-gate 2393*7c478bd9Sstevel@tonic-gate return (ret); 2394*7c478bd9Sstevel@tonic-gate } 2395*7c478bd9Sstevel@tonic-gate 2396*7c478bd9Sstevel@tonic-gate /* 2397*7c478bd9Sstevel@tonic-gate * int rctl_test(rctl_hndl_t, rctl_set_t *, struct proc *, rctl_qty_t, uint_t) 2398*7c478bd9Sstevel@tonic-gate * 2399*7c478bd9Sstevel@tonic-gate * Overview 2400*7c478bd9Sstevel@tonic-gate * Increment the resource associated with the given handle, returning zero if 2401*7c478bd9Sstevel@tonic-gate * the incremented value does not exceed the threshold for the current limit 2402*7c478bd9Sstevel@tonic-gate * on the resource. 2403*7c478bd9Sstevel@tonic-gate * 2404*7c478bd9Sstevel@tonic-gate * Return values 2405*7c478bd9Sstevel@tonic-gate * Actions taken, according to the rctl_test bitmask. 2406*7c478bd9Sstevel@tonic-gate * 2407*7c478bd9Sstevel@tonic-gate * Caller's context 2408*7c478bd9Sstevel@tonic-gate * p_lock held by caller. 2409*7c478bd9Sstevel@tonic-gate */ 2410*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2411*7c478bd9Sstevel@tonic-gate int 2412*7c478bd9Sstevel@tonic-gate rctl_test(rctl_hndl_t rhndl, rctl_set_t *rset, struct proc *p, 2413*7c478bd9Sstevel@tonic-gate rctl_qty_t incr, uint_t flags) 2414*7c478bd9Sstevel@tonic-gate { 2415*7c478bd9Sstevel@tonic-gate return (rctl_test_entity(rhndl, rset, p, NULL, incr, flags)); 2416*7c478bd9Sstevel@tonic-gate } 2417*7c478bd9Sstevel@tonic-gate 2418*7c478bd9Sstevel@tonic-gate int 2419*7c478bd9Sstevel@tonic-gate rctl_test_entity(rctl_hndl_t rhndl, rctl_set_t *rset, struct proc *p, 2420*7c478bd9Sstevel@tonic-gate rctl_entity_p_t *e, rctl_qty_t incr, uint_t flags) 2421*7c478bd9Sstevel@tonic-gate { 2422*7c478bd9Sstevel@tonic-gate rctl_t *lrctl; 2423*7c478bd9Sstevel@tonic-gate int ret = RCT_NONE; 2424*7c478bd9Sstevel@tonic-gate rctl_entity_p_t e_tmp; 2425*7c478bd9Sstevel@tonic-gate if (p == &p0) { 2426*7c478bd9Sstevel@tonic-gate /* 2427*7c478bd9Sstevel@tonic-gate * We don't enforce rctls on the kernel itself. 2428*7c478bd9Sstevel@tonic-gate */ 2429*7c478bd9Sstevel@tonic-gate return (ret); 2430*7c478bd9Sstevel@tonic-gate } 2431*7c478bd9Sstevel@tonic-gate 2432*7c478bd9Sstevel@tonic-gate rctl_test_acquire: 2433*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 2434*7c478bd9Sstevel@tonic-gate 2435*7c478bd9Sstevel@tonic-gate mutex_enter(&rset->rcs_lock); 2436*7c478bd9Sstevel@tonic-gate 2437*7c478bd9Sstevel@tonic-gate /* 2438*7c478bd9Sstevel@tonic-gate * Dereference from rctl_set. We don't enforce newly loaded controls 2439*7c478bd9Sstevel@tonic-gate * that haven't been set on this entity (since the only valid value is 2440*7c478bd9Sstevel@tonic-gate * the infinite system value). 2441*7c478bd9Sstevel@tonic-gate */ 2442*7c478bd9Sstevel@tonic-gate if (rctl_set_find(rset, rhndl, &lrctl) == -1) { 2443*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 2444*7c478bd9Sstevel@tonic-gate return (ret); 2445*7c478bd9Sstevel@tonic-gate } 2446*7c478bd9Sstevel@tonic-gate 2447*7c478bd9Sstevel@tonic-gate /* 2448*7c478bd9Sstevel@tonic-gate * This control is currently unenforced: maximal value on control 2449*7c478bd9Sstevel@tonic-gate * supporting infinitely available resource. 2450*7c478bd9Sstevel@tonic-gate */ 2451*7c478bd9Sstevel@tonic-gate if ((lrctl->rc_dict_entry->rcd_flagaction & RCTL_GLOBAL_INFINITE) && 2452*7c478bd9Sstevel@tonic-gate (lrctl->rc_cursor->rcv_flagaction & RCTL_LOCAL_MAXIMAL)) { 2453*7c478bd9Sstevel@tonic-gate 2454*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 2455*7c478bd9Sstevel@tonic-gate return (ret); 2456*7c478bd9Sstevel@tonic-gate } 2457*7c478bd9Sstevel@tonic-gate 2458*7c478bd9Sstevel@tonic-gate /* 2459*7c478bd9Sstevel@tonic-gate * If we have been called by rctl_test, look up the entity pointer 2460*7c478bd9Sstevel@tonic-gate * from the proc pointer. 2461*7c478bd9Sstevel@tonic-gate */ 2462*7c478bd9Sstevel@tonic-gate if (e == NULL) { 2463*7c478bd9Sstevel@tonic-gate rctl_entity_obtain_entity_p(lrctl->rc_dict_entry->rcd_entity, 2464*7c478bd9Sstevel@tonic-gate p, &e_tmp); 2465*7c478bd9Sstevel@tonic-gate e = &e_tmp; 2466*7c478bd9Sstevel@tonic-gate } 2467*7c478bd9Sstevel@tonic-gate 2468*7c478bd9Sstevel@tonic-gate /* 2469*7c478bd9Sstevel@tonic-gate * Get enforced rctl value and current usage. Test the increment 2470*7c478bd9Sstevel@tonic-gate * with the current usage against the enforced value--take action as 2471*7c478bd9Sstevel@tonic-gate * necessary. 2472*7c478bd9Sstevel@tonic-gate */ 2473*7c478bd9Sstevel@tonic-gate while (RCTLOP_TEST(lrctl, p, e, lrctl->rc_cursor, incr, flags)) { 2474*7c478bd9Sstevel@tonic-gate if ((ret & RCT_LK_ABANDONED) == 0) { 2475*7c478bd9Sstevel@tonic-gate ret |= rctl_global_action(lrctl, rset, p, 2476*7c478bd9Sstevel@tonic-gate lrctl->rc_cursor); 2477*7c478bd9Sstevel@tonic-gate 2478*7c478bd9Sstevel@tonic-gate RCTLOP_ACTION(lrctl, p, e); 2479*7c478bd9Sstevel@tonic-gate 2480*7c478bd9Sstevel@tonic-gate ret |= rctl_local_action(lrctl, rset, p, 2481*7c478bd9Sstevel@tonic-gate lrctl->rc_cursor, flags); 2482*7c478bd9Sstevel@tonic-gate 2483*7c478bd9Sstevel@tonic-gate if (ret & RCT_LK_ABANDONED) 2484*7c478bd9Sstevel@tonic-gate goto rctl_test_acquire; 2485*7c478bd9Sstevel@tonic-gate } 2486*7c478bd9Sstevel@tonic-gate 2487*7c478bd9Sstevel@tonic-gate ret &= ~RCT_LK_ABANDONED; 2488*7c478bd9Sstevel@tonic-gate 2489*7c478bd9Sstevel@tonic-gate if ((ret & RCT_DENY) == RCT_DENY || 2490*7c478bd9Sstevel@tonic-gate lrctl->rc_cursor->rcv_next == NULL) { 2491*7c478bd9Sstevel@tonic-gate ret |= RCT_DENY; 2492*7c478bd9Sstevel@tonic-gate break; 2493*7c478bd9Sstevel@tonic-gate } 2494*7c478bd9Sstevel@tonic-gate 2495*7c478bd9Sstevel@tonic-gate lrctl->rc_cursor = lrctl->rc_cursor->rcv_next; 2496*7c478bd9Sstevel@tonic-gate RCTLOP_SET(lrctl, p, e, rctl_model_value(lrctl->rc_dict_entry, 2497*7c478bd9Sstevel@tonic-gate p, lrctl->rc_cursor->rcv_value)); 2498*7c478bd9Sstevel@tonic-gate } 2499*7c478bd9Sstevel@tonic-gate 2500*7c478bd9Sstevel@tonic-gate mutex_exit(&rset->rcs_lock); 2501*7c478bd9Sstevel@tonic-gate 2502*7c478bd9Sstevel@tonic-gate return (ret); 2503*7c478bd9Sstevel@tonic-gate } 2504*7c478bd9Sstevel@tonic-gate 2505*7c478bd9Sstevel@tonic-gate /* 2506*7c478bd9Sstevel@tonic-gate * void rctl_init(void) 2507*7c478bd9Sstevel@tonic-gate * 2508*7c478bd9Sstevel@tonic-gate * Overview 2509*7c478bd9Sstevel@tonic-gate * Initialize the rctl subsystem, including the primoridal rctls 2510*7c478bd9Sstevel@tonic-gate * provided by the system. New subsystem-specific rctls should _not_ be 2511*7c478bd9Sstevel@tonic-gate * initialized here. (Do it in your own file.) 2512*7c478bd9Sstevel@tonic-gate * 2513*7c478bd9Sstevel@tonic-gate * Return values 2514*7c478bd9Sstevel@tonic-gate * None. 2515*7c478bd9Sstevel@tonic-gate * 2516*7c478bd9Sstevel@tonic-gate * Caller's context 2517*7c478bd9Sstevel@tonic-gate * Safe for KM_SLEEP allocations. Must be called prior to any process model 2518*7c478bd9Sstevel@tonic-gate * initialization. 2519*7c478bd9Sstevel@tonic-gate */ 2520*7c478bd9Sstevel@tonic-gate void 2521*7c478bd9Sstevel@tonic-gate rctl_init(void) 2522*7c478bd9Sstevel@tonic-gate { 2523*7c478bd9Sstevel@tonic-gate rctl_cache = kmem_cache_create("rctl_cache", sizeof (rctl_t), 2524*7c478bd9Sstevel@tonic-gate 0, NULL, NULL, NULL, NULL, NULL, 0); 2525*7c478bd9Sstevel@tonic-gate rctl_val_cache = kmem_cache_create("rctl_val_cache", 2526*7c478bd9Sstevel@tonic-gate sizeof (rctl_val_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 2527*7c478bd9Sstevel@tonic-gate 2528*7c478bd9Sstevel@tonic-gate rctl_dict = mod_hash_create_extended("rctl_dict", 2529*7c478bd9Sstevel@tonic-gate rctl_dict_size, mod_hash_null_keydtor, rctl_dict_val_dtor, 2530*7c478bd9Sstevel@tonic-gate rctl_dict_hash_by_id, NULL, rctl_dict_id_cmp, KM_SLEEP); 2531*7c478bd9Sstevel@tonic-gate rctl_dict_by_name = mod_hash_create_strhash( 2532*7c478bd9Sstevel@tonic-gate "rctl_handles_by_name", rctl_dict_size, 2533*7c478bd9Sstevel@tonic-gate mod_hash_null_valdtor); 2534*7c478bd9Sstevel@tonic-gate rctl_ids = id_space_create("rctl_ids", 1, max_rctl_hndl); 2535*7c478bd9Sstevel@tonic-gate bzero(rctl_lists, (RC_MAX_ENTITY + 1) * sizeof (rctl_dict_entry_t *)); 2536*7c478bd9Sstevel@tonic-gate 2537*7c478bd9Sstevel@tonic-gate rctlproc_init(); 2538*7c478bd9Sstevel@tonic-gate } 2539