Merge commit '7e934d3acc051b7ee3ef0d11571fd1225800a607'
[unleashed.git] / kernel / os / project.c
blobd89f62bea75f55804c8612223d14ec7e1565638b
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2016, Joyent, Inc.
26 #include <sys/project.h>
27 #include <sys/modhash.h>
28 #include <sys/modctl.h>
29 #include <sys/kmem.h>
30 #include <sys/kstat.h>
31 #include <sys/atomic.h>
32 #include <sys/cmn_err.h>
33 #include <sys/proc.h>
34 #include <sys/rctl.h>
35 #include <sys/sunddi.h>
36 #include <sys/fss.h>
37 #include <sys/systm.h>
38 #include <sys/ipc_impl.h>
39 #include <sys/port_kernel.h>
40 #include <sys/task.h>
41 #include <sys/zone.h>
42 #include <sys/cpucaps.h>
43 #include <sys/klpd.h>
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;
51 rctl_hndl_t rc_project_cpu_shares;
52 rctl_hndl_t rc_project_cpu_cap;
53 rctl_hndl_t rc_project_nlwps;
54 rctl_hndl_t rc_project_nprocs;
55 rctl_hndl_t rc_project_ntasks;
56 rctl_hndl_t rc_project_msgmni;
57 rctl_hndl_t rc_project_semmni;
58 rctl_hndl_t rc_project_shmmax;
59 rctl_hndl_t rc_project_shmmni;
60 rctl_hndl_t rc_project_portids;
61 rctl_hndl_t rc_project_locked_mem;
62 rctl_hndl_t rc_project_contract;
63 rctl_hndl_t rc_project_crypto_mem;
66 * Dummy structure used when comparing projects. This structure must be kept
67 * identical to the first two fields of kproject_t.
69 struct project_zone {
70 projid_t kpj_id;
71 zoneid_t kpj_zoneid;
75 * Projects
77 * A dictionary of all active projects is maintained by the kernel so that we
78 * may track project usage and limits. (By an active project, we mean a
79 * project associated with one or more task, and therefore with one or more
80 * processes.) We build the dictionary on top of the mod_hash facility, since
81 * project additions and deletions are relatively rare events. An
82 * integer-to-pointer mapping is maintained within the hash, representing the
83 * map from project id to project structure. All projects, including the
84 * primordial "project 0", are allocated via the project_hold_by_id()
85 * interface.
87 * Currently, the project contains a reference count; the project ID, which is
88 * examined by the extended accounting subsystem as well as /proc; a resource
89 * control set, which contains the allowable values (and actions on exceeding
90 * those values) for controlled project-level resources on the system; and a
91 * number of CPU shares, which is used by the fair share scheduling class
92 * (FSS) to support its proportion-based scheduling algorithm.
94 * Reference counting convention
95 * The dictionary entry does not itself count as a reference--only references
96 * outside of the subsystem are tallied. At the drop of the final external
97 * reference, the project entry is removed. The reference counter keeps
98 * track of the number of threads *and* tasks within a project.
100 * Locking
101 * Walking the doubly-linked project list must be done while holding
102 * projects_list_lock. Thus, any dereference of kpj_next or kpj_prev must be
103 * under projects_list_lock.
105 * If both the hash lock, project_hash_lock, and the list lock are to be
106 * acquired, the hash lock is to be acquired first.
109 static void project_kstat_create(kproject_t *pj, zone_t *zone);
110 static void project_kstat_delete(kproject_t *pj);
112 static void
113 project_data_init(kproject_data_t *data)
116 * Initialize subsystem-specific data
118 data->kpd_shmmax = 0;
119 data->kpd_ipc.ipcq_shmmni = 0;
120 data->kpd_ipc.ipcq_semmni = 0;
121 data->kpd_ipc.ipcq_msgmni = 0;
122 data->kpd_locked_mem = 0;
123 data->kpd_locked_mem_ctl = UINT64_MAX;
124 data->kpd_contract = 0;
125 data->kpd_crypto_mem = 0;
126 data->kpd_crypto_mem_ctl = UINT64_MAX;
127 data->kpd_lockedmem_kstat = NULL;
128 data->kpd_nprocs_kstat = NULL;
131 /*ARGSUSED*/
132 static uint_t
133 project_hash_by_id(void *hash_data, mod_hash_key_t key)
135 struct project_zone *pz = key;
136 uint_t mykey;
139 * Merge the zoneid and projectid together to a 32-bit quantity, and
140 * then pass that in to the existing idhash.
142 mykey = (pz->kpj_zoneid << 16) | pz->kpj_id;
143 return (mod_hash_byid(hash_data, (mod_hash_key_t)(uintptr_t)mykey));
146 static int
147 project_hash_key_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
149 struct project_zone *pz1 = key1, *pz2 = key2;
150 int retval;
152 return ((int)((retval = pz1->kpj_id - pz2->kpj_id) != 0 ? retval :
153 pz1->kpj_zoneid - pz2->kpj_zoneid));
156 static void
157 project_hash_val_dtor(mod_hash_val_t val)
159 kproject_t *kp = (kproject_t *)val;
161 ASSERT(kp->kpj_count == 0);
162 ASSERT(kp->kpj_cpucap == NULL);
163 kmem_free(kp, sizeof (kproject_t));
167 * kproject_t *project_hold(kproject_t *)
169 * Overview
170 * Record that an additional reference on the indicated project has been
171 * taken.
173 * Return values
174 * A pointer to the indicated project.
176 * Caller's context
177 * project_hash_lock must not be held across the project_hold() call.
179 kproject_t *
180 project_hold(kproject_t *p)
182 mutex_enter(&project_hash_lock);
183 ASSERT(p != NULL);
184 p->kpj_count++;
185 ASSERT(p->kpj_count != 0);
186 mutex_exit(&project_hash_lock);
187 return (p);
191 * kproject_t *project_hold_by_id(projid_t, zone_t *, int)
193 * Overview
194 * project_hold_by_id() performs a look-up in the dictionary of projects
195 * active on the system by specified project ID + zone and puts a hold on
196 * it. The third argument defines the desired behavior in the case when
197 * project with given project ID cannot be found:
199 * PROJECT_HOLD_INSERT New entry is made in dictionary and the project
200 * is added to the global list.
202 * PROJECT_HOLD_FIND Return NULL.
204 * The project is returned with its reference count incremented by one.
205 * A new project derives its resource controls from those of project 0.
207 * Return values
208 * A pointer to the held project.
210 * Caller's context
211 * Caller must be in a context suitable for KM_SLEEP allocations.
213 kproject_t *
214 project_hold_by_id(projid_t id, zone_t *zone, int flag)
216 kproject_t *spare_p;
217 kproject_t *p;
218 mod_hash_hndl_t hndl;
219 rctl_set_t *set;
220 rctl_alloc_gp_t *gp;
221 rctl_entity_p_t e;
222 struct project_zone pz;
223 boolean_t create = B_FALSE;
225 pz.kpj_id = id;
226 pz.kpj_zoneid = zone->zone_id;
228 if (flag == PROJECT_HOLD_FIND) {
229 mutex_enter(&project_hash_lock);
231 if (mod_hash_find(projects_hash, (mod_hash_key_t)&pz,
232 (mod_hash_val_t)&p) == MH_ERR_NOTFOUND)
233 p = NULL;
234 else
235 p->kpj_count++;
237 mutex_exit(&project_hash_lock);
238 return (p);
241 ASSERT(flag == PROJECT_HOLD_INSERT);
243 spare_p = kmem_zalloc(sizeof (kproject_t), KM_SLEEP);
244 set = rctl_set_create();
246 gp = rctl_set_init_prealloc(RCENTITY_PROJECT);
248 (void) mod_hash_reserve(projects_hash, &hndl);
250 mutex_enter(&curproc->p_lock);
251 mutex_enter(&project_hash_lock);
252 if (mod_hash_find(projects_hash, (mod_hash_key_t)&pz,
253 (mod_hash_val_t *)&p) == MH_ERR_NOTFOUND) {
255 p = spare_p;
256 p->kpj_id = id;
257 p->kpj_zone = zone;
258 p->kpj_zoneid = zone->zone_id;
259 p->kpj_count = 0;
260 p->kpj_shares = 1;
261 p->kpj_nlwps = 0;
262 p->kpj_nprocs = 0;
263 p->kpj_ntasks = 0;
264 p->kpj_nlwps_ctl = INT_MAX;
265 p->kpj_nprocs_ctl = INT_MAX;
266 p->kpj_ntasks_ctl = INT_MAX;
267 project_data_init(&p->kpj_data);
268 e.rcep_p.proj = p;
269 e.rcep_t = RCENTITY_PROJECT;
270 p->kpj_rctls = rctl_set_init(RCENTITY_PROJECT, curproc, &e,
271 set, gp);
272 mutex_exit(&curproc->p_lock);
274 if (mod_hash_insert_reserve(projects_hash, (mod_hash_key_t)p,
275 (mod_hash_val_t)p, hndl))
276 panic("unable to insert project %d(%p)", id, (void *)p);
279 * Insert project into global project list.
281 mutex_enter(&projects_list_lock);
282 if (id != 0 || zone != &zone0) {
283 p->kpj_next = projects_list;
284 p->kpj_prev = projects_list->kpj_prev;
285 p->kpj_prev->kpj_next = p;
286 projects_list->kpj_prev = p;
287 } else {
289 * Special case: primordial hold on project 0.
291 p->kpj_next = p;
292 p->kpj_prev = p;
293 projects_list = p;
295 mutex_exit(&projects_list_lock);
296 create = B_TRUE;
297 } else {
298 mutex_exit(&curproc->p_lock);
299 mod_hash_cancel(projects_hash, &hndl);
300 kmem_free(spare_p, sizeof (kproject_t));
301 rctl_set_free(set);
304 rctl_prealloc_destroy(gp);
305 p->kpj_count++;
306 mutex_exit(&project_hash_lock);
309 * The kstat stores the project's zone name, as zoneid's may change
310 * across reboots.
312 if (create == B_TRUE) {
314 * Inform CPU caps framework of the new project
316 cpucaps_project_add(p);
318 * Set up project kstats
320 project_kstat_create(p, zone);
322 return (p);
326 * void project_rele(kproject_t *)
328 * Overview
329 * Advertise that one external reference to this project is no longer needed.
331 * Return values
332 * None.
334 * Caller's context
335 * No restriction on context.
337 void
338 project_rele(kproject_t *p)
340 mutex_enter(&project_hash_lock);
341 ASSERT(p->kpj_count != 0);
342 p->kpj_count--;
343 if (p->kpj_count == 0) {
346 * Remove project from global list.
348 ASSERT(p->kpj_nprocs == 0);
350 mutex_enter(&projects_list_lock);
351 p->kpj_next->kpj_prev = p->kpj_prev;
352 p->kpj_prev->kpj_next = p->kpj_next;
353 if (projects_list == p)
354 projects_list = p->kpj_next;
355 mutex_exit(&projects_list_lock);
357 cpucaps_project_remove(p);
359 rctl_set_free(p->kpj_rctls);
360 project_kstat_delete(p);
362 if (p->kpj_klpd != NULL)
363 klpd_freelist(&p->kpj_klpd);
365 if (mod_hash_destroy(projects_hash, (mod_hash_key_t)p))
366 panic("unable to delete project %d zone %d", p->kpj_id,
367 p->kpj_zoneid);
370 mutex_exit(&project_hash_lock);
374 * int project_walk_all(zoneid_t, int (*)(kproject_t *, void *), void *)
376 * Overview
377 * Walk the project list for the given zoneid with a callback.
379 * Return values
380 * -1 for an invalid walk, number of projects visited otherwise.
382 * Caller's context
383 * projects_list_lock must not be held, as it is acquired by
384 * project_walk_all(). Accordingly, callbacks may not perform KM_SLEEP
385 * allocations.
388 project_walk_all(zoneid_t zoneid, int (*cb)(kproject_t *, void *),
389 void *walk_data)
391 int cnt = 0;
392 kproject_t *kp = proj0p;
394 mutex_enter(&projects_list_lock);
395 do {
396 if (zoneid != ALL_ZONES && kp->kpj_zoneid != zoneid)
397 continue;
398 if (cb(kp, walk_data) == -1) {
399 cnt = -1;
400 break;
401 } else {
402 cnt++;
404 } while ((kp = kp->kpj_next) != proj0p);
405 mutex_exit(&projects_list_lock);
406 return (cnt);
410 * projid_t curprojid(void)
412 * Overview
413 * Return project ID of the current thread
415 * Caller's context
416 * No restrictions.
418 projid_t
419 curprojid()
421 return (ttoproj(curthread)->kpj_id);
425 * project.cpu-shares resource control support.
427 /*ARGSUSED*/
428 static rctl_qty_t
429 project_cpu_shares_usage(rctl_t *rctl, struct proc *p)
431 ASSERT(MUTEX_HELD(&p->p_lock));
432 return (p->p_task->tk_proj->kpj_shares);
435 /*ARGSUSED*/
436 static int
437 project_cpu_shares_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
438 rctl_qty_t nv)
440 ASSERT(MUTEX_HELD(&p->p_lock));
441 ASSERT(e->rcep_t == RCENTITY_PROJECT);
442 if (e->rcep_p.proj == NULL)
443 return (0);
445 e->rcep_p.proj->kpj_shares = nv;
447 return (0);
450 static rctl_ops_t project_cpu_shares_ops = {
451 rcop_no_action,
452 project_cpu_shares_usage,
453 project_cpu_shares_set,
454 rcop_no_test
459 * project.cpu-cap resource control support.
461 /*ARGSUSED*/
462 static rctl_qty_t
463 project_cpu_cap_get(rctl_t *rctl, struct proc *p)
465 ASSERT(MUTEX_HELD(&p->p_lock));
466 return (cpucaps_project_get(p->p_task->tk_proj));
469 /*ARGSUSED*/
470 static int
471 project_cpu_cap_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
472 rctl_qty_t nv)
474 kproject_t *kpj = e->rcep_p.proj;
476 ASSERT(MUTEX_HELD(&p->p_lock));
477 ASSERT(e->rcep_t == RCENTITY_PROJECT);
478 if (kpj == NULL)
479 return (0);
482 * set cap to the new value.
484 return (cpucaps_project_set(kpj, nv));
487 static rctl_ops_t project_cpu_cap_ops = {
488 rcop_no_action,
489 project_cpu_cap_get,
490 project_cpu_cap_set,
491 rcop_no_test
494 /*ARGSUSED*/
495 static rctl_qty_t
496 project_lwps_usage(rctl_t *r, proc_t *p)
498 kproject_t *pj;
499 rctl_qty_t nlwps;
501 ASSERT(MUTEX_HELD(&p->p_lock));
502 pj = p->p_task->tk_proj;
503 mutex_enter(&p->p_zone->zone_nlwps_lock);
504 nlwps = pj->kpj_nlwps;
505 mutex_exit(&p->p_zone->zone_nlwps_lock);
507 return (nlwps);
510 /*ARGSUSED*/
511 static int
512 project_lwps_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, rctl_val_t *rcntl,
513 rctl_qty_t incr, uint_t flags)
515 rctl_qty_t nlwps;
517 ASSERT(MUTEX_HELD(&p->p_lock));
518 ASSERT(MUTEX_HELD(&p->p_zone->zone_nlwps_lock));
519 ASSERT(e->rcep_t == RCENTITY_PROJECT);
520 if (e->rcep_p.proj == NULL)
521 return (0);
523 nlwps = e->rcep_p.proj->kpj_nlwps;
524 if (nlwps + incr > rcntl->rcv_value)
525 return (1);
527 return (0);
530 /*ARGSUSED*/
531 static int
532 project_lwps_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
533 rctl_qty_t nv) {
535 ASSERT(MUTEX_HELD(&p->p_lock));
536 ASSERT(e->rcep_t == RCENTITY_PROJECT);
537 if (e->rcep_p.proj == NULL)
538 return (0);
540 e->rcep_p.proj->kpj_nlwps_ctl = nv;
541 return (0);
544 static rctl_ops_t project_lwps_ops = {
545 rcop_no_action,
546 project_lwps_usage,
547 project_lwps_set,
548 project_lwps_test,
551 /*ARGSUSED*/
552 static rctl_qty_t
553 project_procs_usage(rctl_t *r, proc_t *p)
555 kproject_t *pj;
556 rctl_qty_t nprocs;
558 ASSERT(MUTEX_HELD(&p->p_lock));
559 pj = p->p_task->tk_proj;
560 mutex_enter(&p->p_zone->zone_nlwps_lock);
561 nprocs = pj->kpj_nprocs;
562 mutex_exit(&p->p_zone->zone_nlwps_lock);
564 return (nprocs);
567 /*ARGSUSED*/
568 static int
569 project_procs_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, rctl_val_t *rcntl,
570 rctl_qty_t incr, uint_t flags)
572 rctl_qty_t nprocs;
574 ASSERT(MUTEX_HELD(&p->p_lock));
575 ASSERT(MUTEX_HELD(&p->p_zone->zone_nlwps_lock));
576 ASSERT(e->rcep_t == RCENTITY_PROJECT);
577 if (e->rcep_p.proj == NULL)
578 return (0);
580 nprocs = e->rcep_p.proj->kpj_nprocs;
581 if (nprocs + incr > rcntl->rcv_value)
582 return (1);
584 return (0);
587 /*ARGSUSED*/
588 static int
589 project_procs_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
590 rctl_qty_t nv) {
592 ASSERT(MUTEX_HELD(&p->p_lock));
593 ASSERT(e->rcep_t == RCENTITY_PROJECT);
594 if (e->rcep_p.proj == NULL)
595 return (0);
597 e->rcep_p.proj->kpj_nprocs_ctl = nv;
598 return (0);
601 static rctl_ops_t project_procs_ops = {
602 rcop_no_action,
603 project_procs_usage,
604 project_procs_set,
605 project_procs_test,
608 /*ARGSUSED*/
609 static rctl_qty_t
610 project_ntasks_usage(rctl_t *r, proc_t *p)
612 kproject_t *pj;
613 rctl_qty_t ntasks;
615 ASSERT(MUTEX_HELD(&p->p_lock));
616 pj = p->p_task->tk_proj;
617 mutex_enter(&p->p_zone->zone_nlwps_lock);
618 ntasks = pj->kpj_ntasks;
619 mutex_exit(&p->p_zone->zone_nlwps_lock);
621 return (ntasks);
624 /*ARGSUSED*/
625 static int
626 project_ntasks_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, rctl_val_t *rcntl,
627 rctl_qty_t incr, uint_t flags)
629 rctl_qty_t ntasks;
631 ASSERT(MUTEX_HELD(&p->p_lock));
632 ASSERT(e->rcep_t == RCENTITY_PROJECT);
633 ntasks = e->rcep_p.proj->kpj_ntasks;
634 if (ntasks + incr > rcntl->rcv_value)
635 return (1);
637 return (0);
640 /*ARGSUSED*/
641 static int
642 project_ntasks_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
643 rctl_qty_t nv) {
645 ASSERT(MUTEX_HELD(&p->p_lock));
646 ASSERT(e->rcep_t == RCENTITY_PROJECT);
647 e->rcep_p.proj->kpj_ntasks_ctl = nv;
648 return (0);
651 static rctl_ops_t project_tasks_ops = {
652 rcop_no_action,
653 project_ntasks_usage,
654 project_ntasks_set,
655 project_ntasks_test,
659 * project.max-shm-memory resource control support.
662 /*ARGSUSED*/
663 static rctl_qty_t
664 project_shmmax_usage(rctl_t *rctl, struct proc *p)
666 ASSERT(MUTEX_HELD(&p->p_lock));
667 return (p->p_task->tk_proj->kpj_data.kpd_shmmax);
670 /*ARGSUSED*/
671 static int
672 project_shmmax_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
673 rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
675 rctl_qty_t v;
676 ASSERT(MUTEX_HELD(&p->p_lock));
677 ASSERT(e->rcep_t == RCENTITY_PROJECT);
678 v = e->rcep_p.proj->kpj_data.kpd_shmmax + inc;
679 if (v > rval->rcv_value)
680 return (1);
682 return (0);
685 static rctl_ops_t project_shmmax_ops = {
686 rcop_no_action,
687 project_shmmax_usage,
688 rcop_no_set,
689 project_shmmax_test
693 * project.max-shm-ids resource control support.
696 /*ARGSUSED*/
697 static rctl_qty_t
698 project_shmmni_usage(rctl_t *rctl, struct proc *p)
700 ASSERT(MUTEX_HELD(&p->p_lock));
701 return (p->p_task->tk_proj->kpj_data.kpd_ipc.ipcq_shmmni);
704 /*ARGSUSED*/
705 static int
706 project_shmmni_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
707 rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
709 rctl_qty_t v;
710 ASSERT(MUTEX_HELD(&p->p_lock));
711 ASSERT(e->rcep_t == RCENTITY_PROJECT);
712 v = e->rcep_p.proj->kpj_data.kpd_ipc.ipcq_shmmni + inc;
713 if (v > rval->rcv_value)
714 return (1);
716 return (0);
719 static rctl_ops_t project_shmmni_ops = {
720 rcop_no_action,
721 project_shmmni_usage,
722 rcop_no_set,
723 project_shmmni_test
727 * project.max-sem-ids resource control support.
730 /*ARGSUSED*/
731 static rctl_qty_t
732 project_semmni_usage(rctl_t *rctl, struct proc *p)
734 ASSERT(MUTEX_HELD(&p->p_lock));
735 return (p->p_task->tk_proj->kpj_data.kpd_ipc.ipcq_semmni);
738 /*ARGSUSED*/
739 static int
740 project_semmni_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
741 rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
743 rctl_qty_t v;
744 ASSERT(MUTEX_HELD(&p->p_lock));
745 ASSERT(e->rcep_t == RCENTITY_PROJECT);
746 v = e->rcep_p.proj->kpj_data.kpd_ipc.ipcq_semmni + inc;
747 if (v > rval->rcv_value)
748 return (1);
750 return (0);
753 static rctl_ops_t project_semmni_ops = {
754 rcop_no_action,
755 project_semmni_usage,
756 rcop_no_set,
757 project_semmni_test
761 * project.max-msg-ids resource control support.
764 /*ARGSUSED*/
765 static rctl_qty_t
766 project_msgmni_usage(rctl_t *rctl, struct proc *p)
768 ASSERT(MUTEX_HELD(&p->p_lock));
769 return (p->p_task->tk_proj->kpj_data.kpd_ipc.ipcq_msgmni);
772 /*ARGSUSED*/
773 static int
774 project_msgmni_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
775 rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
777 rctl_qty_t v;
778 ASSERT(MUTEX_HELD(&p->p_lock));
779 ASSERT(e->rcep_t == RCENTITY_PROJECT);
780 v = e->rcep_p.proj->kpj_data.kpd_ipc.ipcq_msgmni + inc;
781 if (v > rval->rcv_value)
782 return (1);
784 return (0);
787 static rctl_ops_t project_msgmni_ops = {
788 rcop_no_action,
789 project_msgmni_usage,
790 rcop_no_set,
791 project_msgmni_test
794 /*ARGSUSED*/
795 static rctl_qty_t
796 project_locked_mem_usage(rctl_t *rctl, struct proc *p)
798 rctl_qty_t q;
799 ASSERT(MUTEX_HELD(&p->p_lock));
800 mutex_enter(&p->p_zone->zone_mem_lock);
801 q = p->p_task->tk_proj->kpj_data.kpd_locked_mem;
802 mutex_exit(&p->p_zone->zone_mem_lock);
803 return (q);
806 /*ARGSUSED*/
807 static int
808 project_locked_mem_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
809 rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
811 rctl_qty_t q;
812 ASSERT(MUTEX_HELD(&p->p_lock));
813 ASSERT(MUTEX_HELD(&p->p_zone->zone_mem_lock));
814 q = p->p_task->tk_proj->kpj_data.kpd_locked_mem;
815 if (q + inc > rval->rcv_value)
816 return (1);
817 return (0);
820 /*ARGSUSED*/
821 static int
822 project_locked_mem_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
823 rctl_qty_t nv) {
825 ASSERT(MUTEX_HELD(&p->p_lock));
826 ASSERT(e->rcep_t == RCENTITY_PROJECT);
827 if (e->rcep_p.proj == NULL)
828 return (0);
830 e->rcep_p.proj->kpj_data.kpd_locked_mem_ctl = nv;
831 return (0);
834 static rctl_ops_t project_locked_mem_ops = {
835 rcop_no_action,
836 project_locked_mem_usage,
837 project_locked_mem_set,
838 project_locked_mem_test
842 * project.max-contracts resource control support.
845 /*ARGSUSED*/
846 static int
847 project_contract_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
848 rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
850 rctl_qty_t v;
852 ASSERT(MUTEX_HELD(&p->p_lock));
853 ASSERT(e->rcep_t == RCENTITY_PROJECT);
855 v = e->rcep_p.proj->kpj_data.kpd_contract + inc;
857 if ((p->p_task != NULL) && (p->p_task->tk_proj) != NULL &&
858 (v > rval->rcv_value))
859 return (1);
861 return (0);
864 static rctl_ops_t project_contract_ops = {
865 rcop_no_action,
866 rcop_no_usage,
867 rcop_no_set,
868 project_contract_test
871 /*ARGSUSED*/
872 static rctl_qty_t
873 project_crypto_usage(rctl_t *r, proc_t *p)
875 ASSERT(MUTEX_HELD(&p->p_lock));
876 return (p->p_task->tk_proj->kpj_data.kpd_crypto_mem);
879 /*ARGSUSED*/
880 static int
881 project_crypto_set(rctl_t *r, proc_t *p, rctl_entity_p_t *e,
882 rctl_qty_t nv)
884 ASSERT(MUTEX_HELD(&p->p_lock));
885 ASSERT(e->rcep_t == RCENTITY_PROJECT);
886 if (e->rcep_p.proj == NULL)
887 return (0);
889 e->rcep_p.proj->kpj_data.kpd_crypto_mem_ctl = nv;
890 return (0);
893 /*ARGSUSED*/
894 static int
895 project_crypto_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e,
896 rctl_val_t *rval, rctl_qty_t incr, uint_t flags)
898 rctl_qty_t v;
899 ASSERT(MUTEX_HELD(&p->p_lock));
900 ASSERT(e->rcep_t == RCENTITY_PROJECT);
901 v = e->rcep_p.proj->kpj_data.kpd_crypto_mem + incr;
902 if (v > rval->rcv_value)
903 return (1);
904 return (0);
907 static rctl_ops_t project_crypto_mem_ops = {
908 rcop_no_action,
909 project_crypto_usage,
910 project_crypto_set,
911 project_crypto_test
915 * void project_init(void)
917 * Overview
918 * Initialize the project subsystem, including the primordial project 0 entry.
919 * Register generic project resource controls, if any.
921 * Return values
922 * None.
924 * Caller's context
925 * Safe for KM_SLEEP allocations.
927 void
928 project_init(void)
930 rctl_qty_t shmmni, shmmax, qty;
931 boolean_t check;
933 projects_hash = mod_hash_create_extended("projects_hash",
934 project_hash_size, mod_hash_null_keydtor, project_hash_val_dtor,
935 project_hash_by_id,
936 (void *)(uintptr_t)mod_hash_iddata_gen(project_hash_size),
937 project_hash_key_cmp, KM_SLEEP);
939 rc_project_cpu_shares = rctl_register("project.cpu-shares",
940 RCENTITY_PROJECT, RCTL_GLOBAL_SIGNAL_NEVER |
941 RCTL_GLOBAL_DENY_NEVER | RCTL_GLOBAL_NOBASIC |
942 RCTL_GLOBAL_COUNT | RCTL_GLOBAL_SYSLOG_NEVER,
943 FSS_MAXSHARES, FSS_MAXSHARES,
944 &project_cpu_shares_ops);
945 rctl_add_default_limit("project.cpu-shares", 1, RCPRIV_PRIVILEGED,
946 RCTL_LOCAL_NOACTION);
948 rc_project_cpu_cap = rctl_register("project.cpu-cap",
949 RCENTITY_PROJECT, RCTL_GLOBAL_SIGNAL_NEVER |
950 RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
951 RCTL_GLOBAL_COUNT | RCTL_GLOBAL_SYSLOG_NEVER |
952 RCTL_GLOBAL_INFINITE,
953 MAXCAP, MAXCAP, &project_cpu_cap_ops);
955 rc_project_nlwps = rctl_register("project.max-lwps", RCENTITY_PROJECT,
956 RCTL_GLOBAL_NOACTION | RCTL_GLOBAL_NOBASIC | RCTL_GLOBAL_COUNT,
957 INT_MAX, INT_MAX, &project_lwps_ops);
959 rc_project_nprocs = rctl_register("project.max-processes",
960 RCENTITY_PROJECT, RCTL_GLOBAL_NOACTION | RCTL_GLOBAL_NOBASIC |
961 RCTL_GLOBAL_COUNT, INT_MAX, INT_MAX, &project_procs_ops);
963 rc_project_ntasks = rctl_register("project.max-tasks", RCENTITY_PROJECT,
964 RCTL_GLOBAL_NOACTION | RCTL_GLOBAL_NOBASIC | RCTL_GLOBAL_COUNT,
965 INT_MAX, INT_MAX, &project_tasks_ops);
968 * This rctl handle is used by /dev/crypto. It is here rather than
969 * in misc/kcf or the drv/crypto module because resource controls
970 * currently don't allow modules to be unloaded, and the control
971 * must be registered before init starts.
973 rc_project_crypto_mem = rctl_register("project.max-crypto-memory",
974 RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
975 RCTL_GLOBAL_BYTES, UINT64_MAX, UINT64_MAX,
976 &project_crypto_mem_ops);
979 * Default to a quarter of the machine's memory
981 qty = availrmem_initial << (PAGESHIFT - 2);
982 rctl_add_default_limit("project.max-crypto-memory", qty,
983 RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
986 * System V IPC resource controls
988 rc_project_semmni = rctl_register("project.max-sem-ids",
989 RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
990 RCTL_GLOBAL_COUNT, IPC_IDS_MAX, IPC_IDS_MAX, &project_semmni_ops);
991 rctl_add_legacy_limit("project.max-sem-ids", "semsys",
992 "seminfo_semmni", 128, IPC_IDS_MAX);
994 rc_project_msgmni = rctl_register("project.max-msg-ids",
995 RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
996 RCTL_GLOBAL_COUNT, IPC_IDS_MAX, IPC_IDS_MAX, &project_msgmni_ops);
997 rctl_add_legacy_limit("project.max-msg-ids", "msgsys",
998 "msginfo_msgmni", 128, IPC_IDS_MAX);
1000 rc_project_shmmni = rctl_register("project.max-shm-ids",
1001 RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
1002 RCTL_GLOBAL_COUNT, IPC_IDS_MAX, IPC_IDS_MAX, &project_shmmni_ops);
1003 rctl_add_legacy_limit("project.max-shm-ids", "shmsys",
1004 "shminfo_shmmni", 128, IPC_IDS_MAX);
1006 rc_project_shmmax = rctl_register("project.max-shm-memory",
1007 RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
1008 RCTL_GLOBAL_BYTES, UINT64_MAX, UINT64_MAX, &project_shmmax_ops);
1010 check = B_FALSE;
1011 if (!mod_sysvar("shmsys", "shminfo_shmmni", &shmmni))
1012 shmmni = 100;
1013 else
1014 check = B_TRUE;
1015 if (!mod_sysvar("shmsys", "shminfo_shmmax", &shmmax))
1016 shmmax = 0x800000;
1017 else
1018 check = B_TRUE;
1021 * Default to a quarter of the machine's memory
1023 qty = availrmem_initial << (PAGESHIFT - 2);
1024 if (check) {
1025 if ((shmmax > 0) && (UINT64_MAX / shmmax <= shmmni))
1026 qty = UINT64_MAX;
1027 else if (shmmni * shmmax > qty)
1028 qty = shmmni * shmmax;
1030 rctl_add_default_limit("project.max-shm-memory", qty,
1031 RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
1034 * Event Ports resource controls
1037 rc_project_portids = rctl_register("project.max-port-ids",
1038 RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
1039 RCTL_GLOBAL_COUNT, PORT_MAX_PORTS, PORT_MAX_PORTS,
1040 &rctl_absolute_ops);
1041 rctl_add_default_limit("project.max-port-ids", PORT_DEFAULT_PORTS,
1042 RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
1045 * Resource control for locked memory
1047 rc_project_locked_mem = rctl_register(
1048 "project.max-locked-memory", RCENTITY_PROJECT,
1049 RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC | RCTL_GLOBAL_BYTES,
1050 UINT64_MAX, UINT64_MAX, &project_locked_mem_ops);
1053 * Per project limit on contracts.
1055 rc_project_contract = rctl_register("project.max-contracts",
1056 RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
1057 RCTL_GLOBAL_COUNT, INT_MAX, INT_MAX, &project_contract_ops);
1058 rctl_add_default_limit("project.max-contracts", 10000,
1059 RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
1061 t0.t_proj = proj0p = project_hold_by_id(0, &zone0,
1062 PROJECT_HOLD_INSERT);
1064 mutex_enter(&p0.p_lock);
1065 proj0p->kpj_nlwps = p0.p_lwpcnt;
1066 mutex_exit(&p0.p_lock);
1067 proj0p->kpj_nprocs = 1;
1068 proj0p->kpj_ntasks = 1;
1071 static int
1072 project_lockedmem_kstat_update(kstat_t *ksp, int rw)
1074 kproject_t *pj = ksp->ks_private;
1075 kproject_kstat_t *kpk = ksp->ks_data;
1077 if (rw == KSTAT_WRITE)
1078 return (EACCES);
1080 kpk->kpk_usage.value.ui64 = pj->kpj_data.kpd_locked_mem;
1081 kpk->kpk_value.value.ui64 = pj->kpj_data.kpd_locked_mem_ctl;
1082 return (0);
1085 static int
1086 project_nprocs_kstat_update(kstat_t *ksp, int rw)
1088 kproject_t *pj = ksp->ks_private;
1089 kproject_kstat_t *kpk = ksp->ks_data;
1091 if (rw == KSTAT_WRITE)
1092 return (EACCES);
1094 kpk->kpk_usage.value.ui64 = pj->kpj_nprocs;
1095 kpk->kpk_value.value.ui64 = pj->kpj_nprocs_ctl;
1096 return (0);
1099 static kstat_t *
1100 project_kstat_create_common(kproject_t *pj, char *name, char *zonename,
1101 int (*updatefunc) (kstat_t *, int))
1103 kstat_t *ksp;
1104 kproject_kstat_t *kpk;
1106 ksp = rctl_kstat_create_project(pj, name, KSTAT_TYPE_NAMED,
1107 sizeof (kproject_kstat_t) / sizeof (kstat_named_t),
1108 KSTAT_FLAG_VIRTUAL);
1110 if (ksp == NULL)
1111 return (NULL);
1113 kpk = ksp->ks_data = kmem_alloc(sizeof (kproject_kstat_t), KM_SLEEP);
1114 ksp->ks_data_size += strlen(zonename) + 1;
1115 kstat_named_init(&kpk->kpk_zonename, "zonename", KSTAT_DATA_STRING);
1116 kstat_named_setstr(&kpk->kpk_zonename, zonename);
1117 kstat_named_init(&kpk->kpk_usage, "usage", KSTAT_DATA_UINT64);
1118 kstat_named_init(&kpk->kpk_value, "value", KSTAT_DATA_UINT64);
1119 ksp->ks_update = updatefunc;
1120 ksp->ks_private = pj;
1121 kstat_install(ksp);
1122 return (ksp);
1125 static void
1126 project_kstat_create(kproject_t *pj, zone_t *zone)
1128 kstat_t *ksp_lockedmem;
1129 kstat_t *ksp_nprocs;
1131 ksp_lockedmem = project_kstat_create_common(pj, "lockedmem",
1132 zone->zone_name, project_lockedmem_kstat_update);
1133 ksp_nprocs = project_kstat_create_common(pj, "nprocs",
1134 zone->zone_name, project_nprocs_kstat_update);
1136 mutex_enter(&project_hash_lock);
1137 ASSERT(pj->kpj_data.kpd_lockedmem_kstat == NULL);
1138 pj->kpj_data.kpd_lockedmem_kstat = ksp_lockedmem;
1139 ASSERT(pj->kpj_data.kpd_nprocs_kstat == NULL);
1140 pj->kpj_data.kpd_nprocs_kstat = ksp_nprocs;
1141 mutex_exit(&project_hash_lock);
1144 static void
1145 project_kstat_delete_common(kstat_t **kstat)
1147 void *data;
1149 if (*kstat != NULL) {
1150 data = (*kstat)->ks_data;
1151 kstat_delete(*kstat);
1152 kmem_free(data, sizeof (kproject_kstat_t));
1153 *kstat = NULL;
1157 static void
1158 project_kstat_delete(kproject_t *pj)
1160 project_kstat_delete_common(&pj->kpj_data.kpd_lockedmem_kstat);
1161 project_kstat_delete_common(&pj->kpj_data.kpd_nprocs_kstat);