summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/fs/proc/prdata.h57
-rw-r--r--usr/src/uts/common/fs/proc/prioctl.c159
-rw-r--r--usr/src/uts/common/fs/proc/prsubr.c247
-rw-r--r--usr/src/uts/common/fs/proc/prvnops.c124
4 files changed, 307 insertions, 280 deletions
diff --git a/usr/src/uts/common/fs/proc/prdata.h b/usr/src/uts/common/fs/proc/prdata.h
index 10d7b6e3a4..1294421f9f 100644
--- a/usr/src/uts/common/fs/proc/prdata.h
+++ b/usr/src/uts/common/fs/proc/prdata.h
@@ -2,9 +2,8 @@
* 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.
+ * Common Development and Distribution License (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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -39,6 +38,7 @@
#include <sys/prsystm.h>
#include <sys/model.h>
#include <sys/poll.h>
+#include <sys/list.h>
#ifdef __cplusplus
extern "C" {
@@ -268,6 +268,47 @@ extern int nproc_highbit; /* highbit(v.v_nproc) */
extern struct vnodeops *prvnodeops;
+/*
+ * Generic chained copyout buffers for procfs use.
+ * In order to prevent procfs from making huge oversize kmem_alloc calls,
+ * a list of smaller buffers can be concatenated and copied to userspace in
+ * sequence.
+ *
+ * The implementation is opaque.
+ *
+ * A user of this will perform the following steps:
+ *
+ * list_t listhead;
+ * struct my *mp;
+ *
+ * pr_iol_initlist(&listhead, sizeof (*mp), n);
+ * while (whatever) {
+ * mp = pr_iol_newbuf(&listhead, sizeof (*mp);
+ * ...
+ * error = ...
+ * }
+ *
+ * When done, depending on whether copyout() or uiomove() is supposed to
+ * be used for transferring the buffered data to userspace, call either:
+ *
+ * error = pr_iol_copyout_and_free(&listhead, &cmaddr, error);
+ *
+ * or else:
+ *
+ * error = pr_iol_uiomove_and_free(&listhead, uiop, error);
+ *
+ * These two functions will in any case kmem_free() all list items, but
+ * if an error occurred before they will not perform the copyout/uiomove.
+ * If copyout/uiomove are done, the passed target address / uio_t
+ * are updated. The error returned will either be the one passed in, or
+ * the error that occurred during copyout/uiomove.
+ */
+
+extern void pr_iol_initlist(list_t *head, size_t itemsize, int nitems);
+extern void * pr_iol_newbuf(list_t *head, size_t itemsize);
+extern int pr_iol_copyout_and_free(list_t *head, caddr_t *tgt, int errin);
+extern int pr_iol_uiomove_and_free(list_t *head, uio_t *uiop, int errin);
+
#if defined(_SYSCALL32_IMPL)
extern int prwritectl32(vnode_t *, struct uio *, cred_t *);
@@ -278,11 +319,11 @@ extern void prcvtusage32(struct prhusage *, prusage32_t *);
/* kludge to support old /proc interface */
#if !defined(_SYS_OLD_PROCFS_H)
-extern int prgetmap(proc_t *, int, prmap_t **, size_t *);
-extern int prgetxmap(proc_t *, prxmap_t **, size_t *);
+extern int prgetmap(proc_t *, int, list_t *);
+extern int prgetxmap(proc_t *, list_t *);
#if defined(_SYSCALL32_IMPL)
-extern int prgetmap32(proc_t *, int, prmap32_t **, size_t *);
-extern int prgetxmap32(proc_t *, prxmap32_t **, size_t *);
+extern int prgetmap32(proc_t *, int, list_t *);
+extern int prgetxmap32(proc_t *, list_t *);
#endif /* _SYSCALL32_IMPL */
#endif /* !_SYS_OLD_PROCFS_H */
diff --git a/usr/src/uts/common/fs/proc/prioctl.c b/usr/src/uts/common/fs/proc/prioctl.c
index 844a3b7bb1..1eb2861b0f 100644
--- a/usr/src/uts/common/fs/proc/prioctl.c
+++ b/usr/src/uts/common/fs/proc/prioctl.c
@@ -2,9 +2,8 @@
* 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.
+ * Common Development and Distribution License (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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -85,7 +84,7 @@ static void prsetrun(kthread_t *, prrun_t *);
static int propenm(prnode_t *, caddr_t, caddr_t, int *, cred_t *);
extern void oprgetstatus(kthread_t *, prstatus_t *, zone_t *);
extern void oprgetpsinfo(proc_t *, prpsinfo_t *, kthread_t *);
-static int oprgetmap(proc_t *, prmap_t **, size_t *);
+static int oprgetmap(proc_t *, list_t *);
/*ARGSUSED*/
static int
@@ -957,29 +956,32 @@ startover:
case PIOCMAP: /* get memory map information */
{
- int n;
- prmap_t *prmapp;
- size_t size;
+ list_t iolhead;
struct as *as = p->p_as;
- int issys = ((p->p_flag & SSYS) || as == &kas);
- if (issys) {
- n = 1;
- prmapp = &un.prmap;
- bzero(prmapp, sizeof (*prmapp));
+ if ((p->p_flag & SSYS) || as == &kas) {
+ error = 0;
+ prunlock(pnp);
} else {
mutex_exit(&p->p_lock);
AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
- n = oprgetmap(p, &prmapp, &size);
+ error = oprgetmap(p, &iolhead);
AS_LOCK_EXIT(as, &as->a_lock);
mutex_enter(&p->p_lock);
- }
- prunlock(pnp);
+ prunlock(pnp);
- if (copyout(prmapp, cmaddr, n * sizeof (prmap_t)))
+ error = pr_iol_copyout_and_free(&iolhead,
+ &cmaddr, error);
+ }
+ /*
+ * The procfs PIOCMAP ioctl returns an all-zero buffer
+ * to indicate the end of the prmap[] array.
+ * Append it to whatever has already been copied out.
+ */
+ bzero(&un.prmap, sizeof (un.prmap));
+ if (!error && copyout(&un.prmap, cmaddr, sizeof (un.prmap)))
error = EFAULT;
- if (!issys)
- kmem_free(prmapp, size);
+
break;
}
@@ -1311,7 +1313,7 @@ startover:
#ifdef _SYSCALL32_IMPL
-static int oprgetmap32(proc_t *, ioc_prmap32_t **, size_t *);
+static int oprgetmap32(proc_t *, list_t *);
void
oprgetstatus32(kthread_t *t, prstatus32_t *sp, zone_t *zp)
@@ -2567,33 +2569,35 @@ startover:
case PIOCMAP: /* get memory map information */
{
- int n;
- ioc_prmap32_t *prmapp;
- size_t size;
+ list_t iolhead;
struct as *as = p->p_as;
- int issys = ((p->p_flag & SSYS) || as == &kas);
- if (issys) {
- n = 1;
- prmapp = &un32.prmap;
- bzero(prmapp, sizeof (*prmapp));
+ if ((p->p_flag & SSYS) || as == &kas) {
+ error = 0;
+ prunlock(pnp);
} else if (PROCESS_NOT_32BIT(p)) {
error = EOVERFLOW;
prunlock(pnp);
- break;
} else {
mutex_exit(&p->p_lock);
AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
- n = oprgetmap32(p, &prmapp, &size);
+ error = oprgetmap32(p, &iolhead);
AS_LOCK_EXIT(as, &as->a_lock);
mutex_enter(&p->p_lock);
- }
- prunlock(pnp);
+ prunlock(pnp);
- if (copyout(prmapp, cmaddr, n * sizeof (ioc_prmap32_t)))
- error = EFAULT;
- if (!issys)
- kmem_free(prmapp, size);
+ error = pr_iol_copyout_and_free(&iolhead,
+ &cmaddr, error);
+ }
+ /*
+ * The procfs PIOCMAP ioctl returns an all-zero buffer
+ * to indicate the end of the prmap[] array.
+ * Append it to whatever has already been copied out.
+ */
+ bzero(&un32.prmap, sizeof (un32.prmap));
+ if (!error &&
+ copyout(&un32.prmap, cmaddr, sizeof (un32.prmap)))
+ error = EFAULT;
break;
}
@@ -3468,32 +3472,29 @@ oprgetpsinfo(proc_t *p, prpsinfo_t *psp, kthread_t *tp)
/*
* Return an array of structures with memory map information.
- * In addition to the "real" segments we need space for the
- * zero-filled entry that terminates the list.
* We allocate here; the caller must deallocate.
+ * The caller is also responsible to append the zero-filled entry
+ * that terminates the PIOCMAP output buffer.
*/
-#define MAPSIZE 8192
static int
-oprgetmap(proc_t *p, prmap_t **prmapp, size_t *sizep)
+oprgetmap(proc_t *p, list_t *iolhead)
{
struct as *as = p->p_as;
- int nmaps = 0;
prmap_t *mp;
- size_t size;
struct seg *seg;
struct seg *brkseg, *stkseg;
uint_t prot;
ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
- /* initial allocation */
- *sizep = size = MAPSIZE;
- *prmapp = mp = kmem_alloc(MAPSIZE, KM_SLEEP);
+ /*
+ * Request an initial buffer size that doesn't waste memory
+ * if the address space has only a small number of segments.
+ */
+ pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
- if ((seg = AS_SEGFIRST(as)) == NULL) {
- bzero(mp, sizeof (*mp));
- return (1);
- }
+ if ((seg = AS_SEGFIRST(as)) == NULL)
+ return (0);
brkseg = break_seg(p);
stkseg = as_segat(as, prgetstackbase(p));
@@ -3507,18 +3508,9 @@ oprgetmap(proc_t *p, prmap_t **prmapp, size_t *sizep)
prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
if (saddr == naddr)
continue;
- /* reallocate if necessary */
- if ((nmaps + 2) * sizeof (prmap_t) > size) {
- size_t newsize = size + MAPSIZE;
- prmap_t *newmp = kmem_alloc(newsize, KM_SLEEP);
-
- bcopy(*prmapp, newmp, nmaps * sizeof (prmap_t));
- kmem_free(*prmapp, size);
- *sizep = size = newsize;
- *prmapp = newmp;
- mp = newmp + nmaps;
- }
- bzero(mp, sizeof (*mp));
+
+ mp = pr_iol_newbuf(iolhead, sizeof (*mp));
+
mp->pr_vaddr = saddr;
mp->pr_size = naddr - saddr;
mp->pr_off = SEGOP_GETOFFSET(seg, saddr);
@@ -3536,38 +3528,33 @@ oprgetmap(proc_t *p, prmap_t **prmapp, size_t *sizep)
else if (seg == stkseg)
mp->pr_mflags |= MA_STACK;
mp->pr_pagesize = PAGESIZE;
- mp++;
- nmaps++;
}
ASSERT(tmp == NULL);
} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
- bzero(mp, sizeof (*mp));
- return (nmaps + 1);
+ return (0);
}
#ifdef _SYSCALL32_IMPL
static int
-oprgetmap32(proc_t *p, ioc_prmap32_t **prmapp, size_t *sizep)
+oprgetmap32(proc_t *p, list_t *iolhead)
{
struct as *as = p->p_as;
- int nmaps = 0;
ioc_prmap32_t *mp;
- size_t size;
struct seg *seg;
struct seg *brkseg, *stkseg;
uint_t prot;
ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
- /* initial allocation */
- *sizep = size = MAPSIZE;
- *prmapp = mp = kmem_alloc(MAPSIZE, KM_SLEEP);
+ /*
+ * Request an initial buffer size that doesn't waste memory
+ * if the address space has only a small number of segments.
+ */
+ pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
- if ((seg = AS_SEGFIRST(as)) == NULL) {
- bzero(mp, sizeof (*mp));
- return (1);
- }
+ if ((seg = AS_SEGFIRST(as)) == NULL)
+ return (0);
brkseg = break_seg(p);
stkseg = as_segat(as, prgetstackbase(p));
@@ -3581,20 +3568,9 @@ oprgetmap32(proc_t *p, ioc_prmap32_t **prmapp, size_t *sizep)
prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
if (saddr == naddr)
continue;
- /* reallocate if necessary */
- if ((nmaps + 2) * sizeof (ioc_prmap32_t) > size) {
- size_t newsize = size + MAPSIZE;
- ioc_prmap32_t *newmp =
- kmem_alloc(newsize, KM_SLEEP);
-
- bcopy(*prmapp, newmp,
- nmaps * sizeof (ioc_prmap32_t));
- kmem_free(*prmapp, size);
- *sizep = size = newsize;
- *prmapp = newmp;
- mp = newmp + nmaps;
- }
- bzero(mp, sizeof (*mp));
+
+ mp = pr_iol_newbuf(iolhead, sizeof (*mp));
+
mp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
mp->pr_size = (size32_t)(naddr - saddr);
mp->pr_off = (off32_t)SEGOP_GETOFFSET(seg, saddr);
@@ -3612,14 +3588,11 @@ oprgetmap32(proc_t *p, ioc_prmap32_t **prmapp, size_t *sizep)
else if (seg == stkseg)
mp->pr_mflags |= MA_STACK;
mp->pr_pagesize = PAGESIZE;
- mp++;
- nmaps++;
}
ASSERT(tmp == NULL);
} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
- bzero(mp, sizeof (*mp));
- return (nmaps + 1);
+ return (0);
}
#endif /* _SYSCALL32_IMPL */
diff --git a/usr/src/uts/common/fs/proc/prsubr.c b/usr/src/uts/common/fs/proc/prsubr.c
index e1931414ec..619666e5a8 100644
--- a/usr/src/uts/common/fs/proc/prsubr.c
+++ b/usr/src/uts/common/fs/proc/prsubr.c
@@ -86,6 +86,7 @@
#include <sys/pool.h>
#include <sys/zone.h>
#include <sys/atomic.h>
+#include <sys/sdt.h>
#define MAX_ITERS_SPIN 5
@@ -1475,18 +1476,130 @@ break_seg(proc_t *p)
}
/*
+ * Implementation of service functions to handle procfs generic chained
+ * copyout buffers.
+ */
+typedef struct pr_iobuf_list {
+ list_node_t piol_link; /* buffer linkage */
+ size_t piol_size; /* total size (header + data) */
+ size_t piol_usedsize; /* amount to copy out from this buf */
+} piol_t;
+
+#define MAPSIZE (64 * 1024)
+#define PIOL_DATABUF(iol) ((void *)(&(iol)[1]))
+
+void
+pr_iol_initlist(list_t *iolhead, size_t itemsize, int n)
+{
+ piol_t *iol;
+ size_t initial_size = MIN(1, n) * itemsize;
+
+ list_create(iolhead, sizeof (piol_t), offsetof(piol_t, piol_link));
+
+ ASSERT(list_head(iolhead) == NULL);
+ ASSERT(itemsize < MAPSIZE - sizeof (*iol));
+ ASSERT(initial_size > 0);
+
+ /*
+ * Someone creating chained copyout buffers may ask for less than
+ * MAPSIZE if the amount of data to be buffered is known to be
+ * smaller than that.
+ * But in order to prevent involuntary self-denial of service,
+ * the requested input size is clamped at MAPSIZE.
+ */
+ initial_size = MIN(MAPSIZE, initial_size + sizeof (*iol));
+ iol = kmem_alloc(initial_size, KM_SLEEP);
+ list_insert_head(iolhead, iol);
+ iol->piol_usedsize = 0;
+ iol->piol_size = initial_size;
+}
+
+void *
+pr_iol_newbuf(list_t *iolhead, size_t itemsize)
+{
+ piol_t *iol;
+ char *new;
+
+ ASSERT(itemsize < MAPSIZE - sizeof (*iol));
+ ASSERT(list_head(iolhead) != NULL);
+
+ iol = (piol_t *)list_tail(iolhead);
+
+ if (iol->piol_size <
+ iol->piol_usedsize + sizeof (*iol) + itemsize) {
+ /*
+ * Out of space in the current buffer. Allocate more.
+ */
+ piol_t *newiol;
+
+ newiol = kmem_alloc(MAPSIZE, KM_SLEEP);
+ newiol->piol_size = MAPSIZE;
+ newiol->piol_usedsize = 0;
+
+ list_insert_after(iolhead, iol, newiol);
+ iol = list_next(iolhead, iol);
+ ASSERT(iol == newiol);
+ }
+ new = (char *)PIOL_DATABUF(iol) + iol->piol_usedsize;
+ iol->piol_usedsize += itemsize;
+ bzero(new, itemsize);
+ return (new);
+}
+
+int
+pr_iol_copyout_and_free(list_t *iolhead, caddr_t *tgt, int errin)
+{
+ int error = errin;
+ piol_t *iol;
+
+ while ((iol = list_head(iolhead)) != NULL) {
+ list_remove(iolhead, iol);
+ if (!error) {
+ if (copyout(PIOL_DATABUF(iol), *tgt,
+ iol->piol_usedsize))
+ error = EFAULT;
+ *tgt += iol->piol_usedsize;
+ }
+ kmem_free(iol, iol->piol_size);
+ }
+ list_destroy(iolhead);
+
+ return (error);
+}
+
+int
+pr_iol_uiomove_and_free(list_t *iolhead, uio_t *uiop, int errin)
+{
+ offset_t off = uiop->uio_offset;
+ char *base;
+ size_t size;
+ piol_t *iol;
+ int error = errin;
+
+ while ((iol = list_head(iolhead)) != NULL) {
+ list_remove(iolhead, iol);
+ base = PIOL_DATABUF(iol);
+ size = iol->piol_usedsize;
+ if (off <= size && error == 0 && uiop->uio_resid > 0)
+ error = uiomove(base + off, size - off,
+ UIO_READ, uiop);
+ off = MAX(0, off - (offset_t)size);
+ kmem_free(iol, iol->piol_size);
+ }
+ list_destroy(iolhead);
+
+ return (error);
+}
+
+/*
* Return an array of structures with memory map information.
* We allocate here; the caller must deallocate.
*/
-#define INITIAL_MAPSIZE 65536
-#define MAPSIZE 8192
int
-prgetmap(proc_t *p, int reserved, prmap_t **prmapp, size_t *sizep)
+prgetmap(proc_t *p, int reserved, list_t *iolhead)
{
struct as *as = p->p_as;
- int nmaps = 0;
prmap_t *mp;
- size_t size;
struct seg *seg;
struct seg *brkseg, *stkseg;
struct vnode *vp;
@@ -1495,9 +1608,11 @@ prgetmap(proc_t *p, int reserved, prmap_t **prmapp, size_t *sizep)
ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
- /* initial allocation */
- *sizep = size = INITIAL_MAPSIZE;
- *prmapp = mp = kmem_alloc(size, KM_SLEEP);
+ /*
+ * Request an initial buffer size that doesn't waste memory
+ * if the address space has only a small number of segments.
+ */
+ pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
if ((seg = AS_SEGFIRST(as)) == NULL)
return (0);
@@ -1515,18 +1630,9 @@ prgetmap(proc_t *p, int reserved, prmap_t **prmapp, size_t *sizep)
&saddr, &naddr, eaddr);
if (saddr == naddr)
continue;
- /* reallocate if necessary */
- if ((nmaps + 1) * sizeof (prmap_t) > size) {
- size_t newsize = size + 3 * size / 16;
- prmap_t *newmp = kmem_alloc(newsize, KM_SLEEP);
-
- bcopy(*prmapp, newmp, nmaps * sizeof (prmap_t));
- kmem_free(*prmapp, size);
- *sizep = size = newsize;
- *prmapp = newmp;
- mp = newmp + nmaps;
- }
- bzero(mp, sizeof (*mp));
+
+ mp = pr_iol_newbuf(iolhead, sizeof (*mp));
+
mp->pr_vaddr = (uintptr_t)saddr;
mp->pr_size = naddr - saddr;
mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
@@ -1592,24 +1698,19 @@ prgetmap(proc_t *p, int reserved, prmap_t **prmapp, size_t *sizep)
} else {
mp->pr_shmid = -1;
}
-
- mp++;
- nmaps++;
}
ASSERT(tmp == NULL);
} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
- return (nmaps);
+ return (0);
}
#ifdef _SYSCALL32_IMPL
int
-prgetmap32(proc_t *p, int reserved, prmap32_t **prmapp, size_t *sizep)
+prgetmap32(proc_t *p, int reserved, list_t *iolhead)
{
struct as *as = p->p_as;
- int nmaps = 0;
prmap32_t *mp;
- size_t size;
struct seg *seg;
struct seg *brkseg, *stkseg;
struct vnode *vp;
@@ -1618,9 +1719,11 @@ prgetmap32(proc_t *p, int reserved, prmap32_t **prmapp, size_t *sizep)
ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
- /* initial allocation */
- *sizep = size = INITIAL_MAPSIZE;
- *prmapp = mp = kmem_alloc(size, KM_SLEEP);
+ /*
+ * Request an initial buffer size that doesn't waste memory
+ * if the address space has only a small number of segments.
+ */
+ pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
if ((seg = AS_SEGFIRST(as)) == NULL)
return (0);
@@ -1638,20 +1741,9 @@ prgetmap32(proc_t *p, int reserved, prmap32_t **prmapp, size_t *sizep)
&saddr, &naddr, eaddr);
if (saddr == naddr)
continue;
- /* reallocate if necessary */
- if ((nmaps + 1) * sizeof (prmap32_t) > size) {
- size_t newsize = size + 3 * size / 16;
- prmap32_t *newmp =
- kmem_alloc(newsize, KM_SLEEP);
-
- bcopy(*prmapp, newmp,
- nmaps * sizeof (prmap32_t));
- kmem_free(*prmapp, size);
- *sizep = size = newsize;
- *prmapp = newmp;
- mp = newmp + nmaps;
- }
- bzero(mp, sizeof (*mp));
+
+ mp = pr_iol_newbuf(iolhead, sizeof (*mp));
+
mp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
mp->pr_size = (size32_t)(naddr - saddr);
mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
@@ -1718,14 +1810,11 @@ prgetmap32(proc_t *p, int reserved, prmap32_t **prmapp, size_t *sizep)
} else {
mp->pr_shmid = -1;
}
-
- mp++;
- nmaps++;
}
ASSERT(tmp == NULL);
} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
- return (nmaps);
+ return (0);
}
#endif /* _SYSCALL32_IMPL */
@@ -3791,12 +3880,10 @@ pr_getpagesize(struct seg *seg, caddr_t saddr, caddr_t *naddrp, caddr_t eaddr)
* We allocate here; the caller must deallocate.
*/
int
-prgetxmap(proc_t *p, prxmap_t **prxmapp, size_t *sizep)
+prgetxmap(proc_t *p, list_t *iolhead)
{
struct as *as = p->p_as;
- int nmaps = 0;
prxmap_t *mp;
- size_t size;
struct seg *seg;
struct seg *brkseg, *stkseg;
struct vnode *vp;
@@ -3805,9 +3892,11 @@ prgetxmap(proc_t *p, prxmap_t **prxmapp, size_t *sizep)
ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
- /* initial allocation */
- *sizep = size = INITIAL_MAPSIZE;
- *prxmapp = mp = kmem_alloc(size, KM_SLEEP);
+ /*
+ * Request an initial buffer size that doesn't waste memory
+ * if the address space has only a small number of segments.
+ */
+ pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
if ((seg = AS_SEGFIRST(as)) == NULL)
return (0);
@@ -3843,21 +3932,8 @@ prgetxmap(proc_t *p, prxmap_t **prxmapp, size_t *sizep)
psz = pr_getpagesize(seg, saddr, &naddr, baddr);
ASSERT(naddr >= saddr && naddr <= baddr);
- /* reallocate if necessary */
- if ((nmaps + 1) * sizeof (prxmap_t) > size) {
- size_t newsize = size + 3 * size / 16;
- prxmap_t *newmp =
- kmem_alloc(newsize, KM_SLEEP);
-
- bcopy(*prxmapp, newmp,
- nmaps * sizeof (prxmap_t));
- kmem_free(*prxmapp, size);
- *sizep = size = newsize;
- *prxmapp = newmp;
- mp = newmp + nmaps;
- }
+ mp = pr_iol_newbuf(iolhead, sizeof (*mp));
- bzero(mp, sizeof (*mp));
mp->pr_vaddr = (uintptr_t)saddr;
mp->pr_size = naddr - saddr;
mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
@@ -3939,14 +4015,12 @@ prgetxmap(proc_t *p, prxmap_t **prxmapp, size_t *sizep)
mp->pr_locked++;
}
kmem_free(parr, npages);
- mp++;
- nmaps++;
}
}
ASSERT(tmp == NULL);
} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
- return (nmaps);
+ return (0);
}
/*
@@ -3989,12 +4063,10 @@ prgetpriv(proc_t *p, prpriv_t *pprp)
* We allocate here; the caller must deallocate.
*/
int
-prgetxmap32(proc_t *p, prxmap32_t **prxmapp, size_t *sizep)
+prgetxmap32(proc_t *p, list_t *iolhead)
{
struct as *as = p->p_as;
- int nmaps = 0;
prxmap32_t *mp;
- size_t size;
struct seg *seg;
struct seg *brkseg, *stkseg;
struct vnode *vp;
@@ -4003,9 +4075,11 @@ prgetxmap32(proc_t *p, prxmap32_t **prxmapp, size_t *sizep)
ASSERT(as != &kas && AS_WRITE_HELD(as, &as->a_lock));
- /* initial allocation */
- *sizep = size = INITIAL_MAPSIZE;
- *prxmapp = mp = kmem_alloc(size, KM_SLEEP);
+ /*
+ * Request an initial buffer size that doesn't waste memory
+ * if the address space has only a small number of segments.
+ */
+ pr_iol_initlist(iolhead, sizeof (*mp), avl_numnodes(&as->a_segtree));
if ((seg = AS_SEGFIRST(as)) == NULL)
return (0);
@@ -4041,21 +4115,8 @@ prgetxmap32(proc_t *p, prxmap32_t **prxmapp, size_t *sizep)
psz = pr_getpagesize(seg, saddr, &naddr, baddr);
ASSERT(naddr >= saddr && naddr <= baddr);
- /* reallocate if necessary */
- if ((nmaps + 1) * sizeof (prxmap32_t) > size) {
- size_t newsize = size + 3 * size / 16;
- prxmap32_t *newmp =
- kmem_alloc(newsize, KM_SLEEP);
-
- bcopy(*prxmapp, newmp,
- nmaps * sizeof (prxmap32_t));
- kmem_free(*prxmapp, size);
- *sizep = size = newsize;
- *prxmapp = newmp;
- mp = newmp + nmaps;
- }
+ mp = pr_iol_newbuf(iolhead, sizeof (*mp));
- bzero(mp, sizeof (*mp));
mp->pr_vaddr = (caddr32_t)(uintptr_t)saddr;
mp->pr_size = (size32_t)(naddr - saddr);
mp->pr_offset = SEGOP_GETOFFSET(seg, saddr);
@@ -4138,13 +4199,11 @@ prgetxmap32(proc_t *p, prxmap32_t **prxmapp, size_t *sizep)
mp->pr_locked++;
}
kmem_free(parr, npages);
- mp++;
- nmaps++;
}
}
ASSERT(tmp == NULL);
} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
- return (nmaps);
+ return (0);
}
#endif /* _SYSCALL32_IMPL */
diff --git a/usr/src/uts/common/fs/proc/prvnops.c b/usr/src/uts/common/fs/proc/prvnops.c
index d12ee64e8c..3f15bb084f 100644
--- a/usr/src/uts/common/fs/proc/prvnops.c
+++ b/usr/src/uts/common/fs/proc/prvnops.c
@@ -2,9 +2,8 @@
* 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.
+ * Common Development and Distribution License (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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -857,13 +856,11 @@ pr_read_lpsinfo(prnode_t *pnp, uio_t *uiop)
}
static int
-pr_read_map_common(prnode_t *pnp, uio_t *uiop, int reserved)
+pr_read_map_common(prnode_t *pnp, uio_t *uiop, prnodetype_t type)
{
proc_t *p;
struct as *as;
- int nmaps;
- prmap_t *prmapp;
- size_t size;
+ list_t iolhead;
int error;
if ((error = prlock(pnp, ZNO)) != 0)
@@ -879,13 +876,23 @@ pr_read_map_common(prnode_t *pnp, uio_t *uiop, int reserved)
mutex_exit(&p->p_lock);
AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
- nmaps = prgetmap(p, reserved, &prmapp, &size);
+ switch (type) {
+ case PR_XMAP:
+ error = prgetxmap(p, &iolhead);
+ break;
+ case PR_RMAP:
+ error = prgetmap(p, 1, &iolhead);
+ break;
+ case PR_MAP:
+ error = prgetmap(p, 0, &iolhead);
+ break;
+ }
AS_LOCK_EXIT(as, &as->a_lock);
mutex_enter(&p->p_lock);
prunlock(pnp);
- error = pr_uioread(prmapp, nmaps * sizeof (prmap_t), uiop);
- kmem_free(prmapp, size);
+ error = pr_iol_uiomove_and_free(&iolhead, uiop, error);
+
return (error);
}
@@ -893,49 +900,21 @@ static int
pr_read_map(prnode_t *pnp, uio_t *uiop)
{
ASSERT(pnp->pr_type == PR_MAP);
- return (pr_read_map_common(pnp, uiop, 0));
+ return (pr_read_map_common(pnp, uiop, pnp->pr_type));
}
static int
pr_read_rmap(prnode_t *pnp, uio_t *uiop)
{
ASSERT(pnp->pr_type == PR_RMAP);
- return (pr_read_map_common(pnp, uiop, 1));
+ return (pr_read_map_common(pnp, uiop, pnp->pr_type));
}
static int
pr_read_xmap(prnode_t *pnp, uio_t *uiop)
{
- proc_t *p;
- struct as *as;
- int nmems;
- prxmap_t *prxmapp;
- size_t size;
- int error;
-
ASSERT(pnp->pr_type == PR_XMAP);
-
- if ((error = prlock(pnp, ZNO)) != 0)
- return (error);
-
- p = pnp->pr_common->prc_proc;
- as = p->p_as;
-
- if ((p->p_flag & SSYS) || as == &kas) {
- prunlock(pnp);
- return (0);
- }
-
- mutex_exit(&p->p_lock);
- AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
- nmems = prgetxmap(p, &prxmapp, &size);
- AS_LOCK_EXIT(as, &as->a_lock);
- mutex_enter(&p->p_lock);
- prunlock(pnp);
-
- error = pr_uioread(prxmapp, nmems * sizeof (prxmap_t), uiop);
- kmem_free(prxmapp, size);
- return (error);
+ return (pr_read_map_common(pnp, uiop, pnp->pr_type));
}
static int
@@ -1954,13 +1933,11 @@ pr_read_lpsinfo_32(prnode_t *pnp, uio_t *uiop)
}
static int
-pr_read_map_common_32(prnode_t *pnp, uio_t *uiop, int reserved)
+pr_read_map_common_32(prnode_t *pnp, uio_t *uiop, prnodetype_t type)
{
proc_t *p;
struct as *as;
- int nmaps;
- prmap32_t *prmapp;
- size_t size;
+ list_t iolhead;
int error;
if ((error = prlock(pnp, ZNO)) != 0)
@@ -1981,13 +1958,23 @@ pr_read_map_common_32(prnode_t *pnp, uio_t *uiop, int reserved)
mutex_exit(&p->p_lock);
AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
- nmaps = prgetmap32(p, reserved, &prmapp, &size);
+ switch (type) {
+ case PR_XMAP:
+ error = prgetxmap32(p, &iolhead);
+ break;
+ case PR_RMAP:
+ error = prgetmap32(p, 1, &iolhead);
+ break;
+ case PR_MAP:
+ error = prgetmap32(p, 0, &iolhead);
+ break;
+ }
AS_LOCK_EXIT(as, &as->a_lock);
mutex_enter(&p->p_lock);
prunlock(pnp);
- error = pr_uioread(prmapp, nmaps * sizeof (prmap32_t), uiop);
- kmem_free(prmapp, size);
+ error = pr_iol_uiomove_and_free(&iolhead, uiop, error);
+
return (error);
}
@@ -1995,54 +1982,21 @@ static int
pr_read_map_32(prnode_t *pnp, uio_t *uiop)
{
ASSERT(pnp->pr_type == PR_MAP);
- return (pr_read_map_common_32(pnp, uiop, 0));
+ return (pr_read_map_common_32(pnp, uiop, pnp->pr_type));
}
static int
pr_read_rmap_32(prnode_t *pnp, uio_t *uiop)
{
ASSERT(pnp->pr_type == PR_RMAP);
- return (pr_read_map_common_32(pnp, uiop, 1));
+ return (pr_read_map_common_32(pnp, uiop, pnp->pr_type));
}
static int
pr_read_xmap_32(prnode_t *pnp, uio_t *uiop)
{
- proc_t *p;
- struct as *as;
- int nmems;
- prxmap32_t *prxmapp;
- size_t size;
- int error;
-
ASSERT(pnp->pr_type == PR_XMAP);
-
- if ((error = prlock(pnp, ZNO)) != 0)
- return (error);
-
- p = pnp->pr_common->prc_proc;
- as = p->p_as;
-
- if ((p->p_flag & SSYS) || as == &kas) {
- prunlock(pnp);
- return (0);
- }
-
- if (PROCESS_NOT_32BIT(p)) {
- prunlock(pnp);
- return (EOVERFLOW);
- }
-
- mutex_exit(&p->p_lock);
- AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
- nmems = prgetxmap32(p, &prxmapp, &size);
- AS_LOCK_EXIT(as, &as->a_lock);
- mutex_enter(&p->p_lock);
- prunlock(pnp);
-
- error = pr_uioread(prxmapp, nmems * sizeof (prxmap32_t), uiop);
- kmem_free(prxmapp, size);
- return (error);
+ return (pr_read_map_common_32(pnp, uiop, pnp->pr_type));
}
static int