Subject: RFC: mremap(2)
To: None <tech-kern@netbsd.org>
From: Joerg Sonnenberger <joerg@britannica.bec.de>
List: tech-kern
Date: 07/05/2007 14:23:41
--HcAYCG3uE/tztfnV
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi all,
I would like to add the equivalent of mremap(2) from Linux for the use
e.g. of malloc(3).

Prototype:
	void *mremap(void *oldp, size_t oldsize, void *newp,
		     size_t newsize, int flags)

Supported flags from mmap(2):
MAP_FIXED
MAP_ALIGNED

Semantic:
Resize the mapped range [oldp..oldp_oldsize] to newsize. If MAP_FIXED is
specified newp is tried and mremap fails it that can't be used.
Otherwise oldp and newp are used as hints for the position, factoring in
the given alignment. Return value is either the new address or
MAP_FAILED.

Attached is an attempt to implement this.

Joerg

--HcAYCG3uE/tztfnV
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="mremap.diff"

Index: lib/libc/sys/Makefile.inc
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/sys/Makefile.inc,v
retrieving revision 1.174
diff -u -r1.174 Makefile.inc
--- lib/libc/sys/Makefile.inc	3 Jun 2007 17:35:24 -0000	1.174
+++ lib/libc/sys/Makefile.inc	5 Jul 2007 09:10:24 -0000
@@ -74,7 +74,8 @@
 		_lwp_suspend.S _lwp_continue.S _lwp_wakeup.S _lwp_detach.S \
 		_lwp_getprivate.S _lwp_setprivate.S \
 	madvise.S mincore.S minherit.S mkdir.S mkfifo.S mknod.S \
-		mlock.S mlockall.S mount.S mprotect.S __msgctl13.S msgget.S \
+		mlock.S mlockall.S mount.S mprotect.S \
+		mremap.S __msgctl13.S msgget.S \
 		munlock.S munlockall.S munmap.S \
 	nfssvc.S __ntp_gettime30.S \
 	pathconf.S pmc_get_info.S pmc_control.S __posix_chown.S \
Index: sys/compat/linux/common/linux_misc.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/compat/linux/common/linux_misc.c,v
retrieving revision 1.181
diff -u -r1.181 linux_misc.c
--- sys/compat/linux/common/linux_misc.c	30 Jun 2007 13:34:19 -0000	1.181
+++ sys/compat/linux/common/linux_misc.c	4 Jul 2007 23:56:14 -0000
@@ -553,7 +553,7 @@
 		}
 #if 0 /* notyet */
 		newva = SCARG(uap, new_address);
-		uvmflags = UVM_MREMAP_FIXED;
+		uvmflags = MAP_FIXED;
 #else /* notyet */
 		error = EOPNOTSUPP;
 		goto done;
@@ -562,7 +562,7 @@
 		uvmflags = 0;
 	} else {
 		newva = oldva;
-		uvmflags = UVM_MREMAP_FIXED;
+		uvmflags = MAP_FIXED;
 	}
 	p = l->l_proc;
 	map = &p->p_vmspace->vm_map;
Index: sys/kern/init_sysent.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/kern/init_sysent.c,v
retrieving revision 1.190
diff -u -r1.190 init_sysent.c
--- sys/kern/init_sysent.c	30 Apr 2007 14:47:32 -0000	1.190
+++ sys/kern/init_sysent.c	4 Jul 2007 23:59:39 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: init_sysent.c,v 1.190 2007/04/30 14:47:32 rmind Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call switch table.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_sysent.c,v 1.190 2007/04/30 14:47:32 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #include "opt_ktrace.h"
 #include "opt_nfsserver.h"
@@ -1063,8 +1063,8 @@
 	    sys_aio_write },			/* 405 = aio_write */
 	{ 4, s(struct sys_lio_listio_args), 0,
 	    sys_lio_listio },			/* 406 = lio_listio */
-	{ 0, 0, 0,
-	    sys_nosys },			/* 407 = filler */
+	{ 5, s(struct sys_mremap_args), 0,
+	    sys_mremap },			/* 407 = mremap */
 	{ 0, 0, 0,
 	    sys_nosys },			/* 408 = filler */
 	{ 0, 0, 0,
Index: sys/kern/syscalls.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/kern/syscalls.c,v
retrieving revision 1.186
diff -u -r1.186 syscalls.c
--- sys/kern/syscalls.c	30 Apr 2007 14:47:32 -0000	1.186
+++ sys/kern/syscalls.c	4 Jul 2007 23:59:39 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: syscalls.c,v 1.186 2007/04/30 14:47:32 rmind Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call names.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: syscalls.c,v 1.186 2007/04/30 14:47:32 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ktrace.h"
@@ -541,4 +541,5 @@
 	"aio_suspend",			/* 404 = aio_suspend */
 	"aio_write",			/* 405 = aio_write */
 	"lio_listio",			/* 406 = lio_listio */
+	"mremap",			/* 407 = mremap */
 };
