Page MenuHomeFreeBSD

Generalize lazy dequeue logic for wired pages.
ClosedPublic

Authored by markj on Dec 19 2019, 10:16 PM.
Tags
None
Referenced Files
Unknown Object (File)
Sep 26 2023, 9:20 AM
Unknown Object (File)
Sep 19 2023, 10:53 AM
Unknown Object (File)
Sep 7 2023, 2:26 PM
Unknown Object (File)
Sep 7 2023, 2:25 PM
Unknown Object (File)
Sep 7 2023, 2:22 PM
Unknown Object (File)
Sep 1 2023, 11:13 PM
Unknown Object (File)
Jul 9 2023, 2:09 AM
Unknown Object (File)
Jun 25 2023, 4:36 AM
Subscribers

Details

Summary

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.

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

jeff added inline comments.
sys/vm/vm_page.c
3903–3904 ↗(On Diff #65824)

Do we need the loop to make DEQUEUE atomic with ref_count? If it can be set on a stale reference this could use old = atomic_fetchadd_int(ref_count, -1) which would be faster than cmpset.

This revision is now accepted and ready to land.Dec 20 2019, 11:11 PM
sys/vm/vm_page.c
3903–3904 ↗(On Diff #65824)

Yes, we must avoid setting or clearing PGA_DEQUEUE after the reference is dropped. If the page is busy or the object is locked we do not need to use a cmpset loop and fetchadd is sufficient. We take advantage of that fact in certain places. For example, vm_page_release_locked() releases a wiring with the object lock held and thus just uses vm_page_drop().

This revision was automatically updated to reflect the committed changes.