xref: /illumos-gate/usr/src/uts/common/os/project.c (revision 532877c4)
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 2007 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/project.h>
29 #include <sys/modhash.h>
30 #include <sys/modctl.h>
31 #include <sys/kmem.h>
32 #include <sys/kstat.h>
33 #include <sys/atomic.h>
34 #include <sys/cmn_err.h>
35 #include <sys/proc.h>
36 #include <sys/rctl.h>
37 #include <sys/sunddi.h>
38 #include <sys/fss.h>
39 #include <sys/systm.h>
40 #include <sys/ipc_impl.h>
41 #include <sys/port_kernel.h>
42 #include <sys/task.h>
43 #include <sys/zone.h>
44 
45 int project_hash_size = 64;
46 static kmutex_t project_hash_lock;
47 static kmutex_t projects_list_lock;
48 static mod_hash_t *projects_hash;
49 static kproject_t *projects_list;
50 
51 rctl_hndl_t rc_project_cpu_shares;
52 rctl_hndl_t rc_project_nlwps;
53 rctl_hndl_t rc_project_ntasks;
54 rctl_hndl_t rc_project_msgmni;
55 rctl_hndl_t rc_project_semmni;
56 rctl_hndl_t rc_project_shmmax;
57 rctl_hndl_t rc_project_shmmni;
58 rctl_hndl_t rc_project_portids;
59 rctl_hndl_t rc_project_locked_mem;
60 rctl_hndl_t rc_project_contract;
61 rctl_hndl_t rc_project_crypto_mem;
62 
63 /*
64  * Dummy structure used when comparing projects.  This structure must be kept
65  * identical to the first two fields of kproject_t.
66  */
67 struct project_zone {
68 	projid_t	kpj_id;
69 	zoneid_t	kpj_zoneid;
70 };
71 
72 /*
73  * Projects
74  *
75  *   A dictionary of all active projects is maintained by the kernel so that we
76  *   may track project usage and limits.  (By an active project, we mean a
77  *   project associated with one or more task, and therefore with one or more
78  *   processes.) We build the dictionary on top of the mod_hash facility, since
79  *   project additions and deletions are relatively rare events.  An
80  *   integer-to-pointer mapping is maintained within the hash, representing the
81  *   map from project id to project structure.  All projects, including the
82  *   primordial "project 0", are allocated via the project_hold_by_id()
83  *   interface.
84  *
85  *   Currently, the project contains a reference count; the project ID, which is
86  *   examined by the extended accounting subsystem as well as /proc; a resource
87  *   control set, which contains the allowable values (and actions on exceeding
88  *   those values) for controlled project-level resources on the system; and a
89  *   number of CPU shares, which is used by the fair share scheduling class
90  *   (FSS) to support its proportion-based scheduling algorithm.
91  *
92  * Reference counting convention
93  *   The dictionary entry does not itself count as a reference--only references
94  *   outside of the subsystem are tallied.  At the drop of the final external
95  *   reference, the project entry is removed.  The reference counter keeps
96  *   track of the number of threads *and* tasks within a project.
97  *
98  * Locking
99  *   Walking the doubly-linked project list must be done while holding
100  *   projects_list_lock.  Thus, any dereference of kpj_next or kpj_prev must be
101  *   under projects_list_lock.
102  *
103  *   If both the hash lock, project_hash_lock, and the list lock are to be
104  *   acquired, the hash lock is to be acquired first.
105  */
106 
107 static kstat_t *project_kstat_create(kproject_t *pj, zone_t *zone);
108 static void project_kstat_delete(kproject_t *pj);
109 
110 static void
111 project_data_init(kproject_data_t *data)
112 {
113 	/*
114 	 * Initialize subsystem-specific data
115 	 */
116 	data->kpd_shmmax = 0;
117 	data->kpd_ipc.ipcq_shmmni = 0;
118 	data->kpd_ipc.ipcq_semmni = 0;
119 	data->kpd_ipc.ipcq_msgmni = 0;
120 	data->kpd_locked_mem = 0;
121 	data->kpd_locked_mem_ctl = UINT64_MAX;
122 	data->kpd_contract = 0;
123 	data->kpd_crypto_mem = 0;
124 	data->kpd_crypto_mem_ctl = UINT64_MAX;
125 	data->kpd_lockedmem_kstat = NULL;
126 }
127 
128 /*ARGSUSED*/
129 static uint_t
130 project_hash_by_id(void *hash_data, mod_hash_key_t key)
131 {
132 	struct project_zone *pz = key;
133 	uint_t mykey;
134 
135 	/*
136 	 * Merge the zoneid and projectid together to a 32-bit quantity, and
137 	 * then pass that in to the existing idhash.
138 	 */
139 	mykey = (pz->kpj_zoneid << 16) | pz->kpj_id;
140 	return (mod_hash_byid(hash_data, (mod_hash_key_t)(uintptr_t)mykey));
141 }
142 
143 static int
144 project_hash_key_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
145 {
146 	struct project_zone *pz1 = key1, *pz2 = key2;
147 	int retval;
148 
149 	return ((int)((retval = pz1->kpj_id - pz2->kpj_id) != 0 ? retval :
150 	    pz1->kpj_zoneid - pz2->kpj_zoneid));
151 }
152 
153 static void
154 project_hash_val_dtor(mod_hash_val_t val)
155 {
156 	kproject_t *kp = (kproject_t *)val;
157 
158 	ASSERT(kp->kpj_count == 0);
159 	kmem_free(kp, sizeof (kproject_t));
160 }
161 
162 /*
163  * kproject_t *project_hold(kproject_t *)
164  *
165  * Overview
166  *   Record that an additional reference on the indicated project has been
167  *   taken.
168  *
169  * Return values
170  *   A pointer to the indicated project.
171  *
172  * Caller's context
173  *   project_hash_lock must not be held across the project_hold() call.
174  */
175 kproject_t *
176 project_hold(kproject_t *p)
177 {
178 	mutex_enter(&project_hash_lock);
179 	ASSERT(p != NULL);
180 	p->kpj_count++;
181 	ASSERT(p->kpj_count != 0);
182 	mutex_exit(&project_hash_lock);
183 	return (p);
184 }
185 
186 /*
187  * kproject_t *project_hold_by_id(projid_t, zone_t *, int)
188  *
189  * Overview
190  *   project_hold_by_id() performs a look-up in the dictionary of projects
191  *   active on the system by specified project ID + zone and puts a hold on
192  *   it.  The third argument defines the desired behavior in the case when
193  *   project with given project ID cannot be found:
194  *
195  *   PROJECT_HOLD_INSERT	New entry is made in dictionary and the project
196  *   				is added to the global list.
197  *
198  *   PROJECT_HOLD_FIND		Return NULL.
199  *
200  *   The project is returned with its reference count incremented by one.
201  *   A new project derives its resource controls from those of project 0.
202  *
203  * Return values
204  *   A pointer to the held project.
205  *
206  * Caller's context
207  *   Caller must be in a context suitable for KM_SLEEP allocations.
208  */
209 kproject_t *
210 project_hold_by_id(projid_t id, zone_t *zone, int flag)
211 {
212 	kproject_t *spare_p;
213 	kproject_t *p;
214 	mod_hash_hndl_t hndl;
215 	rctl_set_t *set;
216 	rctl_alloc_gp_t *gp;
217 	rctl_entity_p_t e;
218 	struct project_zone pz;
219 	boolean_t create = B_FALSE;
220 	kstat_t *ksp;
221 
222 	pz.kpj_id = id;
223 	pz.kpj_zoneid = zone->zone_id;
224 
225 	if (flag == PROJECT_HOLD_FIND) {
226 		mutex_enter(&project_hash_lock);
227 
228 		if (mod_hash_find(projects_hash, (mod_hash_key_t)&pz,
229 		    (mod_hash_val_t)&p) == MH_ERR_NOTFOUND)
230 			p = NULL;
231 		else
232 			p->kpj_count++;
233 
234 		mutex_exit(&project_hash_lock);
235 		return (p);
236 	}
237 
238 	ASSERT(flag == PROJECT_HOLD_INSERT);
239 
240 	spare_p = kmem_zalloc(sizeof (kproject_t), KM_SLEEP);
241 	set = rctl_set_create();
242 
243 	gp = rctl_set_init_prealloc(RCENTITY_PROJECT);
244 
245 	(void) mod_hash_reserve(projects_hash, &hndl);
246 
247 	mutex_enter(&curproc->p_lock);
248 	mutex_enter(&project_hash_lock);
249 	if (mod_hash_find(projects_hash, (mod_hash_key_t)&pz,
250 	    (mod_hash_val_t *)&p) == MH_ERR_NOTFOUND) {
251 
252 		p = spare_p;
253 		p->kpj_id = id;
254 		p->kpj_zoneid = zone->zone_id;
255 		p->kpj_count = 0;
256 		p->kpj_shares = 1;
257 		p->kpj_nlwps = 0;
258 		p->kpj_ntasks = 0;
259 		p->kpj_nlwps_ctl = INT_MAX;
260 		p->kpj_ntasks_ctl = INT_MAX;
261 		project_data_init(&p->kpj_data);
262 		e.rcep_p.proj = p;
263 		e.rcep_t = RCENTITY_PROJECT;
264 		p->kpj_rctls = rctl_set_init(RCENTITY_PROJECT, curproc, &e,
265 		    set, gp);
266 		mutex_exit(&curproc->p_lock);
267 
268 		if (mod_hash_insert_reserve(projects_hash, (mod_hash_key_t)p,
269 		    (mod_hash_val_t)p, hndl))
270 			panic("unable to insert project %d(%p)", id, (void *)p);
271 
272 		/*
273 		 * Insert project into global project list.
274 		 */
275 		mutex_enter(&projects_list_lock);
276 		if (id != 0 || zone != &zone0) {
277 			p->kpj_next = projects_list;
278 			p->kpj_prev = projects_list->kpj_prev;
279 			p->kpj_prev->kpj_next = p;
280 			projects_list->kpj_prev = p;
281 		} else {
282 			/*
283 			 * Special case: primordial hold on project 0.
284 			 */
285 			p->kpj_next = p;
286 			p->kpj_prev = p;
287 			projects_list = p;
288 		}
289 		mutex_exit(&projects_list_lock);
290 		create = B_TRUE;
291 	} else {
292 		mutex_exit(&curproc->p_lock);
293 		mod_hash_cancel(projects_hash, &hndl);
294 		kmem_free(spare_p, sizeof (kproject_t));
295 		rctl_set_free(set);
296 	}
297 
298 	rctl_prealloc_destroy(gp);
299 	p->kpj_count++;
300 	mutex_exit(&project_hash_lock);
301 
302 	/*
303 	 * The kstat stores the project's zone name, as zoneid's may change
304 	 * across reboots.
305 	 */
306 	if (create == B_TRUE) {
307 		ksp = project_kstat_create(p, zone);
308 		mutex_enter(&project_hash_lock);
309 		ASSERT(p->kpj_data.kpd_lockedmem_kstat == NULL);
310 		p->kpj_data.kpd_lockedmem_kstat = ksp;
311 		mutex_exit(&project_hash_lock);
312 	}
313 	return (p);
314 }
315 
316 /*
317  * void project_rele(kproject_t *)
318  *
319  * Overview
320  *   Advertise that one external reference to this project is no longer needed.
321  *
322  * Return values
323  *   None.
324  *
325  * Caller's context
326  *   No restriction on context.
327  */
328 void
329 project_rele(kproject_t *p)
330 {
331 	mutex_enter(&project_hash_lock);
332 	ASSERT(p->kpj_count != 0);
333 	p->kpj_count--;
334 	if (p->kpj_count == 0) {
335 
336 		/*
337 		 * Remove project from global list.
338 		 */
339 		mutex_enter(&projects_list_lock);
340 		p->kpj_next->kpj_prev = p->kpj_prev;
341 		p->kpj_prev->kpj_next = p->kpj_next;
342 		if (projects_list == p)
343 			projects_list = p->kpj_next;
344 		mutex_exit(&projects_list_lock);
345 
346 		rctl_set_free(p->kpj_rctls);
347 		project_kstat_delete(p);
348 
349 		if (mod_hash_destroy(projects_hash, (mod_hash_key_t)p))
350 			panic("unable to delete project %d zone %d", p->kpj_id,
351 			    p->kpj_zoneid);
352 
353 		}
354 	mutex_exit(&project_hash_lock);
355 }
356 
357 /*
358  * int project_walk_all(zoneid_t, int (*)(kproject_t *, void *), void *)
359  *
360  * Overview
361  *   Walk the project list for the given zoneid with a callback.
362  *
363  * Return values
364  *   -1 for an invalid walk, number of projects visited otherwise.
365  *
366  * Caller's context
367  *   projects_list_lock must not be held, as it is acquired by
368  *   project_walk_all().  Accordingly, callbacks may not perform KM_SLEEP
369  *   allocations.
370  */
371 int
372 project_walk_all(zoneid_t zoneid, int (*cb)(kproject_t *, void *),
373     void *walk_data)
374 {
375 	int cnt = 0;
376 	kproject_t *kp = proj0p;
377 
378 	mutex_enter(&projects_list_lock);
379 	do {
380 		if (zoneid != ALL_ZONES && kp->kpj_zoneid != zoneid)
381 			continue;
382 		if (cb(kp, walk_data) == -1) {
383 			cnt = -1;
384 			break;
385 		} else {
386 			cnt++;
387 		}
388 	} while ((kp = kp->kpj_next) != proj0p);
389 	mutex_exit(&projects_list_lock);
390 	return (cnt);
391 }
392 
393 /*
394  * projid_t curprojid(void)
395  *
396  * Overview
397  *   Return project ID of the current thread
398  *
399  * Caller's context
400  *   No restrictions.
401  */
402 projid_t
403 curprojid()
404 {
405 	return (ttoproj(curthread)->kpj_id);
406 }
407 
408 /*
409  * project.cpu-shares resource control support.
410  */
411 /*ARGSUSED*/
412 static rctl_qty_t
413 project_cpu_shares_usage(rctl_t *rctl, struct proc *p)
414 {
415 	ASSERT(MUTEX_HELD(&p->p_lock));
416 	return (p->p_task->tk_proj->kpj_shares);
417 }
418 
419 /*ARGSUSED*/
420 static int
421 project_cpu_shares_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
422     rctl_qty_t nv)
423 {
424 	ASSERT(MUTEX_HELD(&p->p_lock));
425 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
426 	if (e->rcep_p.proj == NULL)
427 		return (0);
428 
429 	e->rcep_p.proj->kpj_shares = nv;
430 
431 	return (0);
432 }
433 
434 
435 static rctl_ops_t project_cpu_shares_ops = {
436 	rcop_no_action,
437 	project_cpu_shares_usage,
438 	project_cpu_shares_set,
439 	rcop_no_test
440 };
441 
442 /*ARGSUSED*/
443 static rctl_qty_t
444 project_lwps_usage(rctl_t *r, proc_t *p)
445 {
446 	kproject_t *pj;
447 	rctl_qty_t nlwps;
448 
449 	ASSERT(MUTEX_HELD(&p->p_lock));
450 	pj = p->p_task->tk_proj;
451 	mutex_enter(&p->p_zone->zone_nlwps_lock);
452 	nlwps = pj->kpj_nlwps;
453 	mutex_exit(&p->p_zone->zone_nlwps_lock);
454 
455 	return (nlwps);
456 }
457 
458 /*ARGSUSED*/
459 static int
460 project_lwps_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, rctl_val_t *rcntl,
461     rctl_qty_t incr, uint_t flags)
462 {
463 	rctl_qty_t nlwps;
464 
465 	ASSERT(MUTEX_HELD(&p->p_lock));
466 	ASSERT(MUTEX_HELD(&p->p_zone->zone_nlwps_lock));
467 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
468 	if (e->rcep_p.proj == NULL)
469 		return (0);
470 
471 	nlwps = e->rcep_p.proj->kpj_nlwps;
472 	if (nlwps + incr > rcntl->rcv_value)
473 		return (1);
474 
475 	return (0);
476 }
477 
478 /*ARGSUSED*/
479 static int
480 project_lwps_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
481     rctl_qty_t nv) {
482 
483 	ASSERT(MUTEX_HELD(&p->p_lock));
484 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
485 	if (e->rcep_p.proj == NULL)
486 		return (0);
487 
488 	e->rcep_p.proj->kpj_nlwps_ctl = nv;
489 	return (0);
490 }
491 
492 static rctl_ops_t project_lwps_ops = {
493 	rcop_no_action,
494 	project_lwps_usage,
495 	project_lwps_set,
496 	project_lwps_test,
497 };
498 
499 /*ARGSUSED*/
500 static rctl_qty_t
501 project_ntasks_usage(rctl_t *r, proc_t *p)
502 {
503 	kproject_t *pj;
504 	rctl_qty_t ntasks;
505 
506 	ASSERT(MUTEX_HELD(&p->p_lock));
507 	pj = p->p_task->tk_proj;
508 	mutex_enter(&p->p_zone->zone_nlwps_lock);
509 	ntasks = pj->kpj_ntasks;
510 	mutex_exit(&p->p_zone->zone_nlwps_lock);
511 
512 	return (ntasks);
513 }
514 
515 /*ARGSUSED*/
516 static int
517 project_ntasks_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, rctl_val_t *rcntl,
518     rctl_qty_t incr, uint_t flags)
519 {
520 	rctl_qty_t ntasks;
521 
522 	ASSERT(MUTEX_HELD(&p->p_lock));
523 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
524 	ntasks = e->rcep_p.proj->kpj_ntasks;
525 	if (ntasks + incr > rcntl->rcv_value)
526 		return (1);
527 
528 	return (0);
529 }
530 
531 /*ARGSUSED*/
532 static int
533 project_ntasks_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
534     rctl_qty_t nv) {
535 
536 	ASSERT(MUTEX_HELD(&p->p_lock));
537 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
538 	e->rcep_p.proj->kpj_ntasks_ctl = nv;
539 	return (0);
540 }
541 
542 static rctl_ops_t project_tasks_ops = {
543 	rcop_no_action,
544 	project_ntasks_usage,
545 	project_ntasks_set,
546 	project_ntasks_test,
547 };
548 
549 /*
550  * project.max-shm-memory resource control support.
551  */
552 
553 /*ARGSUSED*/
554 static int
555 project_shmmax_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
556     rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
557 {
558 	rctl_qty_t v;
559 	ASSERT(MUTEX_HELD(&p->p_lock));
560 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
561 	v = e->rcep_p.proj->kpj_data.kpd_shmmax + inc;
562 	if (v > rval->rcv_value)
563 		return (1);
564 
565 	return (0);
566 }
567 
568 static rctl_ops_t project_shmmax_ops = {
569 	rcop_no_action,
570 	rcop_no_usage,
571 	rcop_no_set,
572 	project_shmmax_test
573 };
574 
575 /*
576  * project.max-shm-ids resource control support.
577  */
578 
579 /*ARGSUSED*/
580 static int
581 project_shmmni_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
582     rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
583 {
584 	rctl_qty_t v;
585 	ASSERT(MUTEX_HELD(&p->p_lock));
586 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
587 	v = e->rcep_p.proj->kpj_data.kpd_ipc.ipcq_shmmni + inc;
588 	if (v > rval->rcv_value)
589 		return (1);
590 
591 	return (0);
592 }
593 
594 static rctl_ops_t project_shmmni_ops = {
595 	rcop_no_action,
596 	rcop_no_usage,
597 	rcop_no_set,
598 	project_shmmni_test
599 };
600 
601 /*
602  * project.max-sem-ids resource control support.
603  */
604 
605 /*ARGSUSED*/
606 static int
607 project_semmni_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
608     rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
609 {
610 	rctl_qty_t v;
611 	ASSERT(MUTEX_HELD(&p->p_lock));
612 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
613 	v = e->rcep_p.proj->kpj_data.kpd_ipc.ipcq_semmni + inc;
614 	if (v > rval->rcv_value)
615 		return (1);
616 
617 	return (0);
618 }
619 
620 static rctl_ops_t project_semmni_ops = {
621 	rcop_no_action,
622 	rcop_no_usage,
623 	rcop_no_set,
624 	project_semmni_test
625 };
626 
627 /*
628  * project.max-msg-ids resource control support.
629  */
630 
631 /*ARGSUSED*/
632 static int
633 project_msgmni_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
634     rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
635 {
636 	rctl_qty_t v;
637 	ASSERT(MUTEX_HELD(&p->p_lock));
638 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
639 	v = e->rcep_p.proj->kpj_data.kpd_ipc.ipcq_msgmni + inc;
640 	if (v > rval->rcv_value)
641 		return (1);
642 
643 	return (0);
644 }
645 
646 static rctl_ops_t project_msgmni_ops = {
647 	rcop_no_action,
648 	rcop_no_usage,
649 	rcop_no_set,
650 	project_msgmni_test
651 };
652 
653 /*ARGSUSED*/
654 static rctl_qty_t
655 project_locked_mem_usage(rctl_t *rctl, struct proc *p)
656 {
657 	rctl_qty_t q;
658 	ASSERT(MUTEX_HELD(&p->p_lock));
659 	mutex_enter(&p->p_zone->zone_mem_lock);
660 	q = p->p_task->tk_proj->kpj_data.kpd_locked_mem;
661 	mutex_exit(&p->p_zone->zone_mem_lock);
662 	return (q);
663 }
664 
665 /*ARGSUSED*/
666 static int
667 project_locked_mem_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
668     rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
669 {
670 	rctl_qty_t q;
671 	ASSERT(MUTEX_HELD(&p->p_lock));
672 	ASSERT(MUTEX_HELD(&p->p_zone->zone_mem_lock));
673 	q = p->p_task->tk_proj->kpj_data.kpd_locked_mem;
674 	if (q + inc > rval->rcv_value)
675 		return (1);
676 	return (0);
677 }
678 
679 /*ARGSUSED*/
680 static int
681 project_locked_mem_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
682     rctl_qty_t nv) {
683 
684 	ASSERT(MUTEX_HELD(&p->p_lock));
685 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
686 	if (e->rcep_p.proj == NULL)
687 		return (0);
688 
689 	e->rcep_p.proj->kpj_data.kpd_locked_mem_ctl = nv;
690 	return (0);
691 }
692 
693 static rctl_ops_t project_locked_mem_ops = {
694 	rcop_no_action,
695 	project_locked_mem_usage,
696 	project_locked_mem_set,
697 	project_locked_mem_test
698 };
699 
700 /*
701  * project.max-contracts resource control support.
702  */
703 
704 /*ARGSUSED*/
705 static int
706 project_contract_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
707     rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
708 {
709 	rctl_qty_t v;
710 
711 	ASSERT(MUTEX_HELD(&p->p_lock));
712 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
713 
714 	v = e->rcep_p.proj->kpj_data.kpd_contract + inc;
715 
716 	if ((p->p_task != NULL) && (p->p_task->tk_proj) != NULL &&
717 	    (v > rval->rcv_value))
718 		return (1);
719 
720 	return (0);
721 }
722 
723 static rctl_ops_t project_contract_ops = {
724 	rcop_no_action,
725 	rcop_no_usage,
726 	rcop_no_set,
727 	project_contract_test
728 };
729 
730 /*ARGSUSED*/
731 static rctl_qty_t
732 project_crypto_usage(rctl_t *r, proc_t *p)
733 {
734 	ASSERT(MUTEX_HELD(&p->p_lock));
735 	return (p->p_task->tk_proj->kpj_data.kpd_crypto_mem);
736 }
737 
738 /*ARGSUSED*/
739 static int
740 project_crypto_set(rctl_t *r, proc_t *p, rctl_entity_p_t *e,
741     rctl_qty_t nv)
742 {
743 	ASSERT(MUTEX_HELD(&p->p_lock));
744 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
745 	if (e->rcep_p.proj == NULL)
746 		return (0);
747 
748 	e->rcep_p.proj->kpj_data.kpd_crypto_mem_ctl = nv;
749 	return (0);
750 }
751 
752 /*ARGSUSED*/
753 static int
754 project_crypto_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e,
755     rctl_val_t *rval, rctl_qty_t incr, uint_t flags)
756 {
757 	rctl_qty_t v;
758 	ASSERT(MUTEX_HELD(&p->p_lock));
759 	ASSERT(e->rcep_t == RCENTITY_PROJECT);
760 	v = e->rcep_p.proj->kpj_data.kpd_crypto_mem + incr;
761 	if (v > rval->rcv_value)
762 		return (1);
763 	return (0);
764 }
765 
766 static rctl_ops_t project_crypto_mem_ops = {
767 	rcop_no_action,
768 	project_crypto_usage,
769 	project_crypto_set,
770 	project_crypto_test
771 };
772 
773 /*
774  * void project_init(void)
775  *
776  * Overview
777  *   Initialize the project subsystem, including the primordial project 0 entry.
778  *   Register generic project resource controls, if any.
779  *
780  * Return values
781  *   None.
782  *
783  * Caller's context
784  *   Safe for KM_SLEEP allocations.
785  */
786 void
787 project_init(void)
788 {
789 	rctl_qty_t shmmni, shmmax, qty;
790 	boolean_t check;
791 
792 	projects_hash = mod_hash_create_extended("projects_hash",
793 	    project_hash_size, mod_hash_null_keydtor, project_hash_val_dtor,
794 	    project_hash_by_id,
795 	    (void *)(uintptr_t)mod_hash_iddata_gen(project_hash_size),
796 	    project_hash_key_cmp, KM_SLEEP);
797 
798 	rc_project_cpu_shares = rctl_register("project.cpu-shares",
799 	    RCENTITY_PROJECT, RCTL_GLOBAL_SIGNAL_NEVER |
800 	    RCTL_GLOBAL_DENY_NEVER | RCTL_GLOBAL_NOBASIC |
801 	    RCTL_GLOBAL_COUNT | RCTL_GLOBAL_SYSLOG_NEVER,
802 	    FSS_MAXSHARES, FSS_MAXSHARES,
803 	    &project_cpu_shares_ops);
804 	rctl_add_default_limit("project.cpu-shares", 1, RCPRIV_PRIVILEGED,
805 	    RCTL_LOCAL_NOACTION);
806 
807 	rc_project_nlwps = rctl_register("project.max-lwps", RCENTITY_PROJECT,
808 	    RCTL_GLOBAL_NOACTION | RCTL_GLOBAL_NOBASIC | RCTL_GLOBAL_COUNT,
809 	    INT_MAX, INT_MAX, &project_lwps_ops);
810 
811 	rc_project_ntasks = rctl_register("project.max-tasks", RCENTITY_PROJECT,
812 	    RCTL_GLOBAL_NOACTION | RCTL_GLOBAL_NOBASIC | RCTL_GLOBAL_COUNT,
813 	    INT_MAX, INT_MAX, &project_tasks_ops);
814 
815 	/*
816 	 * This rctl handle is used by /dev/crypto. It is here rather than
817 	 * in misc/kcf or the drv/crypto module because resource controls
818 	 * currently don't allow modules to be unloaded, and the control
819 	 * must be registered before init starts.
820 	 */
821 	rc_project_crypto_mem = rctl_register("project.max-crypto-memory",
822 	    RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
823 	    RCTL_GLOBAL_BYTES, UINT64_MAX, UINT64_MAX,
824 	    &project_crypto_mem_ops);
825 
826 	/*
827 	 * Default to a quarter of the machine's memory
828 	 */
829 	qty = availrmem_initial << (PAGESHIFT - 2);
830 	rctl_add_default_limit("project.max-crypto-memory", qty,
831 	    RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
832 
833 	/*
834 	 * System V IPC resource controls
835 	 */
836 	rc_project_semmni = rctl_register("project.max-sem-ids",
837 	    RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
838 	    RCTL_GLOBAL_COUNT, IPC_IDS_MAX, IPC_IDS_MAX, &project_semmni_ops);
839 	rctl_add_legacy_limit("project.max-sem-ids", "semsys",
840 	    "seminfo_semmni", 128, IPC_IDS_MAX);
841 
842 	rc_project_msgmni = rctl_register("project.max-msg-ids",
843 	    RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
844 	    RCTL_GLOBAL_COUNT, IPC_IDS_MAX, IPC_IDS_MAX, &project_msgmni_ops);
845 	rctl_add_legacy_limit("project.max-msg-ids", "msgsys",
846 	    "msginfo_msgmni", 128, IPC_IDS_MAX);
847 
848 	rc_project_shmmni = rctl_register("project.max-shm-ids",
849 	    RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
850 	    RCTL_GLOBAL_COUNT, IPC_IDS_MAX, IPC_IDS_MAX, &project_shmmni_ops);
851 	rctl_add_legacy_limit("project.max-shm-ids", "shmsys",
852 	    "shminfo_shmmni", 128, IPC_IDS_MAX);
853 
854 	rc_project_shmmax = rctl_register("project.max-shm-memory",
855 	    RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
856 	    RCTL_GLOBAL_BYTES, UINT64_MAX, UINT64_MAX, &project_shmmax_ops);
857 
858 	check = B_FALSE;
859 	if (!mod_sysvar("shmsys", "shminfo_shmmni", &shmmni))
860 		shmmni = 100;
861 	else
862 		check = B_TRUE;
863 	if (!mod_sysvar("shmsys", "shminfo_shmmax", &shmmax))
864 		shmmax = 0x800000;
865 	else
866 		check = B_TRUE;
867 
868 	/*
869 	 * Default to a quarter of the machine's memory
870 	 */
871 	qty = availrmem_initial << (PAGESHIFT - 2);
872 	if (check) {
873 		if ((shmmax > 0) && (UINT64_MAX / shmmax <= shmmni))
874 			qty = UINT64_MAX;
875 		else if (shmmni * shmmax > qty)
876 			qty = shmmni * shmmax;
877 	}
878 	rctl_add_default_limit("project.max-shm-memory", qty,
879 	    RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
880 
881 	/*
882 	 * Event Ports resource controls
883 	 */
884 
885 	rc_project_portids = rctl_register("project.max-port-ids",
886 	    RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
887 	    RCTL_GLOBAL_COUNT, PORT_MAX_PORTS, PORT_MAX_PORTS,
888 	    &rctl_absolute_ops);
889 	rctl_add_default_limit("project.max-port-ids", PORT_DEFAULT_PORTS,
890 	    RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
891 
892 	/*
893 	 * Resource control for locked memory
894 	 */
895 	rc_project_locked_mem = rctl_register(
896 	    "project.max-locked-memory", RCENTITY_PROJECT,
897 	    RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC | RCTL_GLOBAL_BYTES,
898 	    UINT64_MAX, UINT64_MAX, &project_locked_mem_ops);
899 
900 	/* Default value equals that of max-shm-memory. */
901 	rctl_add_default_limit("project.max-locked-memory", qty,
902 	    RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
903 
904 	/*
905 	 * Per project limit on contracts.
906 	 */
907 	rc_project_contract = rctl_register("project.max-contracts",
908 	    RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
909 	    RCTL_GLOBAL_COUNT, INT_MAX, INT_MAX, &project_contract_ops);
910 	rctl_add_default_limit("project.max-contracts", 10000,
911 	    RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
912 
913 	t0.t_proj = proj0p = project_hold_by_id(0, &zone0,
914 	    PROJECT_HOLD_INSERT);
915 
916 	mutex_enter(&p0.p_lock);
917 	proj0p->kpj_nlwps = p0.p_lwpcnt;
918 	mutex_exit(&p0.p_lock);
919 	proj0p->kpj_ntasks = 1;
920 }
921 
922 static int
923 project_lockedmem_kstat_update(kstat_t *ksp, int rw)
924 {
925 	kproject_t *pj = ksp->ks_private;
926 	kproject_kstat_t *kpk = ksp->ks_data;
927 
928 	if (rw == KSTAT_WRITE)
929 		return (EACCES);
930 
931 	kpk->kpk_usage.value.ui64 = pj->kpj_data.kpd_locked_mem;
932 	kpk->kpk_value.value.ui64 = pj->kpj_data.kpd_locked_mem_ctl;
933 	return (0);
934 }
935 
936 static kstat_t *
937 project_kstat_create(kproject_t *pj, zone_t *zone)
938 {
939 	kstat_t *ksp;
940 	kproject_kstat_t *kpk;
941 	char *zonename = zone->zone_name;
942 
943 	ksp = rctl_kstat_create_project(pj, "lockedmem", KSTAT_TYPE_NAMED,
944 	    sizeof (kproject_kstat_t) / sizeof (kstat_named_t),
945 	    KSTAT_FLAG_VIRTUAL);
946 
947 	if (ksp == NULL)
948 		return (NULL);
949 
950 	kpk = ksp->ks_data = kmem_alloc(sizeof (kproject_kstat_t), KM_SLEEP);
951 	ksp->ks_data_size += strlen(zonename) + 1;
952 	kstat_named_init(&kpk->kpk_zonename, "zonename", KSTAT_DATA_STRING);
953 	kstat_named_setstr(&kpk->kpk_zonename, zonename);
954 	kstat_named_init(&kpk->kpk_usage, "usage", KSTAT_DATA_UINT64);
955 	kstat_named_init(&kpk->kpk_value, "value", KSTAT_DATA_UINT64);
956 	ksp->ks_update = project_lockedmem_kstat_update;
957 	ksp->ks_private = pj;
958 	kstat_install(ksp);
959 
960 	return (ksp);
961 }
962 
963 static void
964 project_kstat_delete(kproject_t *pj)
965 {
966 	void *data;
967 
968 	if (pj->kpj_data.kpd_lockedmem_kstat != NULL) {
969 		data = pj->kpj_data.kpd_lockedmem_kstat->ks_data;
970 		kstat_delete(pj->kpj_data.kpd_lockedmem_kstat);
971 		kmem_free(data, sizeof (zone_kstat_t));
972 	}
973 	pj->kpj_data.kpd_lockedmem_kstat = NULL;
974 }
975