Skip to content

Commit 3a010c4

Browse files
Zqiang1211Peter Zijlstra
authored andcommitted
locking/mutex: clear MUTEX_FLAGS if wait_list is empty due to signal
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: 040a0a3 ("mutex: Add support for wound/wait style locks") Suggested-by: Peter Zijlstra <[email protected]> Signed-off-by: Zqiang <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 89e70d5 commit 3a010c4

File tree

4 files changed

+17
-11
lines changed

4 files changed

+17
-11
lines changed

kernel/locking/mutex-debug.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,15 @@ void debug_mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter,
5757
task->blocked_on = waiter;
5858
}
5959

60-
void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter,
60+
void debug_mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter,
6161
struct task_struct *task)
6262
{
6363
DEBUG_LOCKS_WARN_ON(list_empty(&waiter->list));
6464
DEBUG_LOCKS_WARN_ON(waiter->task != task);
6565
DEBUG_LOCKS_WARN_ON(task->blocked_on != waiter);
6666
task->blocked_on = NULL;
6767

68-
list_del_init(&waiter->list);
68+
INIT_LIST_HEAD(&waiter->list);
6969
waiter->task = NULL;
7070
}
7171

kernel/locking/mutex-debug.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extern void debug_mutex_free_waiter(struct mutex_waiter *waiter);
2222
extern void debug_mutex_add_waiter(struct mutex *lock,
2323
struct mutex_waiter *waiter,
2424
struct task_struct *task);
25-
extern void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter,
25+
extern void debug_mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter,
2626
struct task_struct *task);
2727
extern void debug_mutex_unlock(struct mutex *lock);
2828
extern void debug_mutex_init(struct mutex *lock, const char *name,

kernel/locking/mutex.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ static inline bool __mutex_waiter_is_first(struct mutex *lock, struct mutex_wait
194194
* Add @waiter to a given location in the lock wait_list and set the
195195
* FLAG_WAITERS flag if it's the first waiter.
196196
*/
197-
static void __sched
197+
static void
198198
__mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter,
199199
struct list_head *list)
200200
{
@@ -205,6 +205,16 @@ __mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter,
205205
__mutex_set_flag(lock, MUTEX_FLAG_WAITERS);
206206
}
207207

208+
static void
209+
__mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter)
210+
{
211+
list_del(&waiter->list);
212+
if (likely(list_empty(&lock->wait_list)))
213+
__mutex_clear_flag(lock, MUTEX_FLAGS);
214+
215+
debug_mutex_remove_waiter(lock, waiter, current);
216+
}
217+
208218
/*
209219
* Give up ownership to a specific task, when @task = NULL, this is equivalent
210220
* to a regular unlock. Sets PICKUP on a handoff, clears HANDOFF, preserves
@@ -1061,9 +1071,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
10611071
__ww_mutex_check_waiters(lock, ww_ctx);
10621072
}
10631073

1064-
mutex_remove_waiter(lock, &waiter, current);
1065-
if (likely(list_empty(&lock->wait_list)))
1066-
__mutex_clear_flag(lock, MUTEX_FLAGS);
1074+
__mutex_remove_waiter(lock, &waiter);
10671075

10681076
debug_mutex_free_waiter(&waiter);
10691077

@@ -1080,7 +1088,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
10801088

10811089
err:
10821090
__set_current_state(TASK_RUNNING);
1083-
mutex_remove_waiter(lock, &waiter, current);
1091+
__mutex_remove_waiter(lock, &waiter);
10841092
err_early_kill:
10851093
spin_unlock(&lock->wait_lock);
10861094
debug_mutex_free_waiter(&waiter);

kernel/locking/mutex.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@
1010
* !CONFIG_DEBUG_MUTEXES case. Most of them are NOPs:
1111
*/
1212

13-
#define mutex_remove_waiter(lock, waiter, task) \
14-
__list_del((waiter)->list.prev, (waiter)->list.next)
15-
1613
#define debug_mutex_wake_waiter(lock, waiter) do { } while (0)
1714
#define debug_mutex_free_waiter(waiter) do { } while (0)
1815
#define debug_mutex_add_waiter(lock, waiter, ti) do { } while (0)
16+
#define debug_mutex_remove_waiter(lock, waiter, ti) do { } while (0)
1917
#define debug_mutex_unlock(lock) do { } while (0)
2018
#define debug_mutex_init(lock, name, key) do { } while (0)
2119

0 commit comments

Comments
 (0)