lockmgr: rewrite upgrade to stop always dropping the lock
This matches rw and sx locks.
This commit is contained in:
parent
bdb6d824f4
commit
f6b091fbbd
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=363393
@ -878,9 +878,8 @@ static __noinline int
|
|||||||
lockmgr_upgrade(struct lock *lk, u_int flags, struct lock_object *ilk,
|
lockmgr_upgrade(struct lock *lk, u_int flags, struct lock_object *ilk,
|
||||||
const char *file, int line, struct lockmgr_wait *lwa)
|
const char *file, int line, struct lockmgr_wait *lwa)
|
||||||
{
|
{
|
||||||
uintptr_t tid, x, v;
|
uintptr_t tid, v, setv;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
int wakeup_swapper = 0;
|
|
||||||
int op;
|
int op;
|
||||||
|
|
||||||
if (KERNEL_PANICKED())
|
if (KERNEL_PANICKED())
|
||||||
@ -889,48 +888,47 @@ lockmgr_upgrade(struct lock *lk, u_int flags, struct lock_object *ilk,
|
|||||||
tid = (uintptr_t)curthread;
|
tid = (uintptr_t)curthread;
|
||||||
|
|
||||||
_lockmgr_assert(lk, KA_SLOCKED, file, line);
|
_lockmgr_assert(lk, KA_SLOCKED, file, line);
|
||||||
v = lockmgr_read_value(lk);
|
|
||||||
x = v & LK_ALL_WAITERS;
|
|
||||||
v &= LK_EXCLUSIVE_SPINNERS;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to switch from one shared lock to an exclusive one.
|
|
||||||
* We need to preserve waiters flags during the operation.
|
|
||||||
*/
|
|
||||||
if (atomic_cmpset_ptr(&lk->lk_lock, LK_SHARERS_LOCK(1) | x | v,
|
|
||||||
tid | x)) {
|
|
||||||
LOCK_LOG_LOCK("XUPGRADE", &lk->lock_object, 0, 0, file,
|
|
||||||
line);
|
|
||||||
WITNESS_UPGRADE(&lk->lock_object, LOP_EXCLUSIVE |
|
|
||||||
LK_TRYWIT(flags), file, line);
|
|
||||||
LOCKSTAT_RECORD0(lockmgr__upgrade, lk);
|
|
||||||
TD_SLOCKS_DEC(curthread);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
op = flags & LK_TYPE_MASK;
|
op = flags & LK_TYPE_MASK;
|
||||||
|
v = lockmgr_read_value(lk);
|
||||||
|
for (;;) {
|
||||||
|
if (LK_SHARERS_LOCK(v) > 1) {
|
||||||
|
if (op == LK_TRYUPGRADE) {
|
||||||
|
LOCK_LOG2(lk, "%s: %p failed the nowait upgrade",
|
||||||
|
__func__, lk);
|
||||||
|
error = EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (lockmgr_sunlock_try(lk, &v)) {
|
||||||
|
lockmgr_note_shared_release(lk, file, line);
|
||||||
|
goto out_xlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MPASS((v & ~LK_ALL_WAITERS) == LK_SHARERS_LOCK(1));
|
||||||
|
|
||||||
/*
|
setv = tid;
|
||||||
* In LK_TRYUPGRADE mode, do not drop the lock,
|
setv |= (v & LK_ALL_WAITERS);
|
||||||
* returning EBUSY instead.
|
|
||||||
*/
|
/*
|
||||||
if (op == LK_TRYUPGRADE) {
|
* Try to switch from one shared lock to an exclusive one.
|
||||||
LOCK_LOG2(lk, "%s: %p failed the nowait upgrade",
|
* We need to preserve waiters flags during the operation.
|
||||||
__func__, lk);
|
*/
|
||||||
error = EBUSY;
|
if (atomic_fcmpset_ptr(&lk->lk_lock, &v, setv)) {
|
||||||
goto out;
|
LOCK_LOG_LOCK("XUPGRADE", &lk->lock_object, 0, 0, file,
|
||||||
|
line);
|
||||||
|
WITNESS_UPGRADE(&lk->lock_object, LOP_EXCLUSIVE |
|
||||||
|
LK_TRYWIT(flags), file, line);
|
||||||
|
LOCKSTAT_RECORD0(lockmgr__upgrade, lk);
|
||||||
|
TD_SLOCKS_DEC(curthread);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
out_xlock:
|
||||||
* We have been unable to succeed in upgrading, so just
|
|
||||||
* give up the shared lock.
|
|
||||||
*/
|
|
||||||
lockmgr_note_shared_release(lk, file, line);
|
|
||||||
wakeup_swapper |= wakeupshlk(lk, file, line);
|
|
||||||
error = lockmgr_xlock_hard(lk, flags, ilk, file, line, lwa);
|
error = lockmgr_xlock_hard(lk, flags, ilk, file, line, lwa);
|
||||||
flags &= ~LK_INTERLOCK;
|
flags &= ~LK_INTERLOCK;
|
||||||
out:
|
out:
|
||||||
lockmgr_exit(flags, ilk, wakeup_swapper);
|
lockmgr_exit(flags, ilk, 0);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user