diff options
Diffstat (limited to 'usr/src/uts/common/vm/vm_as.c')
-rw-r--r-- | usr/src/uts/common/vm/vm_as.c | 140 |
1 files changed, 102 insertions, 38 deletions
diff --git a/usr/src/uts/common/vm/vm_as.c b/usr/src/uts/common/vm/vm_as.c index f7533f56a6..4e807fd670 100644 --- a/usr/src/uts/common/vm/vm_as.c +++ b/usr/src/uts/common/vm/vm_as.c @@ -1463,11 +1463,9 @@ top: } static int -as_map_vnsegs(struct as *as, caddr_t addr, size_t size, +as_map_segvn_segs(struct as *as, caddr_t addr, size_t size, uint_t szcvec, int (*crfp)(), struct segvn_crargs *vn_a, int *segcreated) { - int text = vn_a->flags & MAP_TEXT; - uint_t szcvec = map_execseg_pgszcvec(text, addr, size); uint_t szc; uint_t nszc; int error; @@ -1475,19 +1473,18 @@ as_map_vnsegs(struct as *as, caddr_t addr, size_t size, caddr_t eaddr; size_t segsize; struct seg *seg; - uint_t save_szcvec; size_t pgsz; - struct vattr va; - u_offset_t eoff; - size_t save_size = 0; + int do_off = (vn_a->vp != NULL || vn_a->amp != NULL); + uint_t save_szcvec; ASSERT(AS_WRITE_HELD(as, &as->a_lock)); ASSERT(IS_P2ALIGNED(addr, PAGESIZE)); ASSERT(IS_P2ALIGNED(size, PAGESIZE)); - ASSERT(vn_a->vp != NULL); - ASSERT(vn_a->amp == NULL); + ASSERT(vn_a->vp == NULL || vn_a->amp == NULL); + if (!do_off) { + vn_a->offset = 0; + } -again: if (szcvec <= 1) { seg = seg_alloc(as, addr, size); if (seg == NULL) { @@ -1501,28 +1498,6 @@ again: return (error); } - va.va_mask = AT_SIZE; - if (VOP_GETATTR(vn_a->vp, &va, ATTR_HINT, vn_a->cred) != 0) { - szcvec = 0; - goto again; - } - eoff = vn_a->offset & PAGEMASK; - if (eoff >= va.va_size) { - szcvec = 0; - goto again; - } - eoff += size; - if (btopr(va.va_size) < btopr(eoff)) { - save_size = size; - size = va.va_size - (vn_a->offset & PAGEMASK); - size = P2ROUNDUP_TYPED(size, PAGESIZE, size_t); - szcvec = map_execseg_pgszcvec(text, addr, size); - if (szcvec <= 1) { - size = save_size; - goto again; - } - } - eaddr = addr + size; save_szcvec = szcvec; szcvec >>= 1; @@ -1551,7 +1526,9 @@ again: return (error); } *segcreated = 1; - vn_a->offset += segsize; + if (do_off) { + vn_a->offset += segsize; + } addr = a; } szc = nszc; @@ -1576,7 +1553,9 @@ again: return (error); } *segcreated = 1; - vn_a->offset += segsize; + if (do_off) { + vn_a->offset += segsize; + } addr = a; } szcvec &= ~(1 << szc); @@ -1587,14 +1566,94 @@ again: } ASSERT(addr == eaddr); + return (0); +} + +static int +as_map_vnsegs(struct as *as, caddr_t addr, size_t size, + int (*crfp)(), struct segvn_crargs *vn_a, int *segcreated) +{ + int text = vn_a->flags & MAP_TEXT; + uint_t szcvec = map_execseg_pgszcvec(text, addr, size); + int error; + struct seg *seg; + struct vattr va; + u_offset_t eoff; + size_t save_size = 0; + + ASSERT(AS_WRITE_HELD(as, &as->a_lock)); + ASSERT(IS_P2ALIGNED(addr, PAGESIZE)); + ASSERT(IS_P2ALIGNED(size, PAGESIZE)); + ASSERT(vn_a->vp != NULL); + ASSERT(vn_a->amp == NULL); + +again: + if (szcvec <= 1) { + seg = seg_alloc(as, addr, size); + if (seg == NULL) { + return (ENOMEM); + } + vn_a->szc = 0; + error = (*crfp)(seg, vn_a); + if (error != 0) { + seg_free(seg); + } + return (error); + } + + va.va_mask = AT_SIZE; + if (VOP_GETATTR(vn_a->vp, &va, ATTR_HINT, vn_a->cred) != 0) { + szcvec = 0; + goto again; + } + eoff = vn_a->offset & PAGEMASK; + if (eoff >= va.va_size) { + szcvec = 0; + goto again; + } + eoff += size; + if (btopr(va.va_size) < btopr(eoff)) { + save_size = size; + size = va.va_size - (vn_a->offset & PAGEMASK); + size = P2ROUNDUP_TYPED(size, PAGESIZE, size_t); + szcvec = map_execseg_pgszcvec(text, addr, size); + if (szcvec <= 1) { + size = save_size; + goto again; + } + } + + error = as_map_segvn_segs(as, addr, size, szcvec, crfp, vn_a, + segcreated); + if (error != 0) { + return (error); + } if (save_size) { + addr += size; size = save_size - size; + szcvec = 0; goto again; } - return (0); } +static int +as_map_sham(struct as *as, caddr_t addr, size_t size, + int (*crfp)(), struct segvn_crargs *vn_a, int *segcreated) +{ + uint_t szcvec = map_shm_pgszcvec(addr, size, + vn_a->amp == NULL ? (uintptr_t)addr : + (uintptr_t)P2ROUNDUP(vn_a->offset, PAGESIZE)); + + ASSERT(AS_WRITE_HELD(as, &as->a_lock)); + ASSERT(IS_P2ALIGNED(addr, PAGESIZE)); + ASSERT(IS_P2ALIGNED(size, PAGESIZE)); + ASSERT(vn_a->vp == NULL); + + return (as_map_segvn_segs(as, addr, size, szcvec, + crfp, vn_a, segcreated)); +} + int as_map(struct as *as, caddr_t addr, size_t size, int (*crfp)(), void *argsp) { @@ -1636,10 +1695,15 @@ as_map_locked(struct as *as, caddr_t addr, size_t size, int (*crfp)(), return (ENOMEM); } - if (AS_MAP_VNSEGS_USELPGS(crfp, argsp)) { + if (AS_MAP_VNSEGS_USELPGS(crfp, argsp) || AS_MAP_SHAMP(crfp, argsp)) { int unmap = 0; - error = as_map_vnsegs(as, raddr, rsize, crfp, - (struct segvn_crargs *)argsp, &unmap); + if (AS_MAP_SHAMP(crfp, argsp)) { + error = as_map_sham(as, raddr, rsize, crfp, + (struct segvn_crargs *)argsp, &unmap); + } else { + error = as_map_vnsegs(as, raddr, rsize, crfp, + (struct segvn_crargs *)argsp, &unmap); + } if (error != 0) { AS_LOCK_EXIT(as, &as->a_lock); if (unmap) { |