vm: use atomic fetchadd in vm_page_sunbusy

This also fixes a bug where not-last unbusy failed to post a release
fence.

Reviewed by:	markj (previous version), kib (previous version)
Differential Revision:	https://reviews.freebsd.org/D36084
This commit is contained in:
Mateusz Guzik 2022-08-05 14:27:55 +00:00
parent f741319724
commit f6ffed44a8

View File

@ -973,27 +973,13 @@ vm_page_sunbusy(vm_page_t m)
{
u_int x;
vm_page_assert_sbusied(m);
x = vm_page_busy_fetch(m);
for (;;) {
KASSERT(x != VPB_FREED,
("vm_page_sunbusy: Unlocking freed page."));
if (VPB_SHARERS(x) > 1) {
if (atomic_fcmpset_int(&m->busy_lock, &x,
x - VPB_ONE_SHARER))
break;
continue;
}
KASSERT((x & ~VPB_BIT_WAITERS) == VPB_SHARERS_WORD(1),
("vm_page_sunbusy: invalid lock state"));
if (!atomic_fcmpset_rel_int(&m->busy_lock, &x, VPB_UNBUSIED))
continue;
if ((x & VPB_BIT_WAITERS) == 0)
break;
atomic_thread_fence_rel();
x = atomic_fetchadd_int(&m->busy_lock, -VPB_ONE_SHARER);
KASSERT(x != VPB_FREED, ("page %p is freed", m));
KASSERT(x != VPB_UNBUSIED && (x & VPB_BIT_SHARED) != 0,
("page %p not sbusied", m));
if (x == (VPB_SHARERS_WORD(1) | VPB_BIT_WAITERS))
wakeup(m);
break;
}
}
/*