Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/uvm Implement uao_flush(). This is pretty much identica...
details: https://anonhg.NetBSD.org/src/rev/270f1612e96b
branches: trunk
changeset: 474720:270f1612e96b
user: thorpej <thorpej%NetBSD.org@localhost>
date: Sat Jul 17 06:06:36 1999 +0000
description:
Implement uao_flush(). This is pretty much identical to the "amap flush"
code in uvm_map_clean().
diffstat:
sys/uvm/uvm_aobj.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 189 insertions(+), 14 deletions(-)
diffs (226 lines):
diff -r 9337baed90ae -r 270f1612e96b sys/uvm/uvm_aobj.c
--- a/sys/uvm/uvm_aobj.c Sat Jul 17 06:01:52 1999 +0000
+++ b/sys/uvm/uvm_aobj.c Sat Jul 17 06:06:36 1999 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_aobj.c,v 1.21 1999/07/07 05:32:26 thorpej Exp $ */
+/* $NetBSD: uvm_aobj.c,v 1.22 1999/07/17 06:06:36 thorpej Exp $ */
/*
* Copyright (c) 1998 Chuck Silvers, Charles D. Cranor and
@@ -708,28 +708,203 @@
}
/*
- * uao_flush: uh, yea, sure it's flushed. really!
+ * uao_flush: "flush" pages out of a uvm object
+ *
+ * => object should be locked by caller. we may _unlock_ the object
+ * if (and only if) we need to clean a page (PGO_CLEANIT).
+ * XXXJRT Currently, however, we don't. In the case of cleaning
+ * XXXJRT a page, we simply just deactivate it. Should probably
+ * XXXJRT handle this better, in the future (although "flushing"
+ * XXXJRT anonymous memory isn't terribly important).
+ * => if PGO_CLEANIT is not set, then we will neither unlock the object
+ * or block.
+ * => if PGO_ALLPAGE is set, then all pages in the object are valid targets
+ * for flushing.
+ * => NOTE: we rely on the fact that the object's memq is a TAILQ and
+ * that new pages are inserted on the tail end of the list. thus,
+ * we can make a complete pass through the object in one go by starting
+ * at the head and working towards the tail (new pages are put in
+ * front of us).
+ * => NOTE: we are allowed to lock the page queues, so the caller
+ * must not be holding the lock on them [e.g. pagedaemon had
+ * better not call us with the queues locked]
+ * => we return TRUE unless we encountered some sort of I/O error
+ * XXXJRT currently never happens, as we never directly initiate
+ * XXXJRT I/O
+ *
+ * comment on "cleaning" object and PG_BUSY pages:
+ * this routine is holding the lock on the object. the only time
+ * that is can run into a PG_BUSY page that it does not own is if
+ * some other process has started I/O on the page (e.g. either
+ * a pagein or a pageout). if the PG_BUSY page is being paged
+ * in, then it can not be dirty (!PG_CLEAN) because no one has
+ * had a change to modify it yet. if the PG_BUSY page is being
+ * paged out then it means that someone else has already started
+ * cleaning the page for us (how nice!). in this case, if we
+ * have syncio specified, then after we make our pass through the
+ * object we need to wait for the other PG_BUSY pages to clear
+ * off (i.e. we need to do an iosync). also note that once a
+ * page is PG_BUSY is must stary in its object until it is un-busyed.
+ * XXXJRT We never actually do this, as we are "flushing" anonymous
+ * XXXJRT memory, which doesn't have persistent backing store.
+ *
+ * note on page traversal:
+ * we can traverse the pages in an object either by going down the
+ * linked list in "uobj->memq", or we can go over the address range
+ * by page doing hash table lookups for each address. depending
+ * on how many pages are in the object it may be cheaper to do one
+ * or the other. we set "by_list" to true if we are using memq.
+ * if the cost of a hash lookup was equal to the cost of the list
+ * traversal we could compare the number of pages in the start->stop
+ * range to the total number of pages in the object. however, it
+ * seems that a hash table lookup is more expensive than the linked
+ * list traversal, so we multiply the number of pages in the
+ * start->stop range by a penalty which we define below.
*/
+
+#define UAO_HASH_PENALTY 4 /* XXX: a guess */
+
boolean_t
-uao_flush(uobj, start, end, flags)
+uao_flush(uobj, start, stop, flags)
struct uvm_object *uobj;
- vaddr_t start, end;
+ vaddr_t start, stop;
int flags;
{
+ struct uvm_aobj *aobj = (struct uvm_aobj *) uobj;
+ struct vm_page *pp, *ppnext;
+ boolean_t retval, by_list;
+ vaddr_t curoff;
+ UVMHIST_FUNC("uao_flush"); UVMHIST_CALLED(maphist);
+
+ curoff = 0; /* XXX: shut up gcc */
+
+ retval = TRUE; /* default to success */
+
+ if (flags & PGO_ALLPAGES) {
+ start = 0;
+ stop = aobj->u_pages << PAGE_SHIFT;
+ by_list = TRUE; /* always go by the list */
+ } else {
+ start = trunc_page(start);
+ stop = round_page(stop);
+ if (stop > (aobj->u_pages << PAGE_SHIFT)) {
+ printf("uao_flush: strange, got an out of range "
+ "flush (fixed)\n");
+ stop = aobj->u_pages << PAGE_SHIFT;
+ }
+ by_list = (uobj->uo_npages <=
+ ((stop - start) >> PAGE_SHIFT) * UAO_HASH_PENALTY);
+ }
+
+ UVMHIST_LOG(maphist,
+ " flush start=0x%lx, stop=0x%x, by_list=%d, flags=0x%x",
+ start, stop, by_list, flags);
/*
- * anonymous memory doesn't "flush"
- */
+ * Don't need to do any work here if we're not freeing
+ * or deactivating pages.
+ */
+ if ((flags & (PGO_DEACTIVATE|PGO_FREE)) == 0) {
+ UVMHIST_LOG(maphist,
+ "<- done (no work to do)",0,0,0,0);
+ return (retval);
+ }
+
/*
- * XXX
- * Deal with:
- *
- * PGO_DEACTIVATE for sequential access, via uvm_fault(), and
- * for MADV_DONTNEED
- *
- * PGO_FREE for MADV_FREE and MSINVALIDATE
+ * now do it. note: we must update ppnext in the body of loop or we
+ * will get stuck. we need to use ppnext because we may free "pp"
+ * before doing the next loop.
*/
- return TRUE;
+
+ if (by_list) {
+ pp = uobj->memq.tqh_first;
+ } else {
+ curoff = start;
+ pp = uvm_pagelookup(uobj, curoff);
+ }
+
+ ppnext = NULL; /* XXX: shut up gcc */
+ uvm_lock_pageq(); /* page queues locked */
+
+ /* locked: both page queues and uobj */
+ for ( ; (by_list && pp != NULL) ||
+ (!by_list && curoff < stop) ; pp = ppnext) {
+ if (by_list) {
+ ppnext = pp->listq.tqe_next;
+
+ /* range check */
+ if (pp->offset < start || pp->offset >= stop)
+ continue;
+ } else {
+ curoff += PAGE_SIZE;
+ if (curoff < stop)
+ ppnext = uvm_pagelookup(uobj, curoff);
+
+ /* null check */
+ if (pp == NULL)
+ 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 specifically
+ * XXX 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 (pp->loan_count != 0 ||
+ pp->wire_count != 0)
+ continue;
+
+ /* zap all mappings for the page. */
+ pmap_page_protect(PMAP_PGARG(pp),
+ VM_PROT_NONE);
+
+ /* ...and deactivate the page. */
+ uvm_pagedeactivate(pp);
+
+ continue;
+
+ case PGO_FREE:
+ /* XXX skip the page if it's loaned or wired */
+ if (pp->loan_count != 0 ||
+ pp->wire_count != 0)
+ continue;
+
+ /*
+ * mark the page as released if its busy.
+ */
+ if (pp->flags & PG_BUSY) {
+ pp->flags |= PG_RELEASED;
+ continue;
+ }
+
+ /* zap all mappings for the page. */
+ pmap_page_protect(PMAP_PGARG(pp),
+ VM_PROT_NONE);
+
+ uao_dropswap(uobj, pp->offset >> PAGE_SHIFT);
+ uvm_pagefree(pp);
+
+ continue;
+
+ default:
+ panic("uao_flush: weird flags");
+ }
+#ifdef DIAGNOSTIC
+ panic("uao_flush: unreachable code");
+#endif
+ }
+
+ uvm_unlock_pageq();
+
+ UVMHIST_LOG(maphist,
+ "<- done, rv=%d",retval,0,0,0);
+ return (retval);
}
/*
Home |
Main Index |
Thread Index |
Old Index