Index: sys/kern/syscalls.master
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/kern/syscalls.master,v
retrieving revision 1.169
diff -u -r1.169 syscalls.master
--- sys/kern/syscalls.master	30 Apr 2007 14:44:30 -0000	1.169
+++ sys/kern/syscalls.master	4 Jul 2007 23:46:11 -0000
@@ -805,3 +805,6 @@
 405	STD		{ int sys_aio_write(struct aiocb *aiocbp); }
 406	STD		{ int sys_lio_listio(int mode, struct aiocb *const *list, \
 			    int nent, struct sigevent *sig); }
+
+407	STD		{ void *sys_mremap(void *old_address, size_t old_size, \
+			    void *new_address, size_t new_size, int flags); }
Index: sys/sys/mman.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/sys/mman.h,v
retrieving revision 1.38
diff -u -r1.38 mman.h
--- sys/sys/mman.h	30 Aug 2006 11:35:21 -0000	1.38
+++ sys/sys/mman.h	5 Jul 2007 00:02:28 -0000
@@ -157,6 +157,7 @@
 
 __BEGIN_DECLS
 void   *mmap(void *, size_t, int, int, int, off_t);
+void   *mremap(void *, size_t, void *, size_t, int);
 int	munmap(void *, size_t);
 int	mprotect(void *, size_t, int);
 #ifndef __LIBC12_SOURCE__
Index: sys/sys/syscall.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/sys/syscall.h,v
retrieving revision 1.184
diff -u -r1.184 syscall.h
--- sys/sys/syscall.h	30 Apr 2007 14:47:32 -0000	1.184
+++ sys/sys/syscall.h	4 Jul 2007 23:59:39 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: syscall.h,v 1.184 2007/04/30 14:47:32 rmind Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call numbers.
@@ -1144,6 +1144,9 @@
 /* syscall: "lio_listio" ret: "int" args: "int" "struct aiocb *const *" "int" "struct sigevent *" */
 #define	SYS_lio_listio	406
 
-#define	SYS_MAXSYSCALL	407
+/* syscall: "mremap" ret: "void *" args: "void *" "size_t" "void *" "size_t" "int" */
+#define	SYS_mremap	407
+
+#define	SYS_MAXSYSCALL	408
 #define	SYS_NSYSENT	512
 #endif /* _SYS_SYSCALL_H_ */
Index: sys/sys/syscallargs.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/sys/syscallargs.h,v
retrieving revision 1.166
diff -u -r1.166 syscallargs.h
--- sys/sys/syscallargs.h	30 Apr 2007 14:47:33 -0000	1.166
+++ sys/sys/syscallargs.h	4 Jul 2007 23:59:39 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: syscallargs.h,v 1.166 2007/04/30 14:47:33 rmind Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call argument lists.
@@ -1779,6 +1779,14 @@
 	syscallarg(struct sigevent *) sig;
 };
 
+struct sys_mremap_args {
+	syscallarg(void *) old_address;
+	syscallarg(size_t) old_size;
+	syscallarg(void *) new_address;
+	syscallarg(size_t) new_size;
+	syscallarg(int) flags;
+};
+
 /*
  * System call prototypes.
  */
@@ -2520,4 +2528,6 @@
 
 int	sys_lio_listio(struct lwp *, void *, register_t *);
 
+int	sys_mremap(struct lwp *, void *, register_t *);
+
 #endif /* _SYS_SYSCALLARGS_H_ */
Index: sys/uvm/files.uvm
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/uvm/files.uvm,v
retrieving revision 1.8
diff -u -r1.8 files.uvm
--- sys/uvm/files.uvm	25 Nov 2006 21:40:06 -0000	1.8
+++ sys/uvm/files.uvm	5 Jul 2007 00:00:07 -0000
@@ -24,7 +24,7 @@
 file	uvm/uvm_map.c
 file	uvm/uvm_meter.c
 file	uvm/uvm_mmap.c
-file	uvm/uvm_mremap.c		compat_linux
+file	uvm/uvm_mremap.c
 file	uvm/uvm_object.c
 file	uvm/uvm_page.c
 file	uvm/uvm_pager.c
Index: sys/uvm/uvm_extern.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/uvm/uvm_extern.h,v
retrieving revision 1.130
diff -u -r1.130 uvm_extern.h
--- sys/uvm/uvm_extern.h	5 Jun 2007 12:31:35 -0000	1.130
+++ sys/uvm/uvm_extern.h	4 Jul 2007 23:55:38 -0000
@@ -660,7 +660,6 @@
 int			uvm_mremap(struct vm_map *, vaddr_t, vsize_t,
 			    struct vm_map *, vaddr_t *, vsize_t,
 			    struct proc *, int);
