mirror of
https://github.com/versity/scoutfs.git
synced 2026-02-07 11:10:44 +00:00
scoutfs: don't livelock conflicting waiters
If there are two tasks waiting for conflicting modes, say a writer waiting for a CW index lock and a index walker waiting for a PR index lock, they can livelock. In the ast one of their modes will be granted. We'll wake them under the lock now that they can see that their mode is ready. But then while still under the lock we see a conflicting waiter, and no users, so we immediately start converting the lock away to the other waiting conflicting mode. The woken waiter is scheduled but now sees that the lock isn't granted anymore because it's converting. This bounces back and forth forever. The fix is to refuse to start conversion while there are still waiters for the currently granted mode. Once they finish it'll be able to convert. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -405,10 +405,10 @@ static void lock_process(struct lock_info *linfo, struct scoutfs_lock *lock)
|
||||
|
||||
/*
|
||||
* Convert on behalf of waiters who aren't satisfied by the
|
||||
* current mode when it won't conflict with users or a pending
|
||||
* bast conversion. The new mode may or may not match the
|
||||
* current granted mode so we may or may not need to block users
|
||||
* during the transition.
|
||||
* current mode when it won't conflict with specific waiters,
|
||||
* matching users, or pending bast conversions. The new mode
|
||||
* may or may not match the current granted mode so we may or
|
||||
* may not need to block users during the transition.
|
||||
*
|
||||
* Remember that the presence of waiters doesn't necessarily
|
||||
* mean that they're blocked. Multiple lock attempts naturally
|
||||
@@ -418,6 +418,8 @@ static void lock_process(struct lock_info *linfo, struct scoutfs_lock *lock)
|
||||
for (mode = 0; mode < SCOUTFS_LOCK_NR_MODES; mode++) {
|
||||
if (lock->work_mode < 0 &&
|
||||
lock->waiters[mode] &&
|
||||
(lock->granted_mode < 0 ||
|
||||
!lock->waiters[lock->granted_mode]) &&
|
||||
!lock_modes_match(lock->granted_mode, mode) &&
|
||||
lock_counts_match(mode, lock->users) &&
|
||||
(lock->bast_mode < 0 ||
|
||||
|
||||
Reference in New Issue
Block a user