Subject: Allow mmap(2) hint to be taken literally (patch)
To: None <tech-kern@netbsd.org>
From: Todd Vierling <tv@pobox.com>
List: tech-kern
Date: 06/20/2003 12:02:46
While attempting to get CrossOver Office (http://www.codeweavers.com/)
running under NetBSD 1.6.1, I hit upon the known mmap(2) incompatibility
where NetBSD's mmap does not work the same as Linux's mmap when a hint is
provided and MAP_FIXED is *not* set.

This was originally described here:

  http://mail-index.netbsd.org/tech-kern/2001/11/18/0000.html

but the patch there is very intrusive into NetBSD's native mmap(2) handling.

One of the requirements here to get CrossOver running will be to provide
this behavior (actually, an even looser form of the above), but specifically
for Linux emulation mmap(2).  This isn't such a big deal, as I could rip out
the guts of sys_mmap() and plonk it into linux_sys_mmap() if need be.

After thinking about it a bit, though, I thought it might be useful to offer
this behavior even under NetBSD, provided a given flag was present to
mmap(2).  The patch below provides a new option to mmap(2), called
MAP_TRYFIXED, which indicates that mmap(2) will *not* try to skip the heap
space when attempting a mapping at the provided hint address.  This was
inspired by another message in the above thread:

http://mail-index.netbsd.org/tech-kern/2001/11/21/0015.html

The effect is that the caller can now try to mmap an absolute file location,
but still get a non-absolute mapping if the asbolute address is "truly"
unavailable (i.e. not in the vm_map).  This flag could only be used by a
process that understands what it is doing -- and in particular, is not using
NetBSD's sbrk heap space.

Comments?  (Also, if you know that there is precedent here on some other
*ix, please let me know.)

=====

Note that the compat/linux/common/linux_misc.c diff should still apply
correctly (with fuzz and offset) if the diff from kern/21937 is committed.

Index: compat/linux/common/linux_misc.c
===================================================================
RCS file: /cvsroot/src/sys/compat/linux/common/linux_misc.c,v
retrieving revision 1.109.4.2
diff -u -r1.109.4.2 linux_misc.c
--- compat/linux/common/linux_misc.c	2002/12/12 21:29:13	1.109.4.2
+++ compat/linux/common/linux_misc.c	2003/06/20 16:00:50
@@ -446,7 +446,7 @@
 	struct sys_mmap_args cma;
 	int flags, fl = SCARG(uap, flags);

-	flags = 0;
+	flags = MAP_TRYFIXED;
 	flags |= cvtto_bsd_mask(fl, LINUX_MAP_SHARED, MAP_SHARED);
 	flags |= cvtto_bsd_mask(fl, LINUX_MAP_PRIVATE, MAP_PRIVATE);
 	flags |= cvtto_bsd_mask(fl, LINUX_MAP_FIXED, MAP_FIXED);
Index: uvm/uvm_mmap.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_mmap.c,v
retrieving revision 1.63
diff -u -r1.63 uvm_mmap.c
--- uvm/uvm_mmap.c	2002/03/22 11:06:33	1.63
+++ uvm/uvm_mmap.c	2003/06/20 16:00:50
@@ -346,7 +346,7 @@
 		if (addr > addr + size)
 			return (EOVERFLOW);		/* no wrapping! */

-	} else {
+	} else if (addr == NULL || !(flags & MAP_TRYFIXED)) {

 		/*
 		 * not fixed: make sure we skip over the largest possible heap.
Index: sys/mman.h
===================================================================
RCS file: /cvsroot/src/sys/sys/mman.h,v
retrieving revision 1.28
diff -u -r1.28 mman.h
--- sys/mman.h	2000/10/18 01:43:18	1.28
+++ sys/mman.h	2003/06/20 16:00:51
@@ -92,6 +92,7 @@
 #define	MAP_INHERIT	 0x0080	/* region is retained after exec */
 #define	MAP_NOEXTEND	 0x0100	/* for MAP_FILE, don't change file size */
 #define	MAP_HASSEMAPHORE 0x0200	/* region may contain semaphores */
+#define	MAP_TRYFIXED     0x0400 /* attempt hint address, even within break */

 /*
  * Mapping type

-- 
-- Todd Vierling <tv@pobox.com>