Page MenuHomeFreeBSD

Remove the page lock dependency on busy sleeps by using sleepq to avoid races.
ClosedPublic

Authored by jeff on Aug 13 2019, 8:08 PM.
Tags
None
Referenced Files
F106274205: D21255.id60810.diff
Sat, Dec 28, 8:47 AM
F106245892: D21255.diff
Fri, Dec 27, 8:34 PM
Unknown Object (File)
Wed, Dec 25, 12:57 PM
Unknown Object (File)
Sun, Dec 22, 4:00 PM
Unknown Object (File)
Tue, Dec 10, 7:17 PM
Unknown Object (File)
Sat, Nov 30, 11:02 AM
Unknown Object (File)
Nov 26 2024, 6:19 PM
Unknown Object (File)
Nov 17 2024, 4:26 AM
Subscribers

Details

Summary

This uses the sleepq lock itself to synchronize busy sleep/wakeup and avoids the need for the page lock. I need the lock test and conditional acquire/release for a later patch. It could be elided for now but it allows for simplifying some consumers already.

I didn't realize some diffs from a different patchset snuck in and I will correct that. I made a note where this occurred.

Diff Detail

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

Event Timeline

jeff added reviewers: alc, kib, markj.
sys/vm/vm_page.c
966 ↗(On Diff #60758)

If the page lock isn't held and the object lock isn't held, what prevents m from being freed after the call to vm_page_busy_sleep() and before the dereference of m->object?

sys/vm/vm_page.c
966 ↗(On Diff #60758)

Nothing prevents it. I believe we handle the race gracefully.

m->object could become NULL at any point after we drop the object lock. However, this means the busy holder is removing the page and will unbusy at some point, waking us up, or avoiding the sleep below.

All vm_page_busy_sleep callers are basically doing what we call "WAITFAIL" elsewhere. They don't return with the busy lock held. They restart compound operations and look for the correct page again.

It is possible that the page could be freed, reallocated, and we sleep for the wrong thing. However, I believe this is harmless and rare. It would be possible to treat the object lock as an interlock here with a slightly more complicated and expensive sleepq operation. Cases that don't hold the object lock are protected by a wire count.

3961–3963 ↗(On Diff #60758)

This is a merge bug and related to a later diff.

sys/vm/vm_pageout.c
378 ↗(On Diff #60758)

Merge bug for later diff.

sys/vm/vm_page.c
966 ↗(On Diff #60758)

The wiring doesn't prevent the page from being removed from its object, in which case m->object will become NULL. See vm_object_terminate_pages() for instance.

sys/vm/vm_page.c
966 ↗(On Diff #60758)

Yes I understand but it does prevent the page from being reallocated to some other purpose. So there is no chance of a spurious sleep.

sys/vm/vm_page.c
966 ↗(On Diff #60758)

We still need to check that obj is non-NULL before dereferencing it.

sys/vm/vm_page.c
932 ↗(On Diff #60758)

I wonder if this needs atomc_cmpset_int_rel. Before, the vm_page_unlock() provided the release semantic, sunbusy acts as unlock. vm_page_xunbusy does use _rel.

961 ↗(On Diff #60758)

Then assert that the object ref count is > 0 ?

I would prefer to convert the nonshared argument to flags, and add two flags, one for nonshared, another for obj_locked, instead of using VM_OBJECT_WOWNED().

sys/vm/vm_page.c
961 ↗(On Diff #60758)

I copied the comment from elsewhere. I'm not comfortable enough with all callers to add a new assert. This may be used in the object tear-down path for example. We rely on object type stability elsewhere.

I thought about the flag. It is a tradeoff. With a flag you are more explicit and so less likely to have bugs where the caller doesn't realize the object lock is dropped. However, you're then subject to bugs where the flag was just specified wrong. With the silent operation you won't have bugs with releasing/re-acquiring the lock but the caller may not anticipate losing synchronization.

If you follow all of my patch sets you will see that ultimately there are few cases that are called with any lock held so I settled on this method.

Address review feedback. Clean up patch. Switch to fcmpset and rel semantics.

Respond to review feedback. Eliminate the object locking changes for now.

This revision is now accepted and ready to land.Aug 20 2019, 1:21 AM

Resolve identity change issues

This revision now requires review to proceed.Sep 5 2019, 6:31 PM
This revision is now accepted and ready to land.Sep 5 2019, 8:52 PM
sys/dev/drm2/ttm/ttm_bo_vm.c
236–237 ↗(On Diff #61698)

I'm curious as to why you didn't further simplify cases like this one to:

if (vm_page_sleep_if_busy(m, "ttmpbs")) {
        ttm_mem_io_unlock(man);
sys/dev/drm2/ttm/ttm_bo_vm.c
236–237 ↗(On Diff #61698)

This is turned into a vm_page_busy_acquire() in another patch I have in review.

if (vm_page_busy_acquire(m, VM_ALLOC_WAITFAIL) == 0) {
        ttm_mem_io_unlock(man);
        ttm_bo_unreserve(bo);
        goto retry;
}