summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/os
diff options
context:
space:
mode:
authorsl108498 <none@none>2006-09-19 15:49:28 -0700
committersl108498 <none@none>2006-09-19 15:49:28 -0700
commitc6939658adb0a356a77bc28f7df252ceb4a8f6cc (patch)
tree2e24cb01bd59e15cda6ad68fa5d778b4cf571fa7 /usr/src/uts/common/os
parent69889278ff50c08a6682a39ce6b5d97c5f0c2387 (diff)
downloadillumos-gate-c6939658adb0a356a77bc28f7df252ceb4a8f6cc.tar.gz
PSARC/2004/580 zone/project.max-locked-memory Resource Controls
PSARC/2006/463 Amendment_to_zone_project.max-locked-memory_Resource_Controls 5053609 RFE: need zone.max-locked-memory rctl 4691104 Need mlock capability without requiring superuser privileges
Diffstat (limited to 'usr/src/uts/common/os')
-rw-r--r--usr/src/uts/common/os/exec.c1
-rw-r--r--usr/src/uts/common/os/fork.c2
-rw-r--r--usr/src/uts/common/os/main.c1
-rw-r--r--usr/src/uts/common/os/project.c66
-rw-r--r--usr/src/uts/common/os/rctl.c107
-rw-r--r--usr/src/uts/common/os/shm.c188
-rw-r--r--usr/src/uts/common/os/sunddi.c106
-rw-r--r--usr/src/uts/common/os/zone.c94
8 files changed, 338 insertions, 227 deletions
diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c
index 3b01993465..657d87300f 100644
--- a/usr/src/uts/common/os/exec.c
+++ b/usr/src/uts/common/os/exec.c
@@ -1816,6 +1816,7 @@ exec_args(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp)
as = as_alloc();
p->p_as = as;
+ as->a_proc = p;
if (p->p_model == DATAMODEL_ILP32)
as->a_userlimit = (caddr_t)USERLIMIT32;
(void) hat_setup(as->a_hat, HAT_ALLOC);
diff --git a/usr/src/uts/common/os/fork.c b/usr/src/uts/common/os/fork.c
index fbda5b8c4a..7ae565274d 100644
--- a/usr/src/uts/common/os/fork.c
+++ b/usr/src/uts/common/os/fork.c
@@ -271,6 +271,8 @@ cfork(int isvfork, int isfork1)
error = (error == ENOMEM) ? ENOMEM : EAGAIN;
goto forkerr;
}
+ cp->p_as->a_proc = cp;
+
/* Duplicate parent's shared memory */
if (p->p_segacct)
shmfork(p, cp);
diff --git a/usr/src/uts/common/os/main.c b/usr/src/uts/common/os/main.c
index ec9fc6c3e3..1f4fbbf877 100644
--- a/usr/src/uts/common/os/main.c
+++ b/usr/src/uts/common/os/main.c
@@ -318,6 +318,7 @@ start_init_common()
p->p_stk_ctl = INT32_MAX;
p->p_as = as_alloc();
+ p->p_as->a_proc = p;
p->p_as->a_userlimit = (caddr_t)USERLIMIT32;
(void) hat_setup(p->p_as->a_hat, HAT_INIT);
diff --git a/usr/src/uts/common/os/project.c b/usr/src/uts/common/os/project.c
index 6eb65a8048..6c266c0ca3 100644
--- a/usr/src/uts/common/os/project.c
+++ b/usr/src/uts/common/os/project.c
@@ -55,7 +55,7 @@ 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_locked_mem;
rctl_hndl_t rc_project_contract;
rctl_hndl_t rc_project_crypto_mem;
@@ -114,7 +114,8 @@ project_data_init(kproject_data_t *data)
data->kpd_ipc.ipcq_shmmni = 0;
data->kpd_ipc.ipcq_semmni = 0;
data->kpd_ipc.ipcq_msgmni = 0;
- data->kpd_devlockmem = 0;
+ data->kpd_locked_mem = 0;
+ data->kpd_locked_mem_ctl = UINT64_MAX;
data->kpd_contract = 0;
data->kpd_crypto_mem = 0;
}
@@ -442,6 +443,7 @@ project_lwps_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, rctl_val_t *rcntl,
rctl_qty_t nlwps;
ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(MUTEX_HELD(&p->p_zone->zone_nlwps_lock));
ASSERT(e->rcep_t == RCENTITY_PROJECT);
if (e->rcep_p.proj == NULL)
return (0);
@@ -628,29 +630,51 @@ static rctl_ops_t project_msgmni_ops = {
project_msgmni_test
};
-/*
- * project.max-device-locked-memory resource control support.
- */
+/*ARGSUSED*/
+static rctl_qty_t
+project_locked_mem_usage(rctl_t *rctl, struct proc *p)
+{
+ rctl_qty_t q;
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ mutex_enter(&p->p_zone->zone_rctl_lock);
+ q = p->p_task->tk_proj->kpj_data.kpd_locked_mem;
+ mutex_exit(&p->p_zone->zone_rctl_lock);
+ return (q);
+}
/*ARGSUSED*/
static int
-project_devlockmem_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
+project_locked_mem_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;
+ rctl_qty_t q;
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)
+ ASSERT(MUTEX_HELD(&p->p_zone->zone_rctl_lock));
+ q = p->p_task->tk_proj->kpj_data.kpd_locked_mem;
+ if (q + inc > rval->rcv_value)
return (1);
return (0);
}
-static rctl_ops_t project_devlockmem_ops = {
+/*ARGSUSED*/
+static int
+project_locked_mem_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_data.kpd_locked_mem_ctl = nv;
+ return (0);
+}
+
+static rctl_ops_t project_locked_mem_ops = {
rcop_no_action,
- rcop_no_usage,
- rcop_no_set,
- project_devlockmem_test
+ project_locked_mem_usage,
+ project_locked_mem_set,
+ project_locked_mem_test
};
/*
@@ -826,17 +850,13 @@ project_init(void)
/*
* Resource control for locked memory
*/
- rc_project_devlockmem = rctl_register(
- "project.max-device-locked-memory", RCENTITY_PROJECT,
+ rc_project_locked_mem = rctl_register(
+ "project.max-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);
+ UINT64_MAX, UINT64_MAX, &project_locked_mem_ops);
- rctl_add_default_limit("project.max-device-locked-memory", qty,
+ /* Default value equals that of max-shm-memory. */
+ rctl_add_default_limit("project.max-locked-memory", qty,
RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
/*
diff --git a/usr/src/uts/common/os/rctl.c b/usr/src/uts/common/os/rctl.c
index dd6230ad7b..4de4c74fe8 100644
--- a/usr/src/uts/common/os/rctl.c
+++ b/usr/src/uts/common/os/rctl.c
@@ -2566,3 +2566,110 @@ rctl_init(void)
rctlproc_init();
}
+
+/*
+ * rctl_incr_locked_mem(proc_t *p, kproject_t *proj, rctl_qty_t inc)
+ *
+ * Increments the amount of locked memory on a project, and
+ * zone. If proj is NULL, the proj and zone of proc_t p is used. If
+ * chargeproc is non-zero, then the charged amount is cached on p->p_locked_mem
+ * so that the charge can be migrated when a process changes projects.
+ *
+ * Return values
+ * 0 - success
+ * EAGAIN - attempting to increment locked memory is denied by one
+ * or more resource entities.
+ */
+int
+rctl_incr_locked_mem(proc_t *p, kproject_t *proj, rctl_qty_t inc,
+ int chargeproc)
+{
+ kproject_t *projp;
+ zone_t *zonep;
+ rctl_entity_p_t e;
+ int ret = 0;
+
+ ASSERT(p != NULL);
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ if (proj != NULL) {
+ projp = proj;
+ zonep = zone_find_by_id(projp->kpj_zoneid);
+ } else {
+ projp = p->p_task->tk_proj;
+ zonep = p->p_zone;
+ }
+
+ mutex_enter(&zonep->zone_rctl_lock);
+
+ e.rcep_p.proj = projp;
+ e.rcep_t = RCENTITY_PROJECT;
+ if (projp->kpj_data.kpd_locked_mem + inc >
+ projp->kpj_data.kpd_locked_mem_ctl) {
+ if (rctl_test_entity(rc_project_locked_mem, projp->kpj_rctls,
+ p, &e, inc, 0) & RCT_DENY) {
+ ret = EAGAIN;
+ goto out;
+ }
+ }
+ e.rcep_p.zone = zonep;
+ e.rcep_t = RCENTITY_ZONE;
+ if (zonep->zone_locked_mem + inc > zonep->zone_locked_mem_ctl) {
+ if (rctl_test_entity(rc_zone_locked_mem, zonep->zone_rctls,
+ p, &e, inc, 0) & RCT_DENY) {
+ ret = EAGAIN;
+ goto out;
+ }
+ }
+
+ zonep->zone_locked_mem += inc;
+ projp->kpj_data.kpd_locked_mem += inc;
+ if (chargeproc != 0) {
+ p->p_locked_mem += inc;
+ }
+out:
+ mutex_exit(&zonep->zone_rctl_lock);
+ if (proj != NULL)
+ zone_rele(zonep);
+ return (ret);
+}
+
+/*
+ * rctl_decr_locked_mem(proc_t *p, kproject_t *proj, rctl_qty_t inc)
+ *
+ * Decrements the amount of locked memory on a project and
+ * zone. If proj is NULL, the proj and zone of proc_t p is used. If
+ * creditproc is non-zero, then the quantity of locked memory is subtracted
+ * from p->p_locked_mem.
+ *
+ * Return values
+ * none
+ */
+void
+rctl_decr_locked_mem(proc_t *p, kproject_t *proj, rctl_qty_t inc,
+ int creditproc)
+{
+ kproject_t *projp;
+ zone_t *zonep;
+
+ if (proj != NULL) {
+ projp = proj;
+ zonep = zone_find_by_id(projp->kpj_zoneid);
+ } else {
+ ASSERT(p != NULL);
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ projp = p->p_task->tk_proj;
+ zonep = p->p_zone;
+ }
+
+ mutex_enter(&zonep->zone_rctl_lock);
+ zonep->zone_locked_mem -= inc;
+ projp->kpj_data.kpd_locked_mem -= inc;
+ if (creditproc != 0) {
+ ASSERT(p != NULL);
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ p->p_locked_mem -= inc;
+ }
+ mutex_exit(&zonep->zone_rctl_lock);
+ if (proj != NULL)
+ zone_rele(zonep);
+}
diff --git a/usr/src/uts/common/os/shm.c b/usr/src/uts/common/os/shm.c
index b8038fd0ae..5c03ab7803 100644
--- a/usr/src/uts/common/os/shm.c
+++ b/usr/src/uts/common/os/shm.c
@@ -108,6 +108,7 @@
#include <sys/project.h>
#include <sys/policy.h>
#include <sys/zone.h>
+#include <sys/rctl.h>
#include <sys/ipc.h>
#include <sys/ipc_impl.h>
@@ -125,11 +126,11 @@
#include <c2/audit.h>
-static int shmem_lock(struct anon_map *amp);
-static void shmem_unlock(struct anon_map *amp, uint_t lck);
+static int shmem_lock(kshmid_t *sp, struct anon_map *amp);
+static void shmem_unlock(kshmid_t *sp, struct anon_map *amp);
static void sa_add(struct proc *pp, caddr_t addr, size_t len, ulong_t flags,
kshmid_t *id);
-static void shm_rm_amp(struct anon_map *amp, uint_t lckflag);
+static void shm_rm_amp(struct anon_map *amp);
static void shm_dtor(kipc_perm_t *);
static void shm_rmid(kipc_perm_t *);
static void shm_remove_zone(zoneid_t, void *);
@@ -464,7 +465,6 @@ shmat(int shmid, caddr_t uaddr, int uflags, uintptr_t *rvp)
sp->shm_sptinfo->sptas = segspt->s_as;
sp->shm_sptseg = segspt;
sp->shm_sptprot = prot;
- sp->shm_lkcnt = 0;
} else if ((prot & sp->shm_sptprot) != sp->shm_sptprot) {
/*
* Ensure we're attaching to an ISM segment with
@@ -573,6 +573,11 @@ shm_dtor(kipc_perm_t *perm)
uint_t cnt;
size_t rsize;
+ if (sp->shm_lkcnt > 0) {
+ shmem_unlock(sp, sp->shm_amp);
+ sp->shm_lkcnt = 0;
+ }
+
if (sp->shm_sptinfo) {
if (isspt(sp))
sptdestroy(sp->shm_sptinfo->sptas, sp->shm_amp);
@@ -583,7 +588,7 @@ shm_dtor(kipc_perm_t *perm)
cnt = --sp->shm_amp->refcnt;
ANON_LOCK_EXIT(&sp->shm_amp->a_rwlock);
ASSERT(cnt == 0);
- shm_rm_amp(sp->shm_amp, sp->shm_lkcnt);
+ shm_rm_amp(sp->shm_amp);
if (sp->shm_perm.ipc_id != IPC_ID_INVAL) {
rsize = ptob(btopr(sp->shm_segsz));
@@ -705,8 +710,13 @@ shmctl(int shmid, int cmd, void *arg)
if ((error = secpolicy_lock_memory(cr)) != 0)
break;
+ /* protect against overflow */
+ if (sp->shm_lkcnt >= USHRT_MAX) {
+ error = ENOMEM;
+ break;
+ }
if (!isspt(sp) && (sp->shm_lkcnt++ == 0)) {
- if (error = shmem_lock(sp->shm_amp)) {
+ if (error = shmem_lock(sp, sp->shm_amp)) {
ANON_LOCK_ENTER(&sp->shm_amp->a_rwlock, RW_WRITER);
cmn_err(CE_NOTE,
"shmctl - couldn't lock %ld pages into memory",
@@ -714,7 +724,6 @@ shmctl(int shmid, int cmd, void *arg)
ANON_LOCK_EXIT(&sp->shm_amp->a_rwlock);
error = ENOMEM;
sp->shm_lkcnt--;
- shmem_unlock(sp->shm_amp, 0);
}
}
break;
@@ -724,10 +733,8 @@ shmctl(int shmid, int cmd, void *arg)
if ((error = secpolicy_lock_memory(cr)) != 0)
break;
- if (!isspt(sp)) {
- if (sp->shm_lkcnt && (--sp->shm_lkcnt == 0)) {
- shmem_unlock(sp->shm_amp, 1);
- }
+ if (sp->shm_lkcnt && (--sp->shm_lkcnt == 0)) {
+ shmem_unlock(sp, sp->shm_amp);
}
break;
@@ -863,7 +870,7 @@ top:
}
sp->shm_amp = anonmap_alloc(rsize, rsize);
-
+ sp->shm_amp->a_sp = sp;
/*
* Store the original user's requested size, in bytes,
* rather than the page-aligned size. The former is
@@ -878,7 +885,6 @@ top:
sp->shm_cpid = curproc->p_pid;
sp->shm_ismattch = 0;
sp->shm_sptinfo = NULL;
-
/*
* Check limits one last time, push id into global
* visibility, and update resource usage counts.
@@ -1094,115 +1100,58 @@ shmexit(struct proc *pp)
* At this time pages should be in memory, so just lock them.
*/
static void
-lock_again(size_t npages, struct anon_map *amp)
+lock_again(size_t npages, kshmid_t *sp, struct anon_map *amp)
{
struct anon *ap;
struct page *pp;
struct vnode *vp;
- anoff_t off;
+ u_offset_t off;
ulong_t anon_idx;
anon_sync_obj_t cookie;
+ mutex_enter(&sp->shm_mlock);
ANON_LOCK_ENTER(&amp->a_rwlock, RW_READER);
-
for (anon_idx = 0; npages != 0; anon_idx++, npages--) {
anon_array_enter(amp, anon_idx, &cookie);
ap = anon_get_ptr(amp->ahp, anon_idx);
+ ASSERT(ap != NULL);
swap_xlate(ap, &vp, &off);
anon_array_exit(&cookie);
- pp = page_lookup(vp, (u_offset_t)off, SE_SHARED);
+ pp = page_lookup(vp, off, SE_SHARED);
if (pp == NULL) {
panic("lock_again: page not in the system");
/*NOTREACHED*/
}
+ /* page should already be locked by caller */
+ ASSERT(pp->p_lckcnt > 0);
(void) page_pp_lock(pp, 0, 0);
page_unlock(pp);
}
ANON_LOCK_EXIT(&amp->a_rwlock);
+ mutex_exit(&sp->shm_mlock);
}
-/* check if this segment is already locked. */
-/*ARGSUSED*/
-static int
-check_locked(struct as *as, struct segvn_data *svd, size_t npages)
-{
- struct vpage *vpp = svd->vpage;
- size_t i;
- if (svd->vpage == NULL)
- return (0); /* unlocked */
-
- SEGVN_LOCK_ENTER(as, &svd->lock, RW_READER);
- for (i = 0; i < npages; i++, vpp++) {
- if (VPP_ISPPLOCK(vpp) == 0) {
- SEGVN_LOCK_EXIT(as, &svd->lock);
- return (1); /* partially locked */
- }
- }
- SEGVN_LOCK_EXIT(as, &svd->lock);
- return (2); /* locked */
-}
-
-
/*
* Attach the shared memory segment to the process
* address space and lock the pages.
*/
static int
-shmem_lock(struct anon_map *amp)
+shmem_lock(kshmid_t *sp, struct anon_map *amp)
{
size_t npages = btopr(amp->size);
- struct seg *seg;
struct as *as;
struct segvn_crargs crargs;
- struct segvn_data *svd;
- proc_t *p = curproc;
- caddr_t addr;
- uint_t error, ret;
- caddr_t seg_base;
- size_t seg_sz;
-
- as = p->p_as;
- AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
- /* check if shared memory is already attached */
- for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
- svd = (struct segvn_data *)seg->s_data;
- if ((seg->s_ops == &segvn_ops) && (svd->amp == amp) &&
- (amp->size == seg->s_size)) {
- switch (ret = check_locked(as, svd, npages)) {
- case 0: /* unlocked */
- case 1: /* partially locked */
- seg_base = seg->s_base;
- seg_sz = seg->s_size;
-
- AS_LOCK_EXIT(as, &as->a_lock);
- if ((error = as_ctl(as, seg_base, seg_sz,
- MC_LOCK, 0, 0, NULL, 0)) == 0)
- lock_again(npages, amp);
- (void) as_ctl(as, seg_base, seg_sz, MC_UNLOCK,
- 0, 0, NULL, NULL);
- return (error);
- case 2: /* locked */
- AS_LOCK_EXIT(as, &as->a_lock);
- lock_again(npages, amp);
- return (0);
- default:
- cmn_err(CE_WARN, "shmem_lock: deflt %d", ret);
- break;
- }
- }
- }
- AS_LOCK_EXIT(as, &as->a_lock);
+ uint_t error;
- /* attach shm segment to our address space */
- as_rangelock(as);
- map_addr(&addr, amp->size, 0ll, 1, 0);
- if (addr == NULL) {
- as_rangeunlock(as);
- return (ENOMEM);
- }
+ /*
+ * A later ISM/DISM attach may increase the size of the amp, so
+ * cache the number of pages locked for the future shmem_unlock()
+ */
+ sp->shm_lkpages = npages;
+ as = as_alloc();
/* Initialize the create arguments and map the segment */
crargs = *(struct segvn_crargs *)zfod_argsp; /* structure copy */
crargs.offset = (u_offset_t)0;
@@ -1211,16 +1160,15 @@ shmem_lock(struct anon_map *amp)
crargs.prot = PROT_ALL;
crargs.maxprot = crargs.prot;
crargs.flags = 0;
-
- error = as_map(as, addr, amp->size, segvn_create, &crargs);
- as_rangeunlock(as);
+ error = as_map(as, 0x0, amp->size, segvn_create, &crargs);
if (!error) {
- if ((error = as_ctl(as, addr, amp->size, MC_LOCK, 0, 0,
+ if ((error = as_ctl(as, 0x0, amp->size, MC_LOCK, 0, 0,
NULL, 0)) == 0) {
- lock_again(npages, amp);
+ lock_again(npages, sp, amp);
}
- (void) as_unmap(as, addr, amp->size);
+ (void) as_unmap(as, 0x0, amp->size);
}
+ as_free(as);
return (error);
}
@@ -1229,38 +1177,53 @@ shmem_lock(struct anon_map *amp)
* Unlock shared memory
*/
static void
-shmem_unlock(struct anon_map *amp, uint_t lck)
+shmem_unlock(kshmid_t *sp, struct anon_map *amp)
{
struct anon *ap;
- pgcnt_t npages = btopr(amp->size);
+ pgcnt_t npages = sp->shm_lkpages;
struct vnode *vp;
struct page *pp;
- anoff_t off;
+ u_offset_t off;
ulong_t anon_idx;
+ size_t unlocked_bytes = 0;
+ kproject_t *proj;
+ anon_sync_obj_t cookie;
+ proj = sp->shm_perm.ipc_proj;
+ mutex_enter(&sp->shm_mlock);
+ ANON_LOCK_ENTER(&amp->a_rwlock, RW_READER);
for (anon_idx = 0; anon_idx < npages; anon_idx++) {
+ anon_array_enter(amp, anon_idx, &cookie);
if ((ap = anon_get_ptr(amp->ahp, anon_idx)) == NULL) {
- if (lck) {
- panic("shmem_unlock: null app");
- /*NOTREACHED*/
- }
- continue;
+ panic("shmem_unlock: null app");
+ /*NOTREACHED*/
}
swap_xlate(ap, &vp, &off);
+ anon_array_exit(&cookie);
pp = page_lookup(vp, off, SE_SHARED);
if (pp == NULL) {
- if (lck) {
- panic("shmem_unlock: page not in the system");
- /*NOTREACHED*/
- }
- continue;
- }
- if (pp->p_lckcnt) {
- page_pp_unlock(pp, 0, 0);
+ panic("shmem_unlock: page not in the system");
+ /*NOTREACHED*/
}
+ /*
+ * Page should at least have once lock from previous
+ * shmem_lock
+ */
+ ASSERT(pp->p_lckcnt > 0);
+ page_pp_unlock(pp, 0, 0);
+ if (pp->p_lckcnt == 0)
+ unlocked_bytes += PAGESIZE;
+
page_unlock(pp);
}
+
+ if (unlocked_bytes > 0) {
+ rctl_decr_locked_mem(NULL, proj, unlocked_bytes, 0);
+ }
+
+ ANON_LOCK_EXIT(&amp->a_rwlock);
+ mutex_exit(&sp->shm_mlock);
}
/*
@@ -1268,16 +1231,9 @@ shmem_unlock(struct anon_map *amp, uint_t lck)
* amp. This means all shmdt()s and the IPC_RMID have been done.
*/
static void
-shm_rm_amp(struct anon_map *amp, uint_t lckflag)
+shm_rm_amp(struct anon_map *amp)
{
/*
- * If we are finally deleting the
- * shared memory, and if no one did
- * the SHM_UNLOCK, we must do it now.
- */
- shmem_unlock(amp, lckflag);
-
- /*
* Free up the anon_map.
*/
lgrp_shm_policy_fini(amp, NULL);
diff --git a/usr/src/uts/common/os/sunddi.c b/usr/src/uts/common/os/sunddi.c
index f16ae44426..8c6bcefe06 100644
--- a/usr/src/uts/common/os/sunddi.c
+++ b/usr/src/uts/common/os/sunddi.c
@@ -82,10 +82,12 @@
#include <sys/devpolicy.h>
#include <sys/ctype.h>
#include <net/if.h>
+#include <sys/rctl.h>
extern pri_t minclsyspri;
-extern rctl_hndl_t rc_project_devlockmem;
+extern rctl_hndl_t rc_project_locked_mem;
+extern rctl_hndl_t rc_zone_locked_mem;
#ifdef DEBUG
static int sunddi_debug = 0;
@@ -104,13 +106,6 @@ static kthread_t *ddi_umem_unlock_thread;
static struct ddi_umem_cookie *ddi_umem_unlock_head = NULL;
static struct ddi_umem_cookie *ddi_umem_unlock_tail = NULL;
-/*
- * This lock protects the project.max-device-locked-memory counter.
- * When both p_lock (proc_t) and this lock need to acquired, p_lock
- * should be acquired first.
- */
-static kmutex_t umem_devlockmem_rctl_lock;
-
/*
* DDI(Sun) Function and flag definitions:
@@ -7819,32 +7814,15 @@ umem_lock_undo(struct as *as, void *arg, uint_t event)
*/
int
/* ARGSUSED */
-i_ddi_incr_locked_memory(proc_t *procp, task_t *taskp,
- kproject_t *projectp, zone_t *zonep, rctl_qty_t inc)
+i_ddi_incr_locked_memory(proc_t *procp, rctl_qty_t inc)
{
- kproject_t *projp;
-
- ASSERT(procp);
- ASSERT(mutex_owned(&procp->p_lock));
-
- projp = procp->p_task->tk_proj;
- mutex_enter(&umem_devlockmem_rctl_lock);
- /*
- * Test if the requested memory can be locked without exceeding the
- * limits.
- */
- if (rctl_test(rc_project_devlockmem, projp->kpj_rctls,
- procp, inc, RCA_SAFE) & RCT_DENY) {
- mutex_exit(&umem_devlockmem_rctl_lock);
+ ASSERT(procp != NULL);
+ mutex_enter(&procp->p_lock);
+ if (rctl_incr_locked_mem(procp, NULL, inc, 1)) {
+ mutex_exit(&procp->p_lock);
return (ENOMEM);
}
- projp->kpj_data.kpd_devlockmem += inc;
- mutex_exit(&umem_devlockmem_rctl_lock);
- /*
- * Grab a hold on the project.
- */
- (void) project_hold(projp);
-
+ mutex_exit(&procp->p_lock);
return (0);
}
@@ -7854,24 +7832,16 @@ i_ddi_incr_locked_memory(proc_t *procp, task_t *taskp,
*/
/* ARGSUSED */
void
-i_ddi_decr_locked_memory(proc_t *procp, task_t *taskp,
- kproject_t *projectp, zone_t *zonep, rctl_qty_t dec)
+i_ddi_decr_locked_memory(proc_t *procp, rctl_qty_t dec)
{
- ASSERT(projectp);
-
- mutex_enter(&umem_devlockmem_rctl_lock);
- projectp->kpj_data.kpd_devlockmem -= dec;
- mutex_exit(&umem_devlockmem_rctl_lock);
-
- /*
- * Release the project pointer reference accquired in
- * i_ddi_incr_locked_memory().
- */
- (void) project_rele(projectp);
+ ASSERT(procp != NULL);
+ mutex_enter(&procp->p_lock);
+ rctl_decr_locked_mem(procp, NULL, dec, 1);
+ mutex_exit(&procp->p_lock);
}
/*
- * This routine checks if the max-device-locked-memory resource ctl is
+ * This routine checks if the max-locked-memory resource ctl is
* exceeded, if not increments it, grabs a hold on the project.
* Returns 0 if successful otherwise returns error code
*/
@@ -7885,41 +7855,27 @@ umem_incr_devlockmem(struct ddi_umem_cookie *cookie)
procp = cookie->procp;
ASSERT(procp);
- mutex_enter(&procp->p_lock);
-
- if ((ret = i_ddi_incr_locked_memory(procp, NULL,
- NULL, NULL, cookie->size)) != 0) {
- mutex_exit(&procp->p_lock);
+ if ((ret = i_ddi_incr_locked_memory(procp,
+ cookie->size)) != 0) {
return (ret);
}
-
- /*
- * save the project pointer in the
- * umem cookie, project pointer already
- * hold in i_ddi_incr_locked_memory
- */
- cookie->lockmem_proj = (void *)procp->p_task->tk_proj;
- mutex_exit(&procp->p_lock);
-
return (0);
}
/*
- * Decrements the max-device-locked-memory resource ctl and releases
+ * Decrements the max-locked-memory resource ctl and releases
* the hold on the project that was acquired during umem_incr_devlockmem
*/
static void
umem_decr_devlockmem(struct ddi_umem_cookie *cookie)
{
- kproject_t *projp;
+ proc_t *proc;
- if (!cookie->lockmem_proj)
+ proc = (proc_t *)cookie->procp;
+ if (!proc)
return;
- projp = (kproject_t *)cookie->lockmem_proj;
- i_ddi_decr_locked_memory(NULL, NULL, projp, NULL, cookie->size);
-
- cookie->lockmem_proj = NULL;
+ i_ddi_decr_locked_memory(proc, cookie->size);
}
/*
@@ -7954,7 +7910,7 @@ umem_decr_devlockmem(struct ddi_umem_cookie *cookie)
* EINVAL - for invalid parameters
* EPERM, ENOMEM and other error codes returned by as_pagelock
* ENOMEM - is returned if the current request to lock memory exceeds
- * project.max-device-locked-memory resource control value.
+ * *.max-locked-memory resource control value.
* EFAULT - memory pertains to a regular file mapped shared and
* and DDI_UMEMLOCK_LONGTERM flag is set
* EAGAIN - could not start the ddi_umem_unlock list processing thread
@@ -8043,12 +7999,6 @@ umem_lockmemory(caddr_t addr, size_t len, int flags, ddi_umem_cookie_t *cookie,
*cookie = (ddi_umem_cookie_t)NULL;
return (ENOMEM);
}
- /*
- * umem_incr_devlockmem stashes the project ptr into the
- * cookie. This is needed during unlock since that can
- * happen in a non-USER context
- */
- ASSERT(p->lockmem_proj);
/* Lock the pages corresponding to addr, len in memory */
error = as_pagelock(as, &(p->pparray), addr, len, p->s_flags);
@@ -8169,7 +8119,7 @@ i_ddi_umem_unlock(struct ddi_umem_cookie *p)
/*
* Now that we have unlocked the memory decrement the
- * max-device-locked-memory rctl
+ * *.max-locked-memory rctl
*/
umem_decr_devlockmem(p);
@@ -8269,7 +8219,7 @@ i_ddi_umem_unlock_thread_start(void)
* EINVAL - for invalid parameters
* EPERM, ENOMEM and other error codes returned by as_pagelock
* ENOMEM - is returned if the current request to lock memory exceeds
- * project.max-device-locked-memory resource control value.
+ * *.max-locked-memory resource control value.
* EAGAIN - could not start the ddi_umem_unlock list processing thread
*/
int
@@ -8338,12 +8288,6 @@ ddi_umem_lock(caddr_t addr, size_t len, int flags, ddi_umem_cookie_t *cookie)
*cookie = (ddi_umem_cookie_t)NULL;
return (ENOMEM);
}
- /*
- * umem_incr_devlockmem stashes the project ptr into the
- * cookie. This is needed during unlock since that can
- * happen in a non-USER context
- */
- ASSERT(p->lockmem_proj);
/* Lock the pages corresponding to addr, len in memory */
error = as_pagelock(((proc_t *)p->procp)->p_as, &(p->pparray),
diff --git a/usr/src/uts/common/os/zone.c b/usr/src/uts/common/os/zone.c
index 9fd6b423bd..0fb2c2be55 100644
--- a/usr/src/uts/common/os/zone.c
+++ b/usr/src/uts/common/os/zone.c
@@ -316,6 +316,7 @@ const char *zone_status_table[] = {
* This isn't static so lint doesn't complain.
*/
rctl_hndl_t rc_zone_cpu_shares;
+rctl_hndl_t rc_zone_locked_mem;
rctl_hndl_t rc_zone_nlwps;
rctl_hndl_t rc_zone_shmmax;
rctl_hndl_t rc_zone_shmmni;
@@ -903,8 +904,8 @@ zone_lwps_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, rctl_val_t *rcntl,
/*ARGSUSED*/
static int
-zone_lwps_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e, rctl_qty_t nv) {
-
+zone_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_ZONE);
if (e->rcep_p.zone == NULL)
@@ -1004,6 +1005,51 @@ static rctl_ops_t zone_msgmni_ops = {
zone_msgmni_test
};
+/*ARGSUSED*/
+static rctl_qty_t
+zone_locked_mem_usage(rctl_t *rctl, struct proc *p)
+{
+ rctl_qty_t q;
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ mutex_enter(&p->p_zone->zone_rctl_lock);
+ q = p->p_zone->zone_locked_mem;
+ mutex_exit(&p->p_zone->zone_rctl_lock);
+ return (q);
+}
+
+/*ARGSUSED*/
+static int
+zone_locked_mem_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 q;
+ ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(MUTEX_HELD(&p->p_zone->zone_rctl_lock));
+ q = p->p_zone->zone_locked_mem;
+ if (q + incr > rcntl->rcv_value)
+ return (1);
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+zone_locked_mem_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_ZONE);
+ if (e->rcep_p.zone == NULL)
+ return (0);
+ e->rcep_p.zone->zone_locked_mem_ctl = nv;
+ return (0);
+}
+
+static rctl_ops_t zone_locked_mem_ops = {
+ rcop_no_action,
+ zone_locked_mem_usage,
+ zone_locked_mem_set,
+ zone_locked_mem_test
+};
/*
* Helper function to brand the zone with a unique ID.
@@ -1209,6 +1255,10 @@ zone_init(void)
rde = rctl_dict_lookup("zone.cpu-shares");
(void) rctl_val_list_insert(&rde->rcd_default_value, dval);
+ rc_zone_locked_mem = rctl_register("zone.max-locked-memory",
+ RCENTITY_ZONE, RCTL_GLOBAL_NOBASIC | RCTL_GLOBAL_BYTES |
+ RCTL_GLOBAL_DENY_ALWAYS, UINT64_MAX, UINT64_MAX,
+ &zone_locked_mem_ops);
/*
* Initialize the ``global zone''.
*/
@@ -2458,6 +2508,14 @@ zsched(void *arg)
mutex_exit(&global_zone->zone_nlwps_lock);
/*
+ * Decrement locked memory counts on old zone and project.
+ */
+ mutex_enter(&global_zone->zone_rctl_lock);
+ global_zone->zone_locked_mem -= pp->p_locked_mem;
+ pj->kpj_data.kpd_locked_mem -= pp->p_locked_mem;
+ mutex_exit(&global_zone->zone_rctl_lock);
+
+ /*
* Create and join a new task in project '0' of this zone.
*
* We don't need to call holdlwps() since we know we're the only lwp in
@@ -2468,21 +2526,29 @@ zsched(void *arg)
tk = task_create(0, zone);
mutex_enter(&cpu_lock);
oldtk = task_join(tk, 0);
- mutex_exit(&curproc->p_lock);
- mutex_exit(&cpu_lock);
- task_rele(oldtk);
+
+ pj = pp->p_task->tk_proj;
+
+ mutex_enter(&zone->zone_rctl_lock);
+ zone->zone_locked_mem += pp->p_locked_mem;
+ pj->kpj_data.kpd_locked_mem += pp->p_locked_mem;
+ mutex_exit(&zone->zone_rctl_lock);
/*
* add lwp counts to zsched's zone, and increment project's task count
* due to the task created in the above tasksys_settaskid
*/
- pj = pp->p_task->tk_proj;
+
mutex_enter(&zone->zone_nlwps_lock);
pj->kpj_nlwps += pp->p_lwpcnt;
pj->kpj_ntasks += 1;
zone->zone_nlwps += pp->p_lwpcnt;
mutex_exit(&zone->zone_nlwps_lock);
+ mutex_exit(&curproc->p_lock);
+ mutex_exit(&cpu_lock);
+ task_rele(oldtk);
+
/*
* The process was created by a process in the global zone, hence the
* credentials are wrong. We might as well have kcred-ish credentials.
@@ -2953,6 +3019,7 @@ zone_create(const char *zone_name, const char *zone_root,
zone->zone_initname = NULL;
mutex_init(&zone->zone_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&zone->zone_nlwps_lock, NULL, MUTEX_DEFAULT, NULL);
+ mutex_init(&zone->zone_rctl_lock, NULL, MUTEX_DEFAULT, NULL);
cv_init(&zone->zone_cv, NULL, CV_DEFAULT, NULL);
list_create(&zone->zone_zsd, sizeof (struct zsd_entry),
offsetof(struct zsd_entry, zsd_linkage));
@@ -2990,6 +3057,8 @@ zone_create(const char *zone_name, const char *zone_root,
zone->zone_initname =
kmem_alloc(strlen(zone_default_initname) + 1, KM_SLEEP);
(void) strcpy(zone->zone_initname, zone_default_initname);
+ zone->zone_locked_mem = 0;
+ zone->zone_locked_mem_ctl = UINT64_MAX;
/*
* Zsched initializes the rctls.
@@ -4145,15 +4214,26 @@ zone_enter(zoneid_t zoneid)
zone->zone_nlwps += pp->p_lwpcnt;
/* add 1 task to zone's proj0 */
zone_proj0->kpj_ntasks += 1;
- mutex_exit(&pp->p_lock);
mutex_exit(&zone->zone_nlwps_lock);
+ mutex_enter(&zone->zone_rctl_lock);
+ zone->zone_locked_mem += pp->p_locked_mem;
+ zone_proj0->kpj_data.kpd_locked_mem += pp->p_locked_mem;
+ mutex_exit(&zone->zone_rctl_lock);
+
/* remove lwps from proc's old zone and old project */
mutex_enter(&pp->p_zone->zone_nlwps_lock);
pp->p_zone->zone_nlwps -= pp->p_lwpcnt;
pp->p_task->tk_proj->kpj_nlwps -= pp->p_lwpcnt;
mutex_exit(&pp->p_zone->zone_nlwps_lock);
+ mutex_enter(&pp->p_zone->zone_rctl_lock);
+ pp->p_zone->zone_locked_mem -= pp->p_locked_mem;
+ pp->p_task->tk_proj->kpj_data.kpd_locked_mem -= pp->p_locked_mem;
+ mutex_exit(&pp->p_zone->zone_rctl_lock);
+
+ mutex_exit(&pp->p_lock);
+
/*
* Joining the zone cannot fail from now on.
*