summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/os/project.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/os/project.c')
-rw-r--r--usr/src/uts/common/os/project.c858
1 files changed, 858 insertions, 0 deletions
diff --git a/usr/src/uts/common/os/project.c b/usr/src/uts/common/os/project.c
new file mode 100644
index 0000000000..177f9a5d21
--- /dev/null
+++ b/usr/src/uts/common/os/project.c
@@ -0,0 +1,858 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/project.h>
+#include <sys/modhash.h>
+#include <sys/modctl.h>
+#include <sys/kmem.h>
+#include <sys/atomic.h>
+#include <sys/cmn_err.h>
+#include <sys/proc.h>
+#include <sys/rctl.h>
+#include <sys/sunddi.h>
+#include <sys/fss.h>
+#include <sys/systm.h>
+#include <sys/ipc_impl.h>
+#include <sys/port_kernel.h>
+#include <sys/task.h>
+#include <sys/zone.h>
+
+int project_hash_size = 64;
+static kmutex_t project_hash_lock;
+static kmutex_t projects_list_lock;
+static mod_hash_t *projects_hash;
+static kproject_t *projects_list;
+
+rctl_hndl_t rc_project_cpu_shares;
+rctl_hndl_t rc_project_nlwps;
+rctl_hndl_t rc_project_ntasks;
+rctl_hndl_t rc_project_msgmni;
+rctl_hndl_t rc_project_semmni;
+rctl_hndl_t rc_project_shmmax;
+rctl_hndl_t rc_project_shmmni;
+rctl_hndl_t rc_project_portids;
+rctl_hndl_t rc_project_devlockmem;
+rctl_hndl_t rc_project_contract;
+rctl_hndl_t rc_project_crypto_mem;
+
+/*
+ * Dummy structure used when comparing projects. This structure must be kept
+ * identical to the first two fields of kproject_t.
+ */
+struct project_zone {
+ projid_t kpj_id;
+ zoneid_t kpj_zoneid;
+};
+
+/*
+ * Projects
+ *
+ * A dictionary of all active projects is maintained by the kernel so that we
+ * may track project usage and limits. (By an active project, we mean a
+ * project associated with one or more task, and therefore with one or more
+ * processes.) We build the dictionary on top of the mod_hash facility, since
+ * project additions and deletions are relatively rare events. An
+ * integer-to-pointer mapping is maintained within the hash, representing the
+ * map from project id to project structure. All projects, including the
+ * primordial "project 0", are allocated via the project_hold_by_id()
+ * interface.
+ *
+ * Currently, the project contains a reference count; the project ID, which is
+ * examined by the extended accounting subsystem as well as /proc; a resource
+ * control set, which contains the allowable values (and actions on exceeding
+ * those values) for controlled project-level resources on the system; and a
+ * number of CPU shares, which is used by the fair share scheduling class
+ * (FSS) to support its proportion-based scheduling algorithm.
+ *
+ * Reference counting convention
+ * The dictionary entry does not itself count as a reference--only references
+ * outside of the subsystem are tallied. At the drop of the final external
+ * reference, the project entry is removed. The reference counter keeps
+ * track of the number of threads *and* tasks within a project.
+ *
+ * Locking
+ * Walking the doubly-linked project list must be done while holding
+ * projects_list_lock. Thus, any dereference of kpj_next or kpj_prev must be
+ * under projects_list_lock.
+ *
+ * If both the hash lock, project_hash_lock, and the list lock are to be
+ * acquired, the hash lock is to be acquired first.
+ */
+
+
+static void
+project_data_init(kproject_data_t *data)
+{
+ /*
+ * Initialize subsystem-specific data
+ */
+ data->kpd_shmmax = 0;
+ data->kpd_shmmni = 0;
+ data->kpd_semmni = 0;
+ data->kpd_msgmni = 0;
+ data->kpd_devlockmem = 0;
+ data->kpd_contract = 0;
+ data->kpd_crypto_mem = 0;
+}
+
+/*ARGSUSED*/
+static uint_t
+project_hash_by_id(void *hash_data, mod_hash_key_t key)
+{
+ struct project_zone *pz = key;
+ uint_t mykey;
+
+ /*
+ * Merge the zoneid and projectid together to a 32-bit quantity, and
+ * then pass that in to the existing idhash.
+ */
+ mykey = (pz->kpj_zoneid << 16) | pz->kpj_id;
+ return (mod_hash_byid(hash_data, (mod_hash_key_t)(uintptr_t)mykey));
+}
+
+static int
+project_hash_key_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
+{
+ struct project_zone *pz1 = key1, *pz2 = key2;
+ int retval;
+
+ return ((int)((retval = pz1->kpj_id - pz2->kpj_id) != 0 ? retval :
+ pz1->kpj_zoneid - pz2->kpj_zoneid));
+}
+
+static void
+project_hash_val_dtor(mod_hash_val_t val)
+{
+ kproject_t *kp = (kproject_t *)val;
+
+ ASSERT(kp->kpj_count == 0);
+ kmem_free(kp, sizeof (kproject_t));
+}
+
+/*
+ * kproject_t *project_hold(kproject_t *)
+ *
+ * Overview
+ * Record that an additional reference on the indicated project has been
+ * taken.
+ *
+ * Return values
+ * A pointer to the indicated project.
+ *
+ * Caller's context
+ * project_hash_lock must not be held across the project_hold() call.
+ */
+kproject_t *
+project_hold(kproject_t *p)
+{
+ mutex_enter(&project_hash_lock);
+ ASSERT(p != NULL);
+ p->kpj_count++;
+ ASSERT(p->kpj_count != 0);
+ mutex_exit(&project_hash_lock);
+ return (p);
+}
+
+/*
+ * kproject_t *project_hold_by_id(projid_t, zoneid_t, int)
+ *
+ * Overview
+ * project_hold_by_id() performs a look-up in the dictionary of projects
+ * active on the system by specified project ID + zone ID and puts a hold on
+ * it. The third argument defines the desired behavior in the case when
+ * project with given project ID cannot be found:
+ *
+ * PROJECT_HOLD_INSERT New entry is made in dictionary and the project
+ * is added to the global list.
+ *
+ * PROJECT_HOLD_FIND Return NULL.
+ *
+ * The project is returned with its reference count incremented by one.
+ * A new project derives its resource controls from those of project 0.
+ *
+ * Return values
+ * A pointer to the held project.
+ *
+ * Caller's context
+ * Caller must be in a context suitable for KM_SLEEP allocations.
+ */
+kproject_t *
+project_hold_by_id(projid_t id, zoneid_t zoneid, int flag)
+{
+ kproject_t *spare_p;
+ kproject_t *p;
+ mod_hash_hndl_t hndl;
+ rctl_set_t *set;
+ rctl_alloc_gp_t *gp;
+ rctl_entity_p_t e;
+ struct project_zone pz;
+
+ pz.kpj_id = id;
+ pz.kpj_zoneid = zoneid;
+
+ if (flag == PROJECT_HOLD_FIND) {
+ mutex_enter(&project_hash_lock);
+
+ if (mod_hash_find(projects_hash, (mod_hash_key_t)&pz,
+ (mod_hash_val_t)&p) == MH_ERR_NOTFOUND)
+ p = NULL;
+ else
+ p->kpj_count++;
+
+ mutex_exit(&project_hash_lock);
+ return (p);
+ }
+
+ ASSERT(flag == PROJECT_HOLD_INSERT);
+
+ spare_p = kmem_zalloc(sizeof (kproject_t), KM_SLEEP);
+ set = rctl_set_create();
+
+ gp = rctl_set_init_prealloc(RCENTITY_PROJECT);
+
+ (void) mod_hash_reserve(projects_hash, &hndl);
+
+ mutex_enter(&curproc->p_lock);
+ mutex_enter(&project_hash_lock);
+ if (mod_hash_find(projects_hash, (mod_hash_key_t)&pz,
+ (mod_hash_val_t *)&p) == MH_ERR_NOTFOUND) {
+ p = spare_p;
+ p->kpj_id = id;
+ p->kpj_zoneid = zoneid;
+ p->kpj_count = 0;
+ p->kpj_shares = 1;
+ p->kpj_nlwps = 0;
+ p->kpj_ntasks = 0;
+ p->kpj_nlwps_ctl = INT_MAX;
+ p->kpj_ntasks_ctl = INT_MAX;
+ project_data_init(&p->kpj_data);
+ e.rcep_p.proj = p;
+ e.rcep_t = RCENTITY_PROJECT;
+ p->kpj_rctls = rctl_set_init(RCENTITY_PROJECT, curproc, &e,
+ set, gp);
+ mutex_exit(&curproc->p_lock);
+
+ if (mod_hash_insert_reserve(projects_hash, (mod_hash_key_t)p,
+ (mod_hash_val_t)p, hndl))
+ panic("unable to insert project %d(%p)", id, (void *)p);
+
+ /*
+ * Insert project into global project list.
+ */
+ mutex_enter(&projects_list_lock);
+ if (id != 0 || zoneid != GLOBAL_ZONEID) {
+ p->kpj_next = projects_list;
+ p->kpj_prev = projects_list->kpj_prev;
+ p->kpj_prev->kpj_next = p;
+ projects_list->kpj_prev = p;
+ } else {
+ /*
+ * Special case: primordial hold on project 0.
+ */
+ p->kpj_next = p;
+ p->kpj_prev = p;
+ projects_list = p;
+ }
+ mutex_exit(&projects_list_lock);
+ } else {
+ mutex_exit(&curproc->p_lock);
+ mod_hash_cancel(projects_hash, &hndl);
+ kmem_free(spare_p, sizeof (kproject_t));
+ rctl_set_free(set);
+ }
+
+ rctl_prealloc_destroy(gp);
+ p->kpj_count++;
+ mutex_exit(&project_hash_lock);
+
+ return (p);
+}
+
+
+/*
+ * void project_rele(kproject_t *)
+ *
+ * Overview
+ * Advertise that one external reference to this project is no longer needed.
+ *
+ * Return values
+ * None.
+ *
+ * Caller's context
+ * No restriction on context.
+ */
+void
+project_rele(kproject_t *p)
+{
+ mutex_enter(&project_hash_lock);
+ ASSERT(p->kpj_count != 0);
+ p->kpj_count--;
+ if (p->kpj_count == 0) {
+
+ /*
+ * Remove project from global list.
+ */
+ mutex_enter(&projects_list_lock);
+ p->kpj_next->kpj_prev = p->kpj_prev;
+ p->kpj_prev->kpj_next = p->kpj_next;
+ if (projects_list == p)
+ projects_list = p->kpj_next;
+ mutex_exit(&projects_list_lock);
+
+ rctl_set_free(p->kpj_rctls);
+
+ if (mod_hash_destroy(projects_hash, (mod_hash_key_t)p))
+ panic("unable to delete project %d zone %d", p->kpj_id,
+ p->kpj_zoneid);
+
+ }
+ mutex_exit(&project_hash_lock);
+}
+
+/*
+ * int project_walk_all(zoneid_t, int (*)(kproject_t *, void *), void *)
+ *
+ * Overview
+ * Walk the project list for the given zoneid with a callback.
+ *
+ * Return values
+ * -1 for an invalid walk, number of projects visited otherwise.
+ *
+ * Caller's context
+ * projects_list_lock must not be held, as it is acquired by
+ * project_walk_all(). Accordingly, callbacks may not perform KM_SLEEP
+ * allocations.
+ */
+int
+project_walk_all(zoneid_t zoneid, int (*cb)(kproject_t *, void *),
+ void *walk_data)
+{
+ int cnt = 0;
+ kproject_t *kp = proj0p;
+
+ mutex_enter(&projects_list_lock);
+ do {
+ if (zoneid != ALL_ZONES && kp->kpj_zoneid != zoneid)
+ continue;
+ if (cb(kp, walk_data) == -1) {
+ cnt = -1;
+ break;
+ } else {
+ cnt++;
+ }
+ } while ((kp = kp->kpj_next) != proj0p);
+ mutex_exit(&projects_list_lock);
+ return (cnt);
+}
+
+/*
+ * projid_t curprojid(void)
+ *
+ * Overview
+ * Return project ID of the current thread
+ *
+ * Caller's context
+ * No restrictions.
+ */
+projid_t
+curprojid()
+{
+ return (ttoproj(curthread)->kpj_id);
+}
+
+/*
+ * project.cpu-shares resource control support.
+ */
+/*ARGSUSED*/
+static rctl_qty_t
+project_cpu_shares_usage(rctl_t *rctl, struct proc *p)
+{
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ return (p->p_task->tk_proj->kpj_shares);
+}
+
+/*ARGSUSED*/
+static int
+project_cpu_shares_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
+ rctl_qty_t nv)
+{
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(e->rcep_t == RCENTITY_PROJECT);
+ if (e->rcep_p.proj == NULL)
+ return (0);
+
+ e->rcep_p.proj->kpj_shares = nv;
+
+ return (0);
+}
+
+
+static rctl_ops_t project_cpu_shares_ops = {
+ rcop_no_action,
+ project_cpu_shares_usage,
+ project_cpu_shares_set,
+ rcop_no_test
+};
+
+/*ARGSUSED*/
+static rctl_qty_t
+project_lwps_usage(rctl_t *r, proc_t *p)
+{
+ kproject_t *pj;
+ rctl_qty_t nlwps;
+
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ pj = p->p_task->tk_proj;
+ mutex_enter(&p->p_zone->zone_nlwps_lock);
+ nlwps = pj->kpj_nlwps;
+ mutex_exit(&p->p_zone->zone_nlwps_lock);
+
+ return (nlwps);
+}
+
+/*ARGSUSED*/
+static int
+project_lwps_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, rctl_val_t *rcntl,
+ rctl_qty_t incr, uint_t flags)
+{
+ rctl_qty_t nlwps;
+
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(e->rcep_t == RCENTITY_PROJECT);
+ if (e->rcep_p.proj == NULL)
+ return (0);
+
+ nlwps = e->rcep_p.proj->kpj_nlwps;
+ if (nlwps + incr > rcntl->rcv_value)
+ return (1);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+project_lwps_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
+ rctl_qty_t nv) {
+
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(e->rcep_t == RCENTITY_PROJECT);
+ if (e->rcep_p.proj == NULL)
+ return (0);
+
+ e->rcep_p.proj->kpj_nlwps_ctl = nv;
+ return (0);
+}
+
+static rctl_ops_t project_lwps_ops = {
+ rcop_no_action,
+ project_lwps_usage,
+ project_lwps_set,
+ project_lwps_test,
+};
+
+/*ARGSUSED*/
+static rctl_qty_t
+project_ntasks_usage(rctl_t *r, proc_t *p)
+{
+ kproject_t *pj;
+ rctl_qty_t ntasks;
+
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ pj = p->p_task->tk_proj;
+ mutex_enter(&p->p_zone->zone_nlwps_lock);
+ ntasks = pj->kpj_ntasks;
+ mutex_exit(&p->p_zone->zone_nlwps_lock);
+
+ return (ntasks);
+}
+
+/*ARGSUSED*/
+static int
+project_ntasks_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, rctl_val_t *rcntl,
+ rctl_qty_t incr, uint_t flags)
+{
+ rctl_qty_t ntasks;
+
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(e->rcep_t == RCENTITY_PROJECT);
+ ntasks = e->rcep_p.proj->kpj_ntasks;
+ if (ntasks + incr > rcntl->rcv_value)
+ return (1);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+project_ntasks_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
+ rctl_qty_t nv) {
+
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(e->rcep_t == RCENTITY_PROJECT);
+ e->rcep_p.proj->kpj_ntasks_ctl = nv;
+ return (0);
+}
+
+static rctl_ops_t project_tasks_ops = {
+ rcop_no_action,
+ project_ntasks_usage,
+ project_ntasks_set,
+ project_ntasks_test,
+};
+
+/*
+ * project.max-shm-memory resource control support.
+ */
+
+/*ARGSUSED*/
+static int
+project_shmmax_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
+ rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
+{
+ rctl_qty_t v;
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(e->rcep_t == RCENTITY_PROJECT);
+ v = e->rcep_p.proj->kpj_data.kpd_shmmax + inc;
+ if (v > rval->rcv_value)
+ return (1);
+
+ return (0);
+}
+
+static rctl_ops_t project_shmmax_ops = {
+ rcop_no_action,
+ rcop_no_usage,
+ rcop_no_set,
+ project_shmmax_test
+};
+
+/*
+ * project.max-shm-ids resource control support.
+ */
+
+/*ARGSUSED*/
+static int
+project_shmmni_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
+ rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
+{
+ rctl_qty_t v;
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(e->rcep_t == RCENTITY_PROJECT);
+ v = e->rcep_p.proj->kpj_data.kpd_shmmni + inc;
+ if (v > rval->rcv_value)
+ return (1);
+
+ return (0);
+}
+
+static rctl_ops_t project_shmmni_ops = {
+ rcop_no_action,
+ rcop_no_usage,
+ rcop_no_set,
+ project_shmmni_test
+};
+
+/*
+ * project.max-sem-ids resource control support.
+ */
+
+/*ARGSUSED*/
+static int
+project_semmni_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
+ rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
+{
+ rctl_qty_t v;
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(e->rcep_t == RCENTITY_PROJECT);
+ v = e->rcep_p.proj->kpj_data.kpd_semmni + inc;
+ if (v > rval->rcv_value)
+ return (1);
+
+ return (0);
+}
+
+static rctl_ops_t project_semmni_ops = {
+ rcop_no_action,
+ rcop_no_usage,
+ rcop_no_set,
+ project_semmni_test
+};
+
+/*
+ * project.max-msg-ids resource control support.
+ */
+
+/*ARGSUSED*/
+static int
+project_msgmni_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
+ rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
+{
+ rctl_qty_t v;
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(e->rcep_t == RCENTITY_PROJECT);
+ v = e->rcep_p.proj->kpj_data.kpd_msgmni + inc;
+ if (v > rval->rcv_value)
+ return (1);
+
+ return (0);
+}
+
+static rctl_ops_t project_msgmni_ops = {
+ rcop_no_action,
+ rcop_no_usage,
+ rcop_no_set,
+ project_msgmni_test
+};
+
+/*
+ * project.max-device-locked-memory resource control support.
+ */
+
+/*ARGSUSED*/
+static int
+project_devlockmem_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
+ rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
+{
+ rctl_qty_t v;
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(e->rcep_t == RCENTITY_PROJECT);
+ v = e->rcep_p.proj->kpj_data.kpd_devlockmem + inc;
+ if (v > rval->rcv_value)
+ return (1);
+ return (0);
+}
+
+static rctl_ops_t project_devlockmem_ops = {
+ rcop_no_action,
+ rcop_no_usage,
+ rcop_no_set,
+ project_devlockmem_test
+};
+
+/*
+ * project.max-contracts resource control support.
+ */
+
+/*ARGSUSED*/
+static int
+project_contract_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
+ rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
+{
+ rctl_qty_t v;
+
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(e->rcep_t == RCENTITY_PROJECT);
+
+ v = e->rcep_p.proj->kpj_data.kpd_contract + inc;
+
+ if ((p->p_task != NULL) && (p->p_task->tk_proj) != NULL &&
+ (v > rval->rcv_value))
+ return (1);
+
+ return (0);
+}
+
+static rctl_ops_t project_contract_ops = {
+ rcop_no_action,
+ rcop_no_usage,
+ rcop_no_set,
+ project_contract_test
+};
+
+/*ARGSUSED*/
+static int
+project_crypto_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e,
+ rctl_val_t *rval, rctl_qty_t incr, uint_t flags)
+{
+ rctl_qty_t v;
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(e->rcep_t == RCENTITY_PROJECT);
+ v = e->rcep_p.proj->kpj_data.kpd_crypto_mem + incr;
+ if (v > rval->rcv_value)
+ return (1);
+ return (0);
+}
+
+static rctl_ops_t project_crypto_mem_ops = {
+ rcop_no_action,
+ rcop_no_usage,
+ rcop_no_set,
+ project_crypto_test
+};
+
+/*
+ * void project_init(void)
+ *
+ * Overview
+ * Initialize the project subsystem, including the primordial project 0 entry.
+ * Register generic project resource controls, if any.
+ *
+ * Return values
+ * None.
+ *
+ * Caller's context
+ * Safe for KM_SLEEP allocations.
+ */
+void
+project_init(void)
+{
+ rctl_qty_t shmmni, shmmax, qty;
+ boolean_t check;
+
+ projects_hash = mod_hash_create_extended("projects_hash",
+ project_hash_size, mod_hash_null_keydtor, project_hash_val_dtor,
+ project_hash_by_id,
+ (void *)(uintptr_t)mod_hash_iddata_gen(project_hash_size),
+ project_hash_key_cmp, KM_SLEEP);
+
+ rc_project_cpu_shares = rctl_register("project.cpu-shares",
+ RCENTITY_PROJECT, RCTL_GLOBAL_SIGNAL_NEVER |
+ RCTL_GLOBAL_DENY_NEVER | RCTL_GLOBAL_NOBASIC |
+ RCTL_GLOBAL_COUNT, FSS_MAXSHARES, FSS_MAXSHARES,
+ &project_cpu_shares_ops);
+ rctl_add_default_limit("project.cpu-shares", 1, RCPRIV_PRIVILEGED,
+ RCTL_LOCAL_NOACTION);
+
+ rc_project_nlwps = rctl_register("project.max-lwps", RCENTITY_PROJECT,
+ RCTL_GLOBAL_NOACTION | RCTL_GLOBAL_NOBASIC | RCTL_GLOBAL_COUNT,
+ INT_MAX, INT_MAX, &project_lwps_ops);
+
+ rc_project_ntasks = rctl_register("project.max-tasks", RCENTITY_PROJECT,
+ RCTL_GLOBAL_NOACTION | RCTL_GLOBAL_NOBASIC | RCTL_GLOBAL_COUNT,
+ INT_MAX, INT_MAX, &project_tasks_ops);
+
+ /*
+ * This rctl handle is used by /dev/crypto. It is here rather than
+ * in misc/kcf or the drv/crypto module because resource controls
+ * currently don't allow modules to be unloaded, and the control
+ * must be registered before init starts.
+ */
+ rc_project_crypto_mem = rctl_register("project.max-crypto-memory",
+ RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
+ RCTL_GLOBAL_BYTES, UINT64_MAX, UINT64_MAX,
+ &project_crypto_mem_ops);
+
+ /*
+ * Default to a quarter of the machine's memory
+ */
+ qty = availrmem_initial << (PAGESHIFT - 2);
+ rctl_add_default_limit("project.max-crypto-memory", qty,
+ RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
+
+ /*
+ * System V IPC resource controls
+ */
+ rc_project_semmni = rctl_register("project.max-sem-ids",
+ RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
+ RCTL_GLOBAL_COUNT, IPC_IDS_MAX, IPC_IDS_MAX, &project_semmni_ops);
+ rctl_add_legacy_limit("project.max-sem-ids", "semsys",
+ "seminfo_semmni", 128, IPC_IDS_MAX);
+
+ rc_project_msgmni = rctl_register("project.max-msg-ids",
+ RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
+ RCTL_GLOBAL_COUNT, IPC_IDS_MAX, IPC_IDS_MAX, &project_msgmni_ops);
+ rctl_add_legacy_limit("project.max-msg-ids", "msgsys",
+ "msginfo_msgmni", 128, IPC_IDS_MAX);
+
+ rc_project_shmmni = rctl_register("project.max-shm-ids",
+ RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
+ RCTL_GLOBAL_COUNT, IPC_IDS_MAX, IPC_IDS_MAX, &project_shmmni_ops);
+ rctl_add_legacy_limit("project.max-shm-ids", "shmsys",
+ "shminfo_shmmni", 128, IPC_IDS_MAX);
+
+ rc_project_shmmax = rctl_register("project.max-shm-memory",
+ RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
+ RCTL_GLOBAL_BYTES, UINT64_MAX, UINT64_MAX, &project_shmmax_ops);
+
+ check = B_FALSE;
+ if (!mod_sysvar("shmsys", "shminfo_shmmni", &shmmni))
+ shmmni = 100;
+ else
+ check = B_TRUE;
+ if (!mod_sysvar("shmsys", "shminfo_shmmax", &shmmax))
+ shmmax = 0x800000;
+ else
+ check = B_TRUE;
+
+ /*
+ * Default to a quarter of the machine's memory
+ */
+ qty = availrmem_initial << (PAGESHIFT - 2);
+ if (check) {
+ if ((shmmax > 0) && (UINT64_MAX / shmmax <= shmmni))
+ qty = UINT64_MAX;
+ else if (shmmni * shmmax > qty)
+ qty = shmmni * shmmax;
+ }
+ rctl_add_default_limit("project.max-shm-memory", qty,
+ RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
+
+ /*
+ * Event Ports resource controls
+ */
+
+ rc_project_portids = rctl_register("project.max-port-ids",
+ RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
+ RCTL_GLOBAL_COUNT, PORT_MAX_PORTS, PORT_MAX_PORTS,
+ &rctl_absolute_ops);
+ rctl_add_default_limit("project.max-port-ids", PORT_DEFAULT_PORTS,
+ RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
+
+ /*
+ * Resource control for locked memory
+ */
+ rc_project_devlockmem = rctl_register(
+ "project.max-device-locked-memory", RCENTITY_PROJECT,
+ RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC | RCTL_GLOBAL_BYTES,
+ UINT64_MAX, UINT64_MAX, &project_devlockmem_ops);
+
+ /*
+ * Defaults to 1/16th of the machine's memory
+ */
+ qty = availrmem_initial << (PAGESHIFT - 4);
+
+ rctl_add_default_limit("project.max-device-locked-memory", qty,
+ RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
+
+ /*
+ * Per project limit on contracts.
+ */
+ rc_project_contract = rctl_register("project.max-contracts",
+ RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
+ INT_MAX, INT_MAX, &project_contract_ops);
+ rctl_add_default_limit("project.max-contracts", 10000,
+ RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
+
+ t0.t_proj = proj0p = project_hold_by_id(0, GLOBAL_ZONEID,
+ PROJECT_HOLD_INSERT);
+
+ mutex_enter(&p0.p_lock);
+ proj0p->kpj_nlwps = p0.p_lwpcnt;
+ mutex_exit(&p0.p_lock);
+ proj0p->kpj_ntasks = 1;
+}