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
This commit is contained in:
Konstantin Belousov 2013-09-05 12:54:40 +00:00
parent 187a8d4b7a
commit 7a4b2bc56c

View File

@ -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);
}
}
/*