]> xenbits.xensource.com Git - people/julieng/freebsd.git/commitdiff
Only marker is guaranteed to be present on the queue after the relock
authorkib <kib@FreeBSD.org>
Sun, 18 Oct 2015 09:33:28 +0000 (09:33 +0000)
committerkib <kib@FreeBSD.org>
Sun, 18 Oct 2015 09:33:28 +0000 (09:33 +0000)
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

sys/vm/vm_pageout.c

index e0d00f5172f30516a4ed8d03efdbc2f22abb96f7..188866efbec4ac63140ed8fd2a617efa95c44476 100644 (file)
@@ -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);
 }