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]
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>
30 #include <sys/kstat.h>
31 #include <sys/atomic.h>
32 #include <sys/cmn_err.h>
35 #include <sys/sunddi.h>
37 #include <sys/systm.h>
38 #include <sys/ipc_impl.h>
39 #include <sys/port_kernel.h>
42 #include <sys/cpucaps.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.
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()
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.
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
);
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
;
133 project_hash_by_id(void *hash_data
, mod_hash_key_t key
)
135 struct project_zone
*pz
= key
;
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
));
147 project_hash_key_cmp(mod_hash_key_t key1
, mod_hash_key_t key2
)
149 struct project_zone
*pz1
= key1
, *pz2
= key2
;
152 return ((int)((retval
= pz1
->kpj_id
- pz2
->kpj_id
) != 0 ? retval
:
153 pz1
->kpj_zoneid
- pz2
->kpj_zoneid
));
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 *)
170 * Record that an additional reference on the indicated project has been
174 * A pointer to the indicated project.
177 * project_hash_lock must not be held across the project_hold() call.
180 project_hold(kproject_t
*p
)
182 mutex_enter(&project_hash_lock
);
185 ASSERT(p
->kpj_count
!= 0);
186 mutex_exit(&project_hash_lock
);
191 * kproject_t *project_hold_by_id(projid_t, zone_t *, int)
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.
208 * A pointer to the held project.
211 * Caller must be in a context suitable for KM_SLEEP allocations.
214 project_hold_by_id(projid_t id
, zone_t
*zone
, int flag
)
218 mod_hash_hndl_t hndl
;
222 struct project_zone pz
;
223 boolean_t create
= B_FALSE
;
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
)
237 mutex_exit(&project_hash_lock
);
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
) {
258 p
->kpj_zoneid
= zone
->zone_id
;
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
);
269 e
.rcep_t
= RCENTITY_PROJECT
;
270 p
->kpj_rctls
= rctl_set_init(RCENTITY_PROJECT
, curproc
, &e
,
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
;
289 * Special case: primordial hold on project 0.
295 mutex_exit(&projects_list_lock
);
298 mutex_exit(&curproc
->p_lock
);
299 mod_hash_cancel(projects_hash
, &hndl
);
300 kmem_free(spare_p
, sizeof (kproject_t
));
304 rctl_prealloc_destroy(gp
);
306 mutex_exit(&project_hash_lock
);
309 * The kstat stores the project's zone name, as zoneid's may change
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
);
326 * void project_rele(kproject_t *)
329 * Advertise that one external reference to this project is no longer needed.
335 * No restriction on context.
338 project_rele(kproject_t
*p
)
340 mutex_enter(&project_hash_lock
);
341 ASSERT(p
->kpj_count
!= 0);
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
,
370 mutex_exit(&project_hash_lock
);
374 * int project_walk_all(zoneid_t, int (*)(kproject_t *, void *), void *)
377 * Walk the project list for the given zoneid with a callback.
380 * -1 for an invalid walk, number of projects visited otherwise.
383 * projects_list_lock must not be held, as it is acquired by
384 * project_walk_all(). Accordingly, callbacks may not perform KM_SLEEP
388 project_walk_all(zoneid_t zoneid
, int (*cb
)(kproject_t
*, void *),
392 kproject_t
*kp
= proj0p
;
394 mutex_enter(&projects_list_lock
);
396 if (zoneid
!= ALL_ZONES
&& kp
->kpj_zoneid
!= zoneid
)
398 if (cb(kp
, walk_data
) == -1) {
404 } while ((kp
= kp
->kpj_next
) != proj0p
);
405 mutex_exit(&projects_list_lock
);
410 * projid_t curprojid(void)
413 * Return project ID of the current thread
421 return (ttoproj(curthread
)->kpj_id
);
425 * project.cpu-shares resource control support.
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
);
437 project_cpu_shares_set(rctl_t
*rctl
, struct proc
*p
, rctl_entity_p_t
*e
,
440 ASSERT(MUTEX_HELD(&p
->p_lock
));
441 ASSERT(e
->rcep_t
== RCENTITY_PROJECT
);
442 if (e
->rcep_p
.proj
== NULL
)
445 e
->rcep_p
.proj
->kpj_shares
= nv
;
450 static rctl_ops_t project_cpu_shares_ops
= {
452 project_cpu_shares_usage
,
453 project_cpu_shares_set
,
459 * project.cpu-cap resource control support.
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
));
471 project_cpu_cap_set(rctl_t
*rctl
, struct proc
*p
, rctl_entity_p_t
*e
,
474 kproject_t
*kpj
= e
->rcep_p
.proj
;
476 ASSERT(MUTEX_HELD(&p
->p_lock
));
477 ASSERT(e
->rcep_t
== RCENTITY_PROJECT
);
482 * set cap to the new value.
484 return (cpucaps_project_set(kpj
, nv
));
487 static rctl_ops_t project_cpu_cap_ops
= {
496 project_lwps_usage(rctl_t
*r
, proc_t
*p
)
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
);
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
)
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
)
523 nlwps
= e
->rcep_p
.proj
->kpj_nlwps
;
524 if (nlwps
+ incr
> rcntl
->rcv_value
)
532 project_lwps_set(rctl_t
*rctl
, struct proc
*p
, rctl_entity_p_t
*e
,
535 ASSERT(MUTEX_HELD(&p
->p_lock
));
536 ASSERT(e
->rcep_t
== RCENTITY_PROJECT
);
537 if (e
->rcep_p
.proj
== NULL
)
540 e
->rcep_p
.proj
->kpj_nlwps_ctl
= nv
;
544 static rctl_ops_t project_lwps_ops
= {
553 project_procs_usage(rctl_t
*r
, proc_t
*p
)
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
);
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
)
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
)
580 nprocs
= e
->rcep_p
.proj
->kpj_nprocs
;
581 if (nprocs
+ incr
> rcntl
->rcv_value
)
589 project_procs_set(rctl_t
*rctl
, struct proc
*p
, rctl_entity_p_t
*e
,
592 ASSERT(MUTEX_HELD(&p
->p_lock
));
593 ASSERT(e
->rcep_t
== RCENTITY_PROJECT
);
594 if (e
->rcep_p
.proj
== NULL
)
597 e
->rcep_p
.proj
->kpj_nprocs_ctl
= nv
;
601 static rctl_ops_t project_procs_ops
= {
610 project_ntasks_usage(rctl_t
*r
, proc_t
*p
)
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
);
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
)
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
)
642 project_ntasks_set(rctl_t
*rctl
, struct proc
*p
, rctl_entity_p_t
*e
,
645 ASSERT(MUTEX_HELD(&p
->p_lock
));
646 ASSERT(e
->rcep_t
== RCENTITY_PROJECT
);
647 e
->rcep_p
.proj
->kpj_ntasks_ctl
= nv
;
651 static rctl_ops_t project_tasks_ops
= {
653 project_ntasks_usage
,
659 * project.max-shm-memory resource control support.
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
);
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
)
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
)
685 static rctl_ops_t project_shmmax_ops
= {
687 project_shmmax_usage
,
693 * project.max-shm-ids resource control support.
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
);
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
)
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
)
719 static rctl_ops_t project_shmmni_ops
= {
721 project_shmmni_usage
,
727 * project.max-sem-ids resource control support.
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
);
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
)
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
)
753 static rctl_ops_t project_semmni_ops
= {
755 project_semmni_usage
,
761 * project.max-msg-ids resource control support.
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
);
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
)
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
)
787 static rctl_ops_t project_msgmni_ops
= {
789 project_msgmni_usage
,
796 project_locked_mem_usage(rctl_t
*rctl
, struct proc
*p
)
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
);
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
)
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
)
822 project_locked_mem_set(rctl_t
*rctl
, struct proc
*p
, rctl_entity_p_t
*e
,
825 ASSERT(MUTEX_HELD(&p
->p_lock
));
826 ASSERT(e
->rcep_t
== RCENTITY_PROJECT
);
827 if (e
->rcep_p
.proj
== NULL
)
830 e
->rcep_p
.proj
->kpj_data
.kpd_locked_mem_ctl
= nv
;
834 static rctl_ops_t project_locked_mem_ops
= {
836 project_locked_mem_usage
,
837 project_locked_mem_set
,
838 project_locked_mem_test
842 * project.max-contracts resource control support.
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
)
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
))
864 static rctl_ops_t project_contract_ops
= {
868 project_contract_test
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
);
881 project_crypto_set(rctl_t
*r
, proc_t
*p
, rctl_entity_p_t
*e
,
884 ASSERT(MUTEX_HELD(&p
->p_lock
));
885 ASSERT(e
->rcep_t
== RCENTITY_PROJECT
);
886 if (e
->rcep_p
.proj
== NULL
)
889 e
->rcep_p
.proj
->kpj_data
.kpd_crypto_mem_ctl
= nv
;
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
)
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
)
907 static rctl_ops_t project_crypto_mem_ops
= {
909 project_crypto_usage
,
915 * void project_init(void)
918 * Initialize the project subsystem, including the primordial project 0 entry.
919 * Register generic project resource controls, if any.
925 * Safe for KM_SLEEP allocations.
930 rctl_qty_t shmmni
, shmmax
, qty
;
933 projects_hash
= mod_hash_create_extended("projects_hash",
934 project_hash_size
, mod_hash_null_keydtor
, project_hash_val_dtor
,
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
);
1011 if (!mod_sysvar("shmsys", "shminfo_shmmni", &shmmni
))
1015 if (!mod_sysvar("shmsys", "shminfo_shmmax", &shmmax
))
1021 * Default to a quarter of the machine's memory
1023 qty
= availrmem_initial
<< (PAGESHIFT
- 2);
1025 if ((shmmax
> 0) && (UINT64_MAX
/ shmmax
<= shmmni
))
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;
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
)
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
;
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
)
1094 kpk
->kpk_usage
.value
.ui64
= pj
->kpj_nprocs
;
1095 kpk
->kpk_value
.value
.ui64
= pj
->kpj_nprocs_ctl
;
1100 project_kstat_create_common(kproject_t
*pj
, char *name
, char *zonename
,
1101 int (*updatefunc
) (kstat_t
*, int))
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
);
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
;
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
);
1145 project_kstat_delete_common(kstat_t
**kstat
)
1149 if (*kstat
!= NULL
) {
1150 data
= (*kstat
)->ks_data
;
1151 kstat_delete(*kstat
);
1152 kmem_free(data
, sizeof (kproject_kstat_t
));
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
);