summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralc <alc@FreeBSD.org>2007-07-10 18:41:34 +0000
committeralc <alc@FreeBSD.org>2007-07-10 18:41:34 +0000
commit3b36c8e7eb7c86086d3023d7ca83d3b6c33a0582 (patch)
tree05d96993080c6bf4f737c85a00ece8514f5ffba2
parent7fce1d7b71e9d9faba1096e731edfa6528bbeea4 (diff)
downloadFreeBSD-src-3b36c8e7eb7c86086d3023d7ca83d3b6c33a0582.zip
FreeBSD-src-3b36c8e7eb7c86086d3023d7ca83d3b6c33a0582.tar.gz
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
-rw-r--r--sys/vm/vm_page.c24
1 files 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) {
OpenPOWER on IntegriCloud