locking/mutex: clear MUTEX_FLAGS if wait_list is empty due to signal
[ Upstream commit 3a010c493271f04578b133de977e0e5dd2848cea ]
When a interruptible mutex locker is interrupted by a signal
without acquiring this lock and removed from the wait queue.
if the mutex isn't contended enough to have a waiter
put into the wait queue again, the setting of the WAITER
bit will force mutex locker to go into the slowpath to
acquire the lock every time, so if the wait queue is empty,
the WAITER bit need to be clear.
Fixes: 040a0a3710
("mutex: Add support for wound/wait style locks")
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Zqiang <qiang.zhang@windriver.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20210517034005.30828-1-qiang.zhang@windriver.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
5dfed1be0e
commit
e354e3744b
@@ -204,7 +204,7 @@ static inline bool __mutex_waiter_is_first(struct mutex *lock, struct mutex_wait
|
||||
* Add @waiter to a given location in the lock wait_list and set the
|
||||
* FLAG_WAITERS flag if it's the first waiter.
|
||||
*/
|
||||
static void __sched
|
||||
static void
|
||||
__mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter,
|
||||
struct list_head *list)
|
||||
{
|
||||
@@ -215,6 +215,16 @@ __mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter,
|
||||
__mutex_set_flag(lock, MUTEX_FLAG_WAITERS);
|
||||
}
|
||||
|
||||
static void
|
||||
__mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter)
|
||||
{
|
||||
list_del(&waiter->list);
|
||||
if (likely(list_empty(&lock->wait_list)))
|
||||
__mutex_clear_flag(lock, MUTEX_FLAGS);
|
||||
|
||||
debug_mutex_remove_waiter(lock, waiter, current);
|
||||
}
|
||||
|
||||
/*
|
||||
* Give up ownership to a specific task, when @task = NULL, this is equivalent
|
||||
* to a regular unlock. Sets PICKUP on a handoff, clears HANDOF, preserves
|
||||
@@ -1071,9 +1081,7 @@ acquired:
|
||||
__ww_mutex_check_waiters(lock, ww_ctx);
|
||||
}
|
||||
|
||||
mutex_remove_waiter(lock, &waiter, current);
|
||||
if (likely(list_empty(&lock->wait_list)))
|
||||
__mutex_clear_flag(lock, MUTEX_FLAGS);
|
||||
__mutex_remove_waiter(lock, &waiter);
|
||||
|
||||
debug_mutex_free_waiter(&waiter);
|
||||
|
||||
@@ -1090,7 +1098,7 @@ skip_wait:
|
||||
|
||||
err:
|
||||
__set_current_state(TASK_RUNNING);
|
||||
mutex_remove_waiter(lock, &waiter, current);
|
||||
__mutex_remove_waiter(lock, &waiter);
|
||||
err_early_kill:
|
||||
spin_unlock(&lock->wait_lock);
|
||||
debug_mutex_free_waiter(&waiter);
|
||||
|
Reference in New Issue
Block a user