The aim of this patch set is to remove the need for the page lock in
performing per-page queue state updates, including in the page queue
scans. We also wish to preserve the current behaviour of lazily
dequeuing wired pages to avoid page queue lock contention if a page is
frequently wired and unwired. But, without the page lock we cannot
directly synchronize unwiring with lazy dequeue. For example, suppose
the page daemon encounters a wired page and calls
vm_page_dequeue_deferred() and is preempted before setting PGA_DEQUEUE.
Suppose that a thread concurrently unwires the page into a queue. We
need to ensure that the page daemon does not dequeue the page after it
has been unwired, since that would leave the unwired page outside of any
queue. Worse, since the page daemon holds no reference to the page, it
could race with a subsequent free of the page.
Handle this by setting PGA_DEQUEUE when a managed page's wire count
transitions from 0 to 1. When the page daemon encounters a page with a
flag in PGA_QUEUE_OP_MASK set, it creates a batch queue entry for that
page, but in so doing it does not modify the page itself and thus racing
with a concurrent free of the page is harmless.
vm_page_unwire_managed() now must clear PGA_DEQUEUE on a 1->0
transition. It must do this before dropping the reference to avoid a
use-after-free but we should handle races with current wirings to
ensure that PGA_DEQUEUE is not left unset on a wired page.
The page daemon will correctly handle wired pages without PGA_DEQUEUE
set; its use here is simply an optimization to allow the page daemon to
skip over pages before acquirining any locks.
Remove some duplicated logic among vm_page_mvqueue() callers.