summaryrefslogtreecommitdiff
path: root/sys/uvm/uvm_aobj.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/uvm/uvm_aobj.c')
-rw-r--r--sys/uvm/uvm_aobj.c235
1 files changed, 49 insertions, 186 deletions
diff --git a/sys/uvm/uvm_aobj.c b/sys/uvm/uvm_aobj.c
index 1bcc615fadc..cc5a075e77f 100644
--- a/sys/uvm/uvm_aobj.c
+++ b/sys/uvm/uvm_aobj.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_aobj.c,v 1.45 2009/06/16 23:54:57 oga Exp $ */
+/* $OpenBSD: uvm_aobj.c,v 1.46 2009/07/22 21:05:37 oga Exp $ */
/* $NetBSD: uvm_aobj.c,v 1.39 2001/02/18 21:19:08 chs Exp $ */
/*
@@ -139,7 +139,7 @@ struct pool uao_swhash_elt_pool;
* uvm_aobj: the actual anon-backed uvm_object
*
* => the uvm_object is at the top of the structure, this allows
- * (struct uvm_device *) == (struct uvm_object *)
+ * (struct uvm_aobj *) == (struct uvm_object *)
* => only one of u_swslots and u_swhash is used in any given aobj
*/
@@ -176,8 +176,6 @@ static void uao_free(struct uvm_aobj *);
static int uao_get(struct uvm_object *, voff_t,
vm_page_t *, int *, int, vm_prot_t,
int, int);
-static boolean_t uao_releasepg(struct vm_page *,
- struct vm_page **);
static boolean_t uao_pagein(struct uvm_aobj *, int, int);
static boolean_t uao_pagein_page(struct uvm_aobj *, int);
@@ -194,10 +192,6 @@ struct uvm_pagerops aobj_pager = {
NULL, /* fault */
uao_flush, /* flush */
uao_get, /* get */
- NULL, /* put (done by pagedaemon) */
- NULL, /* cluster */
- NULL, /* mk_pcluster */
- uao_releasepg /* releasepg */
};
/*
@@ -565,7 +559,7 @@ uao_init(void)
simple_lock_init(&uao_list_lock);
/*
- * NOTE: Pages fror this pool must not come from a pageable
+ * NOTE: Pages for this pool must not come from a pageable
* kernel map!
*/
pool_init(&uao_swhash_elt_pool, sizeof(struct uao_swhash_elt),
@@ -641,8 +635,7 @@ void
uao_detach_locked(struct uvm_object *uobj)
{
struct uvm_aobj *aobj = (struct uvm_aobj *)uobj;
- struct vm_page *pg, *next;
- boolean_t busybody;
+ struct vm_page *pg;
UVMHIST_FUNC("uao_detach"); UVMHIST_CALLED(maphist);
/*
@@ -669,35 +662,26 @@ uao_detach_locked(struct uvm_object *uobj)
simple_unlock(&uao_list_lock);
/*
- * free all the pages that aren't PG_BUSY,
- * mark for release any that are.
+ * Free all pages left in the object. If they're busy, wait
+ * for them to become available before we kill it.
+ * Release swap resources then free the page.
*/
- busybody = FALSE;
- for (pg = TAILQ_FIRST(&uobj->memq); pg != NULL; pg = next) {
- next = TAILQ_NEXT(pg, listq);
+ uvm_lock_pageq();
+ while((pg = TAILQ_FIRST(&uobj->memq)) != NULL) {
if (pg->pg_flags & PG_BUSY) {
- atomic_setbits_int(&pg->pg_flags, PG_RELEASED);
- busybody = TRUE;
+ atomic_setbits_int(&pg->pg_flags, PG_WANTED);
+ uvm_unlock_pageq();
+ UVM_UNLOCK_AND_WAIT(pg, &uobj->vmobjlock, 0,
+ "uao_det", 0);
+ simple_lock(&uobj->vmobjlock);
+ uvm_lock_pageq();
continue;
}
-
- /* zap the mappings, free the swap slot, free the page */
pmap_page_protect(pg, VM_PROT_NONE);
uao_dropswap(&aobj->u_obj, pg->offset >> PAGE_SHIFT);
- uvm_lock_pageq();
uvm_pagefree(pg);
- uvm_unlock_pageq();
- }
-
- /*
- * if we found any busy pages, we're done for now.
- * mark the aobj for death, releasepg will finish up for us.
- */
- if (busybody) {
- aobj->u_flags |= UAO_FLAG_KILLME;
- simple_unlock(&aobj->u_obj.vmobjlock);
- return;
}
+ uvm_unlock_pageq();
/*
* finally, free the rest.
@@ -729,35 +713,6 @@ uao_detach_locked(struct uvm_object *uobj)
* => 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 */
@@ -766,19 +721,13 @@ boolean_t
uao_flush(struct uvm_object *uobj, voff_t start, voff_t stop, int flags)
{
struct uvm_aobj *aobj = (struct uvm_aobj *) uobj;
- struct vm_page *pp, *ppnext;
- boolean_t retval, by_list;
+ struct vm_page *pp;
voff_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);
@@ -787,13 +736,10 @@ uao_flush(struct uvm_object *uobj, voff_t start, voff_t stop, int flags)
"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%lx, by_list=%ld, flags=0x%lx",
- (u_long)start, (u_long)stop, by_list, flags);
+ UVMHIST_LOG(maphist, " flush start=0x%lx, stop=0x%lx, flags=0x%lx",
+ (u_long)start, (u_long)stop, flags, 0);
/*
* Don't need to do any work here if we're not freeing
@@ -802,44 +748,31 @@ uao_flush(struct uvm_object *uobj, voff_t start, voff_t stop, int flags)
if ((flags & (PGO_DEACTIVATE|PGO_FREE)) == 0) {
UVMHIST_LOG(maphist,
"<- done (no work to do)",0,0,0,0);
- return (retval);
+ return (TRUE);
}
- /*
- * 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.
- */
-
- if (by_list) {
- pp = TAILQ_FIRST(&uobj->memq);
- } 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 = TAILQ_NEXT(pp, listq);
-
- /* range check */
- if (pp->offset < start || pp->offset >= stop)
- continue;
- } else {
+ /* locked: uobj */
+ curoff = start;
+ for (;;) {
+ if (curoff < stop) {
+ pp = uvm_pagelookup(uobj, curoff);
curoff += PAGE_SIZE;
- if (curoff < stop)
- ppnext = uvm_pagelookup(uobj, curoff);
-
- /* null check */
if (pp == NULL)
continue;
+ } else {
+ break;
}
-
+
+ /* Make sure page is unbusy, else wait for it. */
+ if (pp->pg_flags & PG_BUSY) {
+ atomic_setbits_int(&pp->pg_flags, PG_WANTED);
+ UVM_UNLOCK_AND_WAIT(pp, &uobj->vmobjlock, 0,
+ "uaoflsh", 0);
+ simple_lock(&uobj->vmobjlock);
+ curoff -= PAGE_SIZE;
+ continue;
+ }
+
switch (flags & (PGO_CLEANIT|PGO_FREE|PGO_DEACTIVATE)) {
/*
* XXX In these first 3 cases, we always just
@@ -848,7 +781,9 @@ uao_flush(struct uvm_object *uobj, voff_t start, voff_t stop, int flags)
* XXX in the future.
*/
case PGO_CLEANIT|PGO_FREE:
+ /* FALLTHROUGH */
case PGO_CLEANIT|PGO_DEACTIVATE:
+ /* FALLTHROUGH */
case PGO_DEACTIVATE:
deactivate_it:
/* skip the page if it's loaned or wired */
@@ -856,16 +791,13 @@ uao_flush(struct uvm_object *uobj, voff_t start, voff_t stop, int flags)
pp->wire_count != 0)
continue;
-#ifdef UBC
- /* ...and deactivate the page. */
- pmap_clear_reference(pp);
-#else
+ uvm_lock_pageq();
/* zap all mappings for the page. */
pmap_page_protect(pp, VM_PROT_NONE);
/* ...and deactivate the page. */
-#endif
uvm_pagedeactivate(pp);
+ uvm_unlock_pageq();
continue;
@@ -882,19 +814,13 @@ uao_flush(struct uvm_object *uobj, voff_t start, voff_t stop, int flags)
pp->wire_count != 0)
continue;
- /*
- * mark the page as released if its busy.
- */
- if (pp->pg_flags & PG_BUSY) {
- atomic_setbits_int(&pp->pg_flags, PG_RELEASED);
- continue;
- }
-
/* zap all mappings for the page. */
pmap_page_protect(pp, VM_PROT_NONE);
uao_dropswap(uobj, pp->offset >> PAGE_SHIFT);
+ uvm_lock_pageq();
uvm_pagefree(pp);
+ uvm_unlock_pageq();
continue;
@@ -903,11 +829,9 @@ uao_flush(struct uvm_object *uobj, voff_t start, voff_t stop, int flags)
}
}
- uvm_unlock_pageq();
-
UVMHIST_LOG(maphist,
"<- done, rv=%ld",retval,0,0,0);
- return (retval);
+ return (TRUE);
}
/*
@@ -989,10 +913,10 @@ uao_get(struct uvm_object *uobj, voff_t offset, struct vm_page **pps,
}
/*
- * to be useful must get a non-busy, non-released page
+ * to be useful must get a non-busy page
*/
if (ptmp == NULL ||
- (ptmp->pg_flags & (PG_BUSY|PG_RELEASED)) != 0) {
+ (ptmp->pg_flags & PG_BUSY) != 0) {
if (lcv == centeridx ||
(flags & PGO_ALLPAGES) != 0)
/* need to do a wait or I/O! */
@@ -1099,7 +1023,7 @@ uao_get(struct uvm_object *uobj, voff_t offset, struct vm_page **pps,
}
/* page is there, see if we need to wait on it */
- if ((ptmp->pg_flags & (PG_BUSY|PG_RELEASED)) != 0) {
+ if ((ptmp->pg_flags & PG_BUSY) != 0) {
atomic_setbits_int(&ptmp->pg_flags, PG_WANTED);
UVMHIST_LOG(pdhist,
"sleeping, ptmp->flags 0x%lx\n",
@@ -1138,8 +1062,7 @@ uao_get(struct uvm_object *uobj, voff_t offset, struct vm_page **pps,
/*
* just zero the page if there's nothing in swap.
*/
- if (swslot == 0)
- {
+ if (swslot == 0) {
/*
* page hasn't existed before, just zero it.
*/
@@ -1216,65 +1139,6 @@ uao_get(struct uvm_object *uobj, voff_t offset, struct vm_page **pps,
}
/*
- * uao_releasepg: handle released page in an aobj
- *
- * => "pg" is a PG_BUSY [caller owns it], PG_RELEASED page that we need
- * to dispose of.
- * => caller must handle PG_WANTED case
- * => called with page's object locked, pageq's unlocked
- * => returns TRUE if page's object is still alive, FALSE if we
- * killed the page's object. if we return TRUE, then we
- * return with the object locked.
- * => if (nextpgp != NULL) => we return the next page on the queue, and return
- * with the page queues locked [for pagedaemon]
- * => if (nextpgp == NULL) => we return with page queues unlocked [normal case]
- * => we kill the aobj if it is not referenced and we are suppose to
- * kill it ("KILLME").
- */
-static boolean_t
-uao_releasepg(struct vm_page *pg, struct vm_page **nextpgp /* OUT */)
-{
- struct uvm_aobj *aobj = (struct uvm_aobj *) pg->uobject;
-
- KASSERT(pg->pg_flags & PG_RELEASED);
-
- /*
- * dispose of the page [caller handles PG_WANTED] and swap slot.
- */
- pmap_page_protect(pg, VM_PROT_NONE);
- uao_dropswap(&aobj->u_obj, pg->offset >> PAGE_SHIFT);
- uvm_lock_pageq();
- if (nextpgp)
- *nextpgp = TAILQ_NEXT(pg, pageq); /* next page for daemon */
- uvm_pagefree(pg);
- if (!nextpgp)
- uvm_unlock_pageq(); /* keep locked for daemon */
-
- /*
- * if we're not killing the object, we're done.
- */
- if ((aobj->u_flags & UAO_FLAG_KILLME) == 0)
- return TRUE;
- KASSERT(aobj->u_obj.uo_refs == 0);
-
- /*
- * if there are still pages in the object, we're done for now.
- */
- if (aobj->u_obj.uo_npages != 0)
- return TRUE;
-
- KASSERT(TAILQ_EMPTY(&aobj->u_obj.memq));
-
- /*
- * finally, free the rest.
- */
- uao_free(aobj);
-
- return FALSE;
-}
-
-
-/*
* uao_dropswap: release any swap resources from this aobj page.
*
* => aobj must be locked or have a reference count of 0.
@@ -1476,7 +1340,6 @@ uao_pagein_page(struct uvm_aobj *aobj, int pageidx)
return FALSE;
}
- KASSERT((pg->pg_flags & PG_RELEASED) == 0);
/*
* ok, we've got the page now.