aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMateusz Guzik <mjg@FreeBSD.org>2022-08-17 16:24:14 +0000
committerMateusz Guzik <mjg@FreeBSD.org>2022-08-17 16:24:14 +0000
commit1b89d40fbf7788c75a7612b22b1dba1612e45c9a (patch)
treeb07f802e2d686d257a176d01f8a4f3c86b37c25a
parente674ddec0b4138274539587fe9336b577ff1242a (diff)
downloadsrc-1b89d40fbf7788c75a7612b22b1dba1612e45c9a.tar.gz
src-1b89d40fbf7788c75a7612b22b1dba1612e45c9a.zip
Revert "vm: use atomic fetchadd in vm_page_sunbusy"
This reverts commit f6ffed44a8eb5d1ab89a18e60fb056aab2105be7. fetchadd will fail the waiters flag, which can cause other code to wait when it should not with nothing clear it Revert until I sort this out. Reported by: markj
-rw-r--r--sys/vm/vm_page.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index defcebb286ae..e7500e9d3e71 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -973,13 +973,27 @@ vm_page_sunbusy(vm_page_t m)
{
u_int x;
- 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))
+ 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;
wakeup(m);
+ break;
+ }
}
/*