diff options
author | 2001-05-10 14:51:20 +0000 | |
---|---|---|
committer | 2001-05-10 14:51:20 +0000 | |
commit | d58942a1ec76e276cb2406d628ec67f91bf3579d (patch) | |
tree | edcd4e78d0a1c463293d677d9dfe34da19e4e5f4 | |
parent | Hasn't been used for ages. ZAP! (diff) | |
download | wireguard-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.h | 4 | ||||
-rw-r--r-- | sys/uvm/uvm_amap.h | 8 | ||||
-rw-r--r-- | sys/uvm/uvm_amap_i.h | 22 | ||||
-rw-r--r-- | sys/uvm/uvm_map.c | 252 | ||||
-rw-r--r-- | sys/uvm/uvm_mmap.c | 81 | ||||
-rw-r--r-- | sys/vm/vm_map.h | 11 |
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(¤t->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. |