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--