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