diff options
author | Owain Ainsworth <oga@cvs.openbsd.org> | 2011-05-10 21:48:18 +0000 |
---|---|---|
committer | Owain Ainsworth <oga@cvs.openbsd.org> | 2011-05-10 21:48:18 +0000 |
commit | 563ca8765260186ce5628efb1fc5501b5e34c8f7 (patch) | |
tree | 46fa4124973f87704bc3d2cd99e3599812ebb963 /sys/uvm/uvm_km.c | |
parent | 2c12eefb2876e0c05a397f3bba92fc865bb0624d (diff) |
Don't leak swapslots when doing a uvm_km_pgremove and a page is in swap only.
Before we were only calling uao_dropswap() if there was a page, maning
that if the buffer was swapped out then we would leak the slot.
Quite rare because only pipebuffers should swap from the kernel object,
but i've seen panics that implied this had happened (alpha.p for example).
ok thib@ after a lot of discussion and checking the semantics.
Diffstat (limited to 'sys/uvm/uvm_km.c')
-rw-r--r-- | sys/uvm/uvm_km.c | 27 |
1 files changed, 12 insertions, 15 deletions
diff --git a/sys/uvm/uvm_km.c b/sys/uvm/uvm_km.c index 2a3a2ffe7c6..368aaa92f2d 100644 --- a/sys/uvm/uvm_km.c +++ b/sys/uvm/uvm_km.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_km.c,v 1.100 2011/04/23 17:48:48 kettenis Exp $ */ +/* $OpenBSD: uvm_km.c,v 1.101 2011/05/10 21:48:17 oga Exp $ */ /* $NetBSD: uvm_km.c,v 1.42 2001/01/14 02:10:01 thorpej Exp $ */ /* @@ -267,36 +267,33 @@ uvm_km_pgremove(struct uvm_object *uobj, vaddr_t start, vaddr_t end) { struct vm_page *pp; voff_t curoff; + int slot; UVMHIST_FUNC("uvm_km_pgremove"); UVMHIST_CALLED(maphist); KASSERT(uobj->pgops == &aobj_pager); for (curoff = start ; curoff < end ; curoff += PAGE_SIZE) { pp = uvm_pagelookup(uobj, curoff); - if (pp == NULL) - continue; - - UVMHIST_LOG(maphist," page %p, busy=%ld", pp, - pp->pg_flags & PG_BUSY, 0, 0); - - if (pp->pg_flags & PG_BUSY) { + if (pp && pp->pg_flags & PG_BUSY) { atomic_setbits_int(&pp->pg_flags, PG_WANTED); UVM_UNLOCK_AND_WAIT(pp, &uobj->vmobjlock, 0, "km_pgrm", 0); simple_lock(&uobj->vmobjlock); curoff -= PAGE_SIZE; /* loop back to us */ continue; - } else { - /* free the swap slot... */ - uao_dropswap(uobj, curoff >> PAGE_SHIFT); + } + + /* free the swap slot, then the page */ + slot = uao_dropswap(uobj, curoff >> PAGE_SHIFT); - /* - * ...and free the page; note it may be on the - * active or inactive queues. - */ + if (pp != NULL) { uvm_lock_pageq(); uvm_pagefree(pp); uvm_unlock_pageq(); + } else if (slot != 0) { + simple_lock(&uvm.swap_data_lock); + uvmexp.swpgonly--; + simple_unlock(&uvm.swap_data_lock); } } } |