diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2024-08-27 21:33:38 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2024-08-28 14:33:58 +0000 |
commit | 0b6b1c285920563ba0c119d3190ac25af4731d02 (patch) | |
tree | 0e3c1e020a0715001ac3fcb0922bab0185c99100 /sys/kern | |
parent | 75447afca868f82f1c53c5be32dccd777813ec1a (diff) | |
download | src-0b6b1c285920563ba0c119d3190ac25af4731d02.tar.gz src-0b6b1c285920563ba0c119d3190ac25af4731d02.zip |
Add rangelock_may_recurse(9)
Reviewed by: markj
Tested by: lwhsu
Sponsored by: The FreeBSD Foundation
Differential revision: https://reviews.freebsd.org/D46465
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_rangelock.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/sys/kern/kern_rangelock.c b/sys/kern/kern_rangelock.c index 0e62b91b4ee7..4d74c02302e7 100644 --- a/sys/kern/kern_rangelock.c +++ b/sys/kern/kern_rangelock.c @@ -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) |