summaryrefslogtreecommitdiffstats
path: root/sys/vm/vm_page.c
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>2002-02-19 23:19:30 +0000
committertegge <tegge@FreeBSD.org>2002-02-19 23:19:30 +0000
commit5f4060fe3b8fa452dbd71d3403ece380470dae76 (patch)
tree99edeec5e5d906e1fc6a786d33ae94e0a71f13df /sys/vm/vm_page.c
parent872134cfe5d102e39b3dbc8363c48462882de702 (diff)
downloadFreeBSD-src-5f4060fe3b8fa452dbd71d3403ece380470dae76.zip
FreeBSD-src-5f4060fe3b8fa452dbd71d3403ece380470dae76.tar.gz
Add a page queue, PQ_HOLD, that temporarily owns pages with nonzero hold
count that would otherwise be on one of the free queues. This eliminates a panic when broken programs unmap memory that still has pending IO from raw devices. Reviewed by: dillon, alc
Diffstat (limited to 'sys/vm/vm_page.c')
-rw-r--r--sys/vm/vm_page.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index 047125f..5141708 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -413,6 +413,8 @@ vm_page_unhold(vm_page_t mem)
GIANT_REQUIRED;
--mem->hold_count;
KASSERT(mem->hold_count >= 0, ("vm_page_unhold: hold count < 0!!!"));
+ if (mem->hold_count == 0 && mem->queue == PQ_HOLD)
+ vm_page_free_toq(mem);
}
/*
@@ -1108,8 +1110,7 @@ vm_page_free_toq(vm_page_t m)
s = splvm();
cnt.v_tfree++;
- if (m->busy || ((m->queue - m->pc) == PQ_FREE) ||
- (m->hold_count != 0)) {
+ if (m->busy || ((m->queue - m->pc) == PQ_FREE)) {
printf(
"vm_page_free: pindex(%lu), busy(%d), PG_BUSY(%d), hold(%d)\n",
(u_long)m->pindex, m->busy, (m->flags & PG_BUSY) ? 1 : 0,
@@ -1178,7 +1179,11 @@ vm_page_free_toq(vm_page_t m)
#endif
}
- m->queue = PQ_FREE + m->pc;
+ if (m->hold_count != 0) {
+ m->flags &= ~PG_ZERO;
+ m->queue = PQ_HOLD;
+ } else
+ m->queue = PQ_FREE + m->pc;
pq = &vm_page_queues[m->queue];
pq->lcnt++;
++(*pq->cnt);
OpenPOWER on IntegriCloud