summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/vm/vm_as.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/vm/vm_as.c')
-rw-r--r--usr/src/uts/common/vm/vm_as.c140
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) {