summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorart <art@openbsd.org>2001-05-10 14:51:20 +0000
committerart <art@openbsd.org>2001-05-10 14:51:20 +0000
commitd58942a1ec76e276cb2406d628ec67f91bf3579d (patch)
treeedcd4e78d0a1c463293d677d9dfe34da19e4e5f4
parentHasn't been used for ages. ZAP! (diff)
downloadwireguard-openbsd-d58942a1ec76e276cb2406d628ec67f91bf3579d.tar.xz
wireguard-openbsd-d58942a1ec76e276cb2406d628ec67f91bf3579d.zip
More sync to NetBSD.
The highlight is some more advices to madvise(2). o MADV_DONTNEED will deactive the pages in the given range giving a quicker reuse. o MADV_FREE will garbage-collect the pages and swap resources causing the next fault to either page in new pages from backing store (mapped vnode) or allocate new zero-fill pages (anonymous mapping).
-rw-r--r--sys/sys/mman.h4
-rw-r--r--sys/uvm/uvm_amap.h8
-rw-r--r--sys/uvm/uvm_amap_i.h22
-rw-r--r--sys/uvm/uvm_map.c252
-rw-r--r--sys/uvm/uvm_mmap.c81
-rw-r--r--sys/vm/vm_map.h11
6 files changed, 259 insertions, 119 deletions
diff --git a/sys/sys/mman.h b/sys/sys/mman.h
index e04ee0027a8..1401d76387c 100644
--- a/sys/sys/mman.h
+++ b/sys/sys/mman.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mman.h,v 1.8 2001/03/09 14:20:50 art Exp $ */
+/* $OpenBSD: mman.h,v 1.9 2001/05/10 14:51:20 art Exp $ */
/* $NetBSD: mman.h,v 1.11 1995/03/26 20:24:23 jtc Exp $ */
/*-
@@ -81,6 +81,8 @@
#define MADV_SEQUENTIAL 2 /* expect sequential page references */
#define MADV_WILLNEED 3 /* will need these pages */
#define MADV_DONTNEED 4 /* dont need these pages */
+#define MADV_SPACEAVAIL 5 /* insure that resources are reserved */
+#define MADV_FREE 6 /* pages are empty, free them */
/*
* Flags to msync
diff --git a/sys/uvm/uvm_amap.h b/sys/uvm/uvm_amap.h
index 495da2488ac..22eecd6f120 100644
--- a/sys/uvm/uvm_amap.h
+++ b/sys/uvm/uvm_amap.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: uvm_amap.h,v 1.5 2001/03/09 05:34:38 smart Exp $ */
-/* $NetBSD: uvm_amap.h,v 1.11 1999/06/21 17:25:11 thorpej Exp $ */
+/* $OpenBSD: uvm_amap.h,v 1.6 2001/05/10 14:51:21 art Exp $ */
+/* $NetBSD: uvm_amap.h,v 1.12 1999/07/07 05:31:40 thorpej Exp $ */
/*
*
@@ -82,7 +82,7 @@ struct vm_amap;
*/
AMAP_INLINE
-vaddr_t amap_add /* add an anon to an amap */
+void amap_add /* add an anon to an amap */
__P((struct vm_aref *, vaddr_t,
struct vm_anon *, int));
struct vm_amap *amap_alloc /* allocate a new amap */
@@ -121,7 +121,7 @@ void amap_splitref /* split reference to amap into two */
vaddr_t));
AMAP_INLINE
void amap_unadd /* remove an anon from an amap */
- __P((struct vm_amap *, vaddr_t));
+ __P((struct vm_aref *, vaddr_t));
void amap_unlock /* unlock amap */
__P((struct vm_amap *));
AMAP_INLINE
diff --git a/sys/uvm/uvm_amap_i.h b/sys/uvm/uvm_amap_i.h
index 14398330016..bc8f43e3fb6 100644
--- a/sys/uvm/uvm_amap_i.h
+++ b/sys/uvm/uvm_amap_i.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: uvm_amap_i.h,v 1.7 2001/03/22 03:05:54 smart Exp $ */
-/* $NetBSD: uvm_amap_i.h,v 1.12 1999/03/25 18:48:49 mrg Exp $ */
+/* $OpenBSD: uvm_amap_i.h,v 1.8 2001/05/10 14:51:21 art Exp $ */
+/* $NetBSD: uvm_amap_i.h,v 1.13 1999/07/07 05:31:40 thorpej Exp $ */
/*
*
@@ -114,7 +114,7 @@ amap_lookups(aref, offset, anons, npages)
* pmap_page_protect on the anon's page.
* => returns an "offset" which is meaningful to amap_unadd().
*/
-AMAP_INLINE vaddr_t
+AMAP_INLINE void
amap_add(aref, offset, anon, replace)
struct vm_aref *aref;
vaddr_t offset;
@@ -156,23 +156,25 @@ amap_add(aref, offset, anon, replace)
UVMHIST_LOG(maphist,
"<- done (amap=0x%x, offset=0x%x, anon=0x%x, rep=%d)",
amap, offset, anon, replace);
-
- return(slot);
}
/*
- * amap_unadd: remove a page from an amap, given we know the slot #.
+ * amap_unadd: remove a page from an amap
*
* => caller must lock amap
*/
AMAP_INLINE void
-amap_unadd(amap, slot)
- struct vm_amap *amap;
- vaddr_t slot;
+amap_unadd(aref, offset)
+ struct vm_aref *aref;
+ vaddr_t offset;
{
- int ptr;
+ int ptr, slot;
+ struct vm_amap *amap = aref->ar_amap;
UVMHIST_FUNC("amap_unadd"); UVMHIST_CALLED(maphist);
+ AMAP_B2SLOT(slot, offset);
+ slot += aref->ar_pageoff;
+
if (slot >= amap->am_nslot)
panic("amap_unadd: offset out of range");
diff --git a/sys/uvm/uvm_map.c b/sys/uvm/uvm_map.c
index 4d98199d524..14e18ff3f60 100644
--- a/sys/uvm/uvm_map.c
+++ b/sys/uvm/uvm_map.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: uvm_map.c,v 1.14 2001/05/10 07:59:06 art Exp $ */
-/* $NetBSD: uvm_map.c,v 1.60 1999/07/01 20:07:05 thorpej Exp $ */
+/* $OpenBSD: uvm_map.c,v 1.15 2001/05/10 14:51:21 art Exp $ */
+/* $NetBSD: uvm_map.c,v 1.63 1999/07/07 21:51:35 thorpej Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -1824,7 +1824,11 @@ uvm_map_inherit(map, start, end, new_inheritance)
} else {
entry = temp_entry->next;
}
-
+
+ /*
+ * XXXJRT: disallow holes?
+ */
+
while ((entry != &map->header) && (entry->start < end)) {
UVM_MAP_CLIP_END(map, entry, end);
@@ -1877,65 +1881,6 @@ uvm_map_advice(map, start, end, new_advice)
/* nothing special here */
break;
-#if 0
- case MADV_WILLNEED:
- /* activate all these pages */
- /* XXX */
- /*
- * should invent a "weak" mode for uvm_fault()
- * which would only do the PGO_LOCKED pgo_get().
- */
- break;
-
- case MADV_DONTNEED:
- /* deactivate this page */
- /* XXX */
- /*
- * vm_page_t p;
- * uvm_lock_pageq();
- * for (p in each page)
- * if (not_wired)
- * uvm_pagedeactivate(p);
- * uvm_unlock_pageq();
- */
- break;
-
- case MADV_SPACEAVAIL:
- /*
- * XXXMRG
- * what is this? i think: "ensure that we have
- * allocated backing-store for these pages". this
- * is going to require changes in the page daemon,
- * as it will free swap space allocated to pages in
- * core. there's also what to do for
- * device/file/anonymous memory..
- */
- break;
-
- case MADV_GARBAGE:
- /* pages are `empty' and can be garbage collected */
- /* XXX */
- /*
- * (perhaps MADV_FREE? check freebsd's MADV_FREE).
- *
- * need to do this:
- * - clear all the referenced and modified bits on
- * the pages,
- * - delete any backing store,
- * - mark the page as `recycable'.
- *
- * So, if you start paging, the pages would be thrown out
- * and then zero-filled the next time they're used.
- * Otherwise you'd just reuse them directly. Once the
- * page has been modified again, it would no longer be
- * recyclable. That way, malloc() can just tell the
- * system when pages are `empty'; if memory is needed,
- * they'll be tossed; if memory is not needed, there
- * will be no additional overhead.
- */
- break;
-#endif
-
default:
vm_map_unlock(map);
UVMHIST_LOG(maphist,"<- done (INVALID ARG)",0,0,0,0);
@@ -2236,7 +2181,7 @@ uvm_map_pageable_all(map, flags, limit)
if (VM_MAPENT_ISWIRED(entry))
uvm_map_entry_unwire(map, entry);
}
- map->flags &= ~VM_MAP_WIREFUTURE;
+ vm_map_modflags(map, 0, VM_MAP_WIREFUTURE);
vm_map_unlock(map);
UVMHIST_LOG(maphist,"<- done (OK UNWIRE)",0,0,0,0);
return (KERN_SUCCESS);
@@ -2250,7 +2195,7 @@ uvm_map_pageable_all(map, flags, limit)
/*
* must wire all future mappings; remember this.
*/
- map->flags |= VM_MAP_WIREFUTURE;
+ vm_map_modflags(map, VM_MAP_WIREFUTURE, 0);
}
if ((flags & MCL_CURRENT) == 0) {
@@ -2408,20 +2353,23 @@ uvm_map_pageable_all(map, flags, limit)
}
/*
- * uvm_map_clean: push dirty pages off to backing store.
+ * uvm_map_clean: clean out a map range
*
* => valid flags:
+ * if (flags & PGO_CLEANIT): dirty pages are cleaned first
* if (flags & PGO_SYNCIO): dirty pages are written synchronously
* if (flags & PGO_DEACTIVATE): any cached pages are deactivated after clean
* if (flags & PGO_FREE): any cached pages are freed after clean
* => returns an error if any part of the specified range isn't mapped
* => never a need to flush amap layer since the anonymous memory has
- * no permanent home...
- * => called from sys_msync()
+ * no permanent home, but may deactivate pages there
+ * => called from sys_msync() and sys_madvise()
* => caller must not write-lock map (read OK).
* => we may sleep while cleaning if SYNCIO [with map read-locked]
*/
+int amap_clean_works = 1; /* XXX for now, just in case... */
+
int
uvm_map_clean(map, start, end, flags)
vm_map_t map;
@@ -2429,16 +2377,25 @@ uvm_map_clean(map, start, end, flags)
int flags;
{
vm_map_entry_t current, entry;
- vsize_t size;
- struct uvm_object *object;
+ struct uvm_object *uobj;
+ struct vm_amap *amap;
+ struct vm_anon *anon;
+ struct vm_page *pg;
vaddr_t offset;
+ vsize_t size;
+ int rv, error, refs;
UVMHIST_FUNC("uvm_map_clean"); UVMHIST_CALLED(maphist);
UVMHIST_LOG(maphist,"(map=0x%x,start=0x%x,end=0x%x,flags=0x%x)",
map, start, end, flags);
+#ifdef DIAGNOSTIC
+ if ((flags & (PGO_FREE|PGO_DEACTIVATE)) == (PGO_FREE|PGO_DEACTIVATE))
+ panic("uvm_map_clean: FREE and DEACTIVATE");
+#endif
+
vm_map_lock_read(map);
VM_MAP_RANGE_CHECK(map, start, end);
- if (!uvm_map_lookup_entry(map, start, &entry)) {
+ if (uvm_map_lookup_entry(map, start, &entry) == FALSE) {
vm_map_unlock_read(map);
return(KERN_INVALID_ADDRESS);
}
@@ -2458,41 +2415,150 @@ uvm_map_clean(map, start, end, flags)
}
}
- /*
- * add "cleanit" flag to flags (for generic flush routine).
- * then make a second pass, cleaning/uncaching pages from
- * the indicated objects as we go.
- */
- flags = flags | PGO_CLEANIT;
+ error = KERN_SUCCESS;
+
for (current = entry; current->start < end; current = current->next) {
- offset = current->offset + (start - current->start);
- size = (end <= current->end ? end : current->end) - start;
+ amap = current->aref.ar_amap; /* top layer */
+ uobj = current->object.uvm_obj; /* bottom layer */
+
+#ifdef DIAGNOSTIC
+ if (start < current->start)
+ panic("uvm_map_clean: hole");
+#endif
/*
- * get object/offset. can't be submap (checked above).
+ * No amap cleaning necessary if:
+ *
+ * (1) There's no amap.
+ *
+ * (2) We're not deactivating or freeing pages.
*/
- object = current->object.uvm_obj;
- simple_lock(&object->vmobjlock);
+ if (amap == NULL ||
+ (flags & (PGO_DEACTIVATE|PGO_FREE)) == 0)
+ goto flush_object;
+
+ /* XXX for now, just in case... */
+ if (amap_clean_works == 0)
+ goto flush_object;
+
+ amap_lock(amap);
+
+ offset = start - current->start;
+ size = (end <= current->end ? end : current->end) -
+ start;
+
+ for (/* nothing */; size != 0; size -= PAGE_SIZE,
+ offset += PAGE_SIZE) {
+ anon = amap_lookup(&current->aref, offset);
+ if (anon == NULL)
+ continue;
+
+ simple_lock(&anon->an_lock);
+
+ pg = anon->u.an_page;
+ if (pg == NULL) {
+ simple_unlock(&anon->an_lock);
+ continue;
+ }
+
+ switch (flags & (PGO_CLEANIT|PGO_FREE|PGO_DEACTIVATE)) {
+ /*
+ * XXX In these first 3 cases, we always just
+ * XXX deactivate the page. We may want to
+ * XXX handle the different cases more
+ * XXX specifically, in the future.
+ */
+ case PGO_CLEANIT|PGO_FREE:
+ case PGO_CLEANIT|PGO_DEACTIVATE:
+ case PGO_DEACTIVATE:
+ /* skip the page if it's loaned or wired */
+ if (pg->loan_count != 0 ||
+ pg->wire_count != 0) {
+ simple_unlock(&anon->an_lock);
+ continue;
+ }
+
+ uvm_lock_pageq();
+
+ /*
+ * skip the page if it's not actually owned
+ * by the anon (may simply be loaned to the
+ * anon).
+ */
+ if ((pg->pqflags & PQ_ANON) == 0) {
+#ifdef DIAGNOSTIC
+ if (pg->uobject != NULL)
+ panic("uvm_map_clean: "
+ "page anon vs. object "
+ "inconsistency");
+#endif
+ uvm_unlock_pageq();
+ simple_unlock(&anon->an_lock);
+ continue;
+ }
+#ifdef DIAGNOSTIC
+ if (pg->uanon != anon)
+ panic("uvm_map_clean: anon "
+ "inconsistency");
+#endif
+
+ /* zap all mappings for the page. */
+ pmap_page_protect(PMAP_PGARG(pg),
+ VM_PROT_NONE);
+
+ /* ...and deactivate the page. */
+ uvm_pagedeactivate(pg);
+
+ uvm_unlock_pageq();
+ simple_unlock(&anon->an_lock);
+ continue;
+
+ case PGO_FREE:
+ /* XXX skip the page if it's wired */
+ if (pg->wire_count != 0) {
+ simple_unlock(&anon->an_lock);
+ continue;
+ }
+ amap_unadd(&entry->aref, offset);
+ refs = --anon->an_ref;
+ simple_unlock(&anon->an_lock);
+ if (refs == 0)
+ uvm_anfree(anon);
+ continue;
+
+ default:
+ panic("uvm_map_clean: wierd flags");
+ }
+#ifdef DIAGNOSTIC
+ panic("uvm_map_clean: unreachable code");
+#endif
+ }
+
+ amap_unlock(amap);
+
+ flush_object:
/*
* flush pages if we've got a valid backing object.
- * note that object is locked.
- * XXX should we continue on an error?
*/
- if (object && object->pgops) {
- if (!object->pgops->pgo_flush(object, offset,
- offset+size, flags)) {
- simple_unlock(&object->vmobjlock);
- vm_map_unlock_read(map);
- return (KERN_FAILURE);
- }
+ offset = current->offset + (start - current->start);
+ size = (end <= current->end ? end : current->end) - start;
+
+ if (uobj != NULL) {
+ simple_lock(&uobj->vmobjlock);
+ rv = uobj->pgops->pgo_flush(uobj, offset,
+ offset + size, flags);
+ simple_unlock(&uobj->vmobjlock);
+
+ if (rv == FALSE)
+ error = KERN_FAILURE;
}
- simple_unlock(&object->vmobjlock);
start += size;
}
+
vm_map_unlock_read(map);
- return(KERN_SUCCESS);
+ return (error);
}
@@ -2688,7 +2754,7 @@ uvmspace_exec(p)
* when a process execs another program image.
*/
vm_map_lock(map);
- map->flags &= ~VM_MAP_WIREFUTURE;
+ vm_map_modflags(map, 0, VM_MAP_WIREFUTURE);
vm_map_unlock(map);
/*
diff --git a/sys/uvm/uvm_mmap.c b/sys/uvm/uvm_mmap.c
index 56a4cad7503..63d6cfb51f9 100644
--- a/sys/uvm/uvm_mmap.c
+++ b/sys/uvm/uvm_mmap.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: uvm_mmap.c,v 1.12 2001/05/10 07:59:06 art Exp $ */
-/* $NetBSD: uvm_mmap.c,v 1.28 1999/07/06 02:31:05 cgd Exp $ */
+/* $OpenBSD: uvm_mmap.c,v 1.13 2001/05/10 14:51:21 art Exp $ */
+/* $NetBSD: uvm_mmap.c,v 1.29 1999/07/07 06:02:22 thorpej Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -621,7 +621,7 @@ sys_msync(p, v, retval)
/*
* translate MS_ flags into PGO_ flags
*/
- uvmflags = (flags & MS_INVALIDATE) ? PGO_FREE : 0;
+ uvmflags = PGO_CLEANIT | (flags & MS_INVALIDATE) ? PGO_FREE : 0;
if (flags & MS_SYNC)
uvmflags |= PGO_SYNCIO;
else
@@ -843,7 +843,7 @@ sys_madvise(p, v, retval)
} */ *uap = v;
vaddr_t addr;
vsize_t size, pageoff;
- int advice;
+ int advice, rv;;
addr = (vaddr_t)SCARG(uap, addr);
size = (vsize_t)SCARG(uap, len);
@@ -857,15 +857,76 @@ sys_madvise(p, v, retval)
size += pageoff;
size = (vsize_t) round_page(size);
- if ((int)size < 0)
+ if ((ssize_t)size <= 0)
return (EINVAL);
-
- switch (uvm_map_advice(&p->p_vmspace->vm_map, addr, addr+size,
- advice)) {
+
+ switch (advice) {
+ case MADV_NORMAL:
+ case MADV_RANDOM:
+ case MADV_SEQUENTIAL:
+ rv = uvm_map_advice(&p->p_vmspace->vm_map, addr, addr + size,
+ advice);
+ break;
+
+ case MADV_WILLNEED:
+ /*
+ * Activate all these pages, pre-faulting them in if
+ * necessary.
+ */
+ /*
+ * XXX IMPLEMENT ME.
+ * Should invent a "weak" mode for uvm_fault()
+ * which would only do the PGO_LOCKED pgo_get().
+ */
+ return (0);
+
+ case MADV_DONTNEED:
+ /*
+ * Deactivate all these pages. We don't need them
+ * any more. We don't, however, toss the data in
+ * the pages.
+ */
+ rv = uvm_map_clean(&p->p_vmspace->vm_map, addr, addr + size,
+ PGO_DEACTIVATE);
+ break;
+
+ case MADV_FREE:
+ /*
+ * These pages contain no valid data, and may be
+ * grbage-collected. Toss all resources, including
+ * backing store; note that if the page is not backed
+ * by swap, it will be cleaned first, for good measure.
+ */
+ rv = uvm_map_clean(&p->p_vmspace->vm_map, addr, addr + size,
+ PGO_FREE);
+ break;
+
+ case MADV_SPACEAVAIL:
+ /*
+ * XXXMRG What is this? I think it's:
+ *
+ * Ensure that we have allocated backing-store
+ * for these pages.
+ *
+ * This is going to require changes to the page daemon,
+ * as it will free swap space allocated to pages in core.
+ * There's also what to do for device/file/anonymous memory.
+ */
+ return (EINVAL);
+
+ default:
+ return (EINVAL);
+ }
+
+ switch (rv) {
case KERN_SUCCESS:
return (0);
- case KERN_PROTECTION_FAILURE:
- return (EACCES);
+ case KERN_NO_SPACE:
+ return (EAGAIN);
+ case KERN_INVALID_ADDRESS:
+ return (ENOMEM);
+ case KERN_FAILURE:
+ return (EIO);
}
return (EINVAL);
diff --git a/sys/vm/vm_map.h b/sys/vm/vm_map.h
index 47107fec0e7..515c9ec378c 100644
--- a/sys/vm/vm_map.h
+++ b/sys/vm/vm_map.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_map.h,v 1.13 2001/05/10 07:59:06 art Exp $ */
+/* $OpenBSD: vm_map.h,v 1.14 2001/05/10 14:51:21 art Exp $ */
/* $NetBSD: vm_map.h,v 1.11 1995/03/26 20:39:10 jtc Exp $ */
/*
@@ -231,6 +231,15 @@ struct vm_map {
#define VM_MAP_BUSY 0x08 /* rw: map is busy */
#define VM_MAP_WANTLOCK 0x10 /* rw: want to write-lock */
+#ifdef _KERNEL
+#define vm_map_modflags(map, set, clear) \
+do { \
+ simple_lock(&(map)->flags_lock); \
+ (map)->flags = ((map)->flags | (set)) & ~(clear); \
+ simple_unlock(&(map)->flags_lock); \
+} while (0)
+#endif /* _KERNEL */
+
/*
* Interrupt-safe maps must also be kept on a special list,
* to assist uvm_fault() in avoiding locking problems.