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