summaryrefslogtreecommitdiff
path: root/sys/uvm/uvm_km.c
diff options
context:
space:
mode:
authorOwain Ainsworth <oga@cvs.openbsd.org>2011-05-10 21:48:18 +0000
committerOwain Ainsworth <oga@cvs.openbsd.org>2011-05-10 21:48:18 +0000
commit563ca8765260186ce5628efb1fc5501b5e34c8f7 (patch)
tree46fa4124973f87704bc3d2cd99e3599812ebb963 /sys/uvm/uvm_km.c
parent2c12eefb2876e0c05a397f3bba92fc865bb0624d (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.c27
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);
}
}
}