Page MenuHomeFreeBSD

Generalize lazy dequeue logic for wired pages.
ClosedPublic

Authored by markj on Dec 19 2019, 10:16 PM.
Tags
None
Referenced Files
F83215703: D22882.diff
Tue, May 7, 7:39 PM
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
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

Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 28238
Build 26361: arc lint + arc unit

Event Timeline

jeff added inline comments.
sys/vm/vm_page.c
3903–3904

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

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.