Skip to content

Commit

Permalink
Add rangelock_may_recurse(9)
Browse files Browse the repository at this point in the history
Reviewed by:	markj
Tested by:	lwhsu
Sponsored by:	The FreeBSD Foundation
Differential revision:	https://reviews.freebsd.org/D46465
  • Loading branch information
kostikbel committed Aug 28, 2024
1 parent 75447af commit 0b6b1c2
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 0 deletions.
41 changes: 41 additions & 0 deletions sys/kern/kern_rangelock.c
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,47 @@ rangelock_trywlock(struct rangelock *lock, vm_ooffset_t start, vm_ooffset_t end)
return (rangelock_lock_int(lock, true, start, end, RL_LOCK_WRITE));
}

/*
* If the caller asserts that it can obtain the range locks on the
* same lock simultaneously, switch to the non-cheat mode. Cheat mode
* cannot handle it, hanging in drain or trylock retries.
*/
void
rangelock_may_recurse(struct rangelock *lock)
{
uintptr_t v, x;

v = atomic_load_ptr(&lock->head);
if ((v & RL_CHEAT_CHEATING) == 0)
return;

sleepq_lock(&lock->head);
for (;;) {
if ((v & RL_CHEAT_CHEATING) == 0) {
sleepq_release(&lock->head);
return;
}

/* Cheating and locked, drain. */
if ((v & RL_CHEAT_WLOCKED) != 0 ||
(v & ~RL_CHEAT_MASK) >= RL_CHEAT_READER) {
x = v | RL_CHEAT_DRAINING;
if (atomic_fcmpset_ptr(&lock->head, &v, x) != 0) {
rangelock_cheat_drain(lock);
return;
}
continue;
}

/* Cheating and unlocked, clear RL_CHEAT_CHEATING. */
x = 0;
if (atomic_fcmpset_ptr(&lock->head, &v, x) != 0) {
sleepq_release(&lock->head);
return;
}
}
}

#ifdef INVARIANT_SUPPORT
void
_rangelock_cookie_assert(void *cookie, int what, const char *file, int line)
Expand Down
1 change: 1 addition & 0 deletions sys/sys/rangelock.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ void *rangelock_wlock(struct rangelock *lock, vm_ooffset_t start,
void *rangelock_trywlock(struct rangelock *lock, vm_ooffset_t start,
vm_ooffset_t end);
void rangelock_entry_free(struct rl_q_entry *e);
void rangelock_may_recurse(struct rangelock *lock);
#if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
void _rangelock_cookie_assert(void *cookie, int what, const char *file,
int line);
Expand Down

0 comments on commit 0b6b1c2

Please sign in to comment.