summaryrefslogtreecommitdiffstats
path: root/sys/vm/vm_page.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2013-09-05 12:54:40 +0000
committerkib <kib@FreeBSD.org>2013-09-05 12:54:40 +0000
commit7ab18d4990d80767c250514df82b25bd076c5801 (patch)
tree138dc3860ef9530acb37af4e45319255e4607094 /sys/vm/vm_page.c
parent795da63f42e0a9f2beb0ea81351fc839f169fa6e (diff)
downloadFreeBSD-src-7ab18d4990d80767c250514df82b25bd076c5801.zip
FreeBSD-src-7ab18d4990d80767c250514df82b25bd076c5801.tar.gz
The vm_page_trysbusy() should not fail when shared busy counter or
VPB_BIT_WAITERS flag were changed between reading of busy_lock and the cas. The vm_page_sbusy(), which is the only user of vm_page_trysbusy() in the tree, panics on the failure, which in these cases is transient and do not mean that the current page state prevents sbusying. Retry the operation inside vm_page_trysbusy() if cas failed, only return a failure when VPB_BIT_SHARED is cleared. Reported and tested by: pho Reviewed by: attilio Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'sys/vm/vm_page.c')
-rw-r--r--sys/vm/vm_page.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index 7b4b57c..53ffc72 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -602,9 +602,13 @@ vm_page_trysbusy(vm_page_t m)
{
u_int x;
- x = m->busy_lock;
- return ((x & VPB_BIT_SHARED) != 0 &&
- atomic_cmpset_acq_int(&m->busy_lock, x, x + VPB_ONE_SHARER));
+ for (;;) {
+ x = m->busy_lock;
+ if ((x & VPB_BIT_SHARED) == 0)
+ return (0);
+ if (atomic_cmpset_acq_int(&m->busy_lock, x, x + VPB_ONE_SHARER))
+ return (1);
+ }
}
/*
OpenPOWER on IntegriCloud