diff options
author | sl108498 <none@none> | 2006-09-19 15:49:28 -0700 |
---|---|---|
committer | sl108498 <none@none> | 2006-09-19 15:49:28 -0700 |
commit | c6939658adb0a356a77bc28f7df252ceb4a8f6cc (patch) | |
tree | 2e24cb01bd59e15cda6ad68fa5d778b4cf571fa7 /usr/src/uts/common/os | |
parent | 69889278ff50c08a6682a39ce6b5d97c5f0c2387 (diff) | |
download | illumos-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.c | 1 | ||||
-rw-r--r-- | usr/src/uts/common/os/fork.c | 2 | ||||
-rw-r--r-- | usr/src/uts/common/os/main.c | 1 | ||||
-rw-r--r-- | usr/src/uts/common/os/project.c | 66 | ||||
-rw-r--r-- | usr/src/uts/common/os/rctl.c | 107 | ||||
-rw-r--r-- | usr/src/uts/common/os/shm.c | 188 | ||||
-rw-r--r-- | usr/src/uts/common/os/sunddi.c | 106 | ||||
-rw-r--r-- | usr/src/uts/common/os/zone.c | 94 |
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(&->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(&->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(&->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(&->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. * |