summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2015-10-18 09:33:28 +0000
committerkib <kib@FreeBSD.org>2015-10-18 09:33:28 +0000
commit9d188e9d5cda858010e5985995d7becd469456f8 (patch)
tree75895eaeab973fa6cd0b491ad6581bc37c8d88f8
parentc1a65e2b3fddbf58c4e8adbdcc00d3b93585e8ee (diff)
downloadFreeBSD-src-9d188e9d5cda858010e5985995d7becd469456f8.zip
FreeBSD-src-9d188e9d5cda858010e5985995d7becd469456f8.tar.gz
Only marker is guaranteed to be present on the queue after the relock
in vm_pageout_fallback_object_lock() and vm_pageout_page_lock(). The check for the m->queue == queue assumes that the page does belong to a queue. Modify the 'unchanged' calculation bu dereferencing the marker tailq pointers, which is known to belong to the queue. Since for a page m linked to the queue, m->queue must be equal to the queue index, assert this instead of checking. In collaboration with: alc Sponsored by: The FreeBSD Foundation (kib) MFC after: 2 weeks
-rw-r--r--sys/vm/vm_pageout.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c
index e0d00f5..188866e 100644
--- a/sys/vm/vm_pageout.c
+++ b/sys/vm/vm_pageout.c
@@ -292,11 +292,21 @@ vm_pageout_fallback_object_lock(vm_page_t m, vm_page_t *next)
vm_page_lock(m);
vm_pagequeue_lock(pq);
- /* Page queue might have changed. */
+ /*
+ * The page's object might have changed, and/or the page might
+ * have moved from its original position in the queue. If the
+ * page's object has changed, then the caller should abandon
+ * processing the page because the wrong object lock was
+ * acquired. Use the marker's plinks.q, not the page's, to
+ * determine if the page has been moved. The state of the
+ * page's plinks.q can be indeterminate; whereas, the marker's
+ * plinks.q must be valid.
+ */
*next = TAILQ_NEXT(&marker, plinks.q);
- unchanged = (m->queue == queue &&
- m->object == object &&
- &marker == TAILQ_NEXT(m, plinks.q));
+ unchanged = m->object == object &&
+ m == TAILQ_PREV(&marker, pglist, plinks.q);
+ KASSERT(!unchanged || m->queue == queue,
+ ("page %p queue %d %d", m, queue, m->queue));
TAILQ_REMOVE(&pq->pq_pl, &marker, plinks.q);
return (unchanged);
}
@@ -333,7 +343,9 @@ vm_pageout_page_lock(vm_page_t m, vm_page_t *next)
/* Page queue might have changed. */
*next = TAILQ_NEXT(&marker, plinks.q);
- unchanged = (m->queue == queue && &marker == TAILQ_NEXT(m, plinks.q));
+ unchanged = m == TAILQ_PREV(&marker, pglist, plinks.q);
+ KASSERT(!unchanged || m->queue == queue,
+ ("page %p queue %d %d", m, queue, m->queue));
TAILQ_REMOVE(&pq->pq_pl, &marker, plinks.q);
return (unchanged);
}
OpenPOWER on IntegriCloud