summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1997-08-30 18:50:06 +0000
committerpeter <peter@FreeBSD.org>1997-08-30 18:50:06 +0000
commit29e2c84e7aa0fb8266dcd2f6c6770b1a48a5b029 (patch)
treebb6b488501d01e1442c888f234d896a1f4933a66
parent0d58a5f146f29f780a0dd195fb5444d29eac080d (diff)
downloadFreeBSD-src-29e2c84e7aa0fb8266dcd2f6c6770b1a48a5b029.zip
FreeBSD-src-29e2c84e7aa0fb8266dcd2f6c6770b1a48a5b029.tar.gz
Allow non-page aligned file offset mmap's, providing that the system is
allowed to choose the address, or that the MAP_FIXED address has the same remainder when modulo PAGE_SIZE as the file offset. Apparently this is posix1003.1b specified behavior. SVR4 and the other *BSD's allow it too. It costs us nothing to support and means we don't get EINVAL on some mmap code that works perfectly elsewhere. Obtained from: NetBSD
-rw-r--r--sys/vm/vm_mmap.c70
1 files changed, 47 insertions, 23 deletions
diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c
index 6c1db90..f39530f 100644
--- a/sys/vm/vm_mmap.c
+++ b/sys/vm/vm_mmap.c
@@ -38,7 +38,7 @@
* from: Utah $Hdr: vm_mmap.c 1.6 91/10/21$
*
* @(#)vm_mmap.c 8.4 (Berkeley) 1/12/94
- * $Id: vm_mmap.c,v 1.65 1997/07/17 04:34:03 dyson Exp $
+ * $Id: vm_mmap.c,v 1.66 1997/08/25 22:15:25 bde Exp $
*/
/*
@@ -132,6 +132,15 @@ ogetpagesize(p, uap, retval)
}
#endif /* COMPAT_43 || COMPAT_SUNOS */
+
+/*
+ * Memory Map (mmap) system call. Note that the file offset
+ * and address are allowed to be NOT page aligned, though if
+ * the MAP_FIXED flag it set, both must have the same remainder
+ * modulo the PAGE_SIZE (POSIX 1003.1b). If the address is not
+ * page-aligned, the actual mapping starts at trunc_page(addr)
+ * and the return value is adjusted up by the page offset.
+ */
#ifndef _SYS_SYSPROTO_H_
struct mmap_args {
caddr_t addr;
@@ -158,33 +167,45 @@ mmap(p, uap, retval)
vm_prot_t prot, maxprot;
caddr_t handle;
int flags, error;
+ off_t pos;
+ addr = (vm_offset_t) uap->addr;
+ size = uap->len;
prot = uap->prot & VM_PROT_ALL;
flags = uap->flags;
- /*
- * Address (if FIXED) must be page aligned. Size is implicitly rounded
- * to a page boundary.
- */
- addr = (vm_offset_t) uap->addr;
- if (((flags & MAP_FIXED) && (addr & PAGE_MASK)) ||
- (ssize_t) uap->len < 0 || ((flags & MAP_ANON) && uap->fd != -1))
+ pos = uap->pos;
+
+ /* make sure mapping fits into numeric range etc */
+ if ((pos + size > (vm_offset_t)-PAGE_SIZE) ||
+ (ssize_t) uap->len < 0 ||
+ ((flags & MAP_ANON) && uap->fd != -1))
return (EINVAL);
/*
- * Round page if not already disallowed by above test
- * XXX: Is there any point in the MAP_FIXED align requirement above?
+ * Align the file position to a page boundary,
+ * and save its page offset component.
*/
- size = uap->len;
- pageoff = (addr & PAGE_MASK);
- addr -= pageoff;
- size += pageoff;
- size = (vm_size_t) round_page(size);
+ pageoff = (pos & PAGE_MASK);
+ pos -= pageoff;
+
+ /* Adjust size for rounding (on both ends). */
+ size += pageoff; /* low end... */
+ size = (vm_size_t) round_page(size); /* hi end */
/*
* Check for illegal addresses. Watch out for address wrap... Note
* that VM_*_ADDRESS are not constants due to casts (argh).
*/
if (flags & MAP_FIXED) {
+ /*
+ * The specified address must have the same remainder
+ * as the file offset taken modulo PAGE_SIZE, so it
+ * should be aligned after adjustment by pageoff.
+ */
+ addr -= pageoff;
+ if (addr & PAGE_MASK)
+ return (EINVAL);
+ /* Address range must be all in user VM space. */
if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS)
return (EINVAL);
#ifndef i386
@@ -195,19 +216,23 @@ mmap(p, uap, retval)
return (EINVAL);
}
/*
- * XXX if no hint provided for a non-fixed mapping place it after the
- * end of the largest possible heap.
+ * XXX for non-fixed mappings where no hint is provided or
+ * the hint would fall in the potential heap space,
+ * place it after the end of the largest possible heap.
*
- * There should really be a pmap call to determine a reasonable location.
+ * There should really be a pmap call to determine a reasonable
+ * location.
*/
- if (addr == 0 && (flags & MAP_FIXED) == 0)
+ else if (addr < round_page(p->p_vmspace->vm_daddr + MAXDSIZ))
addr = round_page(p->p_vmspace->vm_daddr + MAXDSIZ);
+
if (flags & MAP_ANON) {
/*
* Mapping blank space is trivial.
*/
handle = NULL;
maxprot = VM_PROT_ALL;
+ pos = 0;
} else {
/*
* Mapping file, get fp for validation. Obtain vnode and make
@@ -229,6 +254,7 @@ mmap(p, uap, retval)
handle = NULL;
maxprot = VM_PROT_ALL;
flags |= MAP_ANON;
+ pos = 0;
} else {
/*
* Ensure that file and memory protections are
@@ -255,9 +281,9 @@ mmap(p, uap, retval)
}
}
error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot,
- flags, handle, uap->pos);
+ flags, handle, pos);
if (error == 0)
- *retval = (int) addr;
+ *retval = (int) (addr + pageoff);
return (error);
}
@@ -432,8 +458,6 @@ munmap(p, uap, retval)
if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS)
return (EINVAL);
#endif
- if (addr + size < addr)
- return (EINVAL);
map = &p->p_vmspace->vm_map;
/*
* Make sure entire range is allocated.
OpenPOWER on IntegriCloud