-#define	UVM_MREMAP_FIXED	1
 
 /* uvm_object.c */
 int			uobj_wirepages(struct uvm_object *uobj, off_t start,
Index: sys/uvm/uvm_mremap.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/uvm/uvm_mremap.c,v
retrieving revision 1.4
diff -u -r1.4 uvm_mremap.c
--- sys/uvm/uvm_mremap.c	21 Feb 2007 23:00:14 -0000	1.4
+++ sys/uvm/uvm_mremap.c	5 Jul 2007 00:22:56 -0000
@@ -30,6 +30,8 @@
 __KERNEL_RCSID(0, "$NetBSD: uvm_mremap.c,v 1.4 2007/02/21 23:00:14 thorpej Exp $");
 
 #include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/syscallargs.h>
 
 #include <uvm/uvm.h>
 
@@ -111,8 +113,9 @@
 	vaddr_t dstva;
 	vsize_t movesize;
 	vaddr_t newva;
+	vaddr_t align = 0;
 	int error = 0;
-	const bool fixed = (flags & UVM_MREMAP_FIXED) != 0;
+	const bool fixed = (flags & MAP_FIXED) != 0;
 
 	if (fixed) {
 		newva = *newvap;
@@ -131,10 +134,35 @@
 	}
 
 	/*
+	 * Try to see if any requested alignment can even be attemped.
+	 * Make sure we can express the alignment (asking for a >= 4GB
+	 * alignment on an ILP32 architecure make no sense) and the
+	 * alignment is at least for a page sized quanitiy.  If the
+	 * request was for a fixed mapping, make sure supplied address
+	 * adheres to the request alignment.
+	 */
+	align = (flags & MAP_ALIGNMENT_MASK) >> MAP_ALIGNMENT_SHIFT;
+	if (align) {
+		if (align >= sizeof(vaddr_t) * NBBY)
+			return(EINVAL);
+		align = 1L << align;
+		if (align < PAGE_SIZE)
+			return(EINVAL);
+		if (align >= vm_map_max(oldmap))
+			return(ENOMEM);
+		if (flags & MAP_FIXED) {
+			if ((*newvap & (align-1)) != 0)
+				return(EINVAL);
+			align = 0;
+		}
+	}
+
+	/*
 	 * check the easy cases first.
 	 */
 
-	if ((!fixed || newva == oldva) && newmap == oldmap) {
+	if ((!fixed || newva == oldva) && newmap == oldmap &&
+	    (align == 0 || (oldva & ~(align - 1)) == 0)) {
 		vaddr_t va;
 
 		if (newsize == oldsize) {
@@ -167,7 +195,7 @@
 		    (vaddr_t)newproc->p_vmspace->vm_daddr, newsize);
 	}
 	dstva = newva;
-	if (!uvm_map_reserve(newmap, newsize, oldva, 0, &dstva, 
+	if (!uvm_map_reserve(newmap, newsize, oldva, align, &dstva, 
 	    fixed ? UVM_FLAG_FIXED : 0)) {
 		return ENOMEM;
 	}
@@ -204,3 +232,49 @@
 	*newvap = newva;
 	return 0;
 }
+
+/*
+ * sys_mremap: mremap system call.
+ */
+
+int
+sys_mremap(struct lwp *l, void *v, register_t *retval)
+{
+	struct sys_mremap_args /* {
+		syscallarg(void *) old_address;
+		syscallarg(size_t) old_size;
+		syscallarg(void *) new_address;
+		syscallarg(size_t) new_size;
+		syscallarg(int) flags;
+	} */ *uap = v;
+
+	struct proc *p;
+	struct vm_map *map;
+	vaddr_t oldva;
+	vaddr_t newva;
+	size_t oldsize;
+	size_t newsize;
+	int flags;
+	int error;
+
+	flags = SCARG(uap, flags);
+	oldva = (vaddr_t)SCARG(uap, old_address);
+	oldsize = (vsize_t)(SCARG(uap, old_size));
+	newva = (vaddr_t)SCARG(uap, new_address);
+	newsize = (vsize_t)(SCARG(uap, new_size));
+
+	if ((flags & ~(MAP_FIXED | MAP_ALIGNMENT_MASK)) != 0) {
+		error = EINVAL;
+		goto done;
+	}
+
+	p = l->l_proc;
+	map = &p->p_vmspace->vm_map;
+	error = uvm_mremap(map, oldva, oldsize, map, &newva, newsize, p,
+	    flags);
+
+done:
+	*retval = (error != 0) ? 0 : (register_t)newva;
+	return error;
+
+}

--HcAYCG3uE/tztfnV--