Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/compat/linux/common handle mmap() request with MAP_GROWS...



details:   https://anonhg.NetBSD.org/src/rev/81107f925508
branches:  trunk
changeset: 569680:81107f925508
user:      jdolecek <jdolecek%NetBSD.org@localhost>
date:      Sun Aug 29 14:08:06 2004 +0000

description:
handle mmap() request with MAP_GROWSDOWN flag (request for stack-like
grow-down auto extend segment) by allocating segment sized at
current stack size limit, and offsetting requested/returned address
as required

due to how normal virtual memory management work, allocating the
full sized stack memory segment up-front actually requires exactly same
amount of VA space and physical memory as the Linux 'grow' scheme and the
'grow' scheme is quite a lot more difficult to use in applications correctly,
so it's not very apparent why Linux introduced this feature at all

this fixes Thomas Klausner's Heroes3 crash, and might also
fix PR 26687 by Jan Schaumann

diffstat:

 sys/compat/linux/common/linux_misc.c |  66 +++++++++++++++++++++++++++++++----
 1 files changed, 57 insertions(+), 9 deletions(-)

diffs (109 lines):

diff -r c69640a2446b -r 81107f925508 sys/compat/linux/common/linux_misc.c
--- a/sys/compat/linux/common/linux_misc.c      Sun Aug 29 13:26:17 2004 +0000
+++ b/sys/compat/linux/common/linux_misc.c      Sun Aug 29 14:08:06 2004 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: linux_misc.c,v 1.127 2004/08/08 09:40:50 jdolecek Exp $        */
+/*     $NetBSD: linux_misc.c,v 1.128 2004/08/29 14:08:06 jdolecek Exp $        */
 
 /*-
  * Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc.
@@ -64,7 +64,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_misc.c,v 1.127 2004/08/08 09:40:50 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_misc.c,v 1.128 2004/08/29 14:08:06 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -173,6 +173,9 @@
 static int linux_to_bsd_limit __P((int));
 static void linux_to_bsd_mmap_args __P((struct sys_mmap_args *,
     const struct linux_sys_mmap_args *));
+static int linux_mmap __P((struct lwp *, struct linux_sys_mmap_args *,
+    register_t *, off_t));
+
 
 /*
  * The information on a terminated (or stopped) process needs
@@ -453,15 +456,11 @@
                syscallarg(int) fd;
                syscallarg(linux_off_t) offset;
        } */ *uap = v;
-       struct sys_mmap_args cma;
 
        if (SCARG(uap, offset) & PAGE_MASK)
                return EINVAL;
 
-       linux_to_bsd_mmap_args(&cma, uap);
-       SCARG(&cma, pos) = (off_t)SCARG(uap, offset);
-
-       return sys_mmap(l, &cma, retval);
+       return linux_mmap(l, uap, retval, SCARG(uap, offset));
 }
 
 /*
@@ -487,12 +486,61 @@
                syscallarg(int) fd;
                syscallarg(linux_off_t) offset;
        } */ *uap = v;
+
+       return linux_mmap(l, uap, retval,
+           ((off_t)SCARG(uap, offset)) << PAGE_SHIFT);
+}
+
+/*
+ * Massage arguments and call system mmap(2).
+ */
+static int
+linux_mmap(l, uap, retval, offset)
+       struct lwp *l;
+       struct linux_sys_mmap_args *uap;
+       register_t *retval;
+       off_t offset;
+{
        struct sys_mmap_args cma;
+       int error;
+       size_t mmoff=0;
+
+       if (SCARG(uap, flags) & LINUX_MAP_GROWSDOWN) {
+               /*
+                * Request for stack-like memory segment. On linux, this
+                * works by mmap()ping (small) segment, which is automatically
+                * extended when page fault happens below the currently
+                * allocated area. We emulate this by allocating (typically
+                * bigger) segment sized at current stack size limit, and
+                * offsetting the requested and returned address accordingly.
+                * Since physical pages are only allocated on-demand, this
+                * is effectively identical.
+                */
+               rlim_t ssl = l->l_proc->p_rlimit[RLIMIT_STACK].rlim_cur;
+
+               if (SCARG(uap, len) < ssl) {
+                       /* Compute the address offset */
+                       mmoff = round_page(ssl) - SCARG(uap, len);
+
+                       if (SCARG(uap, addr))
+                               SCARG(uap, addr) -= mmoff;
+
+                       SCARG(uap, len) = (size_t) ssl;
+               }
+       }
 
        linux_to_bsd_mmap_args(&cma, uap);
-       SCARG(&cma, pos) = ((off_t)SCARG(uap, offset)) << PAGE_SHIFT;
+       SCARG(&cma, pos) = offset;
+
+       error = sys_mmap(l, &cma, retval);
+       if (error)
+               return (error);
 
-       return sys_mmap(l, &cma, retval);
+       /* Shift the returned address for stack-like segment if necessary */
+       if (SCARG(uap, flags) & LINUX_MAP_GROWSDOWN && mmoff)
+               retval[0] += mmoff;
+
+       return (0);
 }
 
 static void



Home | Main Index | Thread Index | Old Index