From 3b36c8e7eb7c86086d3023d7ca83d3b6c33a0582 Mon Sep 17 00:00:00 2001 From: alc Date: Tue, 10 Jul 2007 18:41:34 +0000 Subject: Correct a problem in the ZERO_COPY_SOCKETS option, specifically, in vm_page_cowfault(). Initially, if vm_page_cowfault() sleeps, the given page is wired, preventing it from being recycled. However, when transmission of the page completes, the page is unwired and returned to the page queues. At that point, the page is not in any special state that prevents it from being recycled. Consequently, vm_page_cowfault() should verify that the page is still held by the same vm object before retrying the replacement of the page. Note: The containing object is, however, safe from being recycled by virtue of having a non-zero paging-in-progress count. While I'm here, add some assertions and comments. Approved by: re (rwatson) MFC After: 3 weeks --- sys/vm/vm_page.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index d4a7ba5..947e5d4 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -1697,6 +1697,14 @@ vm_page_test_dirty(vm_page_t m) int so_zerocp_fullpage = 0; +/* + * Replace the given page with a copy. The copied page assumes + * the portion of the given page's "wire_count" that is not the + * responsibility of this copy-on-write mechanism. + * + * The object containing the given page must have a non-zero + * paging-in-progress count and be locked. + */ void vm_page_cowfault(vm_page_t m) { @@ -1705,6 +1713,10 @@ vm_page_cowfault(vm_page_t m) vm_pindex_t pindex; object = m->object; + VM_OBJECT_LOCK_ASSERT(object, MA_OWNED); + KASSERT(object->paging_in_progress != 0, + ("vm_page_cowfault: object %p's paging-in-progress count is zero.", + object)); pindex = m->pindex; retry_alloc: @@ -1717,8 +1729,16 @@ vm_page_cowfault(vm_page_t m) VM_OBJECT_UNLOCK(object); VM_WAIT; VM_OBJECT_LOCK(object); - vm_page_lock_queues(); - goto retry_alloc; + if (m == vm_page_lookup(object, pindex)) { + vm_page_lock_queues(); + goto retry_alloc; + } else { + /* + * Page disappeared during the wait. + */ + vm_page_lock_queues(); + return; + } } if (m->cow == 0) { -- cgit v1.1