diff options
Diffstat (limited to 'kernel/locking/mutex.c')
-rw-r--r-- | kernel/locking/mutex.c | 62 |
1 files changed, 33 insertions, 29 deletions
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index 454195194d4a..94674e5919cb 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c | |||
@@ -81,7 +81,7 @@ __visible void __sched __mutex_lock_slowpath(atomic_t *lock_count); | |||
81 | * The mutex must later on be released by the same task that | 81 | * The mutex must later on be released by the same task that |
82 | * acquired it. Recursive locking is not allowed. The task | 82 | * acquired it. Recursive locking is not allowed. The task |
83 | * may not exit without first unlocking the mutex. Also, kernel | 83 | * may not exit without first unlocking the mutex. Also, kernel |
84 | * memory where the mutex resides mutex must not be freed with | 84 | * memory where the mutex resides must not be freed with |
85 | * the mutex still locked. The mutex must first be initialized | 85 | * the mutex still locked. The mutex must first be initialized |
86 | * (or statically defined) before it can be locked. memset()-ing | 86 | * (or statically defined) before it can be locked. memset()-ing |
87 | * the mutex to 0 is not allowed. | 87 | * the mutex to 0 is not allowed. |
@@ -147,7 +147,7 @@ static __always_inline void ww_mutex_lock_acquired(struct ww_mutex *ww, | |||
147 | } | 147 | } |
148 | 148 | ||
149 | /* | 149 | /* |
150 | * after acquiring lock with fastpath or when we lost out in contested | 150 | * After acquiring lock with fastpath or when we lost out in contested |
151 | * slowpath, set ctx and wake up any waiters so they can recheck. | 151 | * slowpath, set ctx and wake up any waiters so they can recheck. |
152 | * | 152 | * |
153 | * This function is never called when CONFIG_DEBUG_LOCK_ALLOC is set, | 153 | * This function is never called when CONFIG_DEBUG_LOCK_ALLOC is set, |
@@ -191,19 +191,32 @@ ww_mutex_set_context_fastpath(struct ww_mutex *lock, | |||
191 | spin_unlock_mutex(&lock->base.wait_lock, flags); | 191 | spin_unlock_mutex(&lock->base.wait_lock, flags); |
192 | } | 192 | } |
193 | 193 | ||
194 | |||
195 | #ifdef CONFIG_MUTEX_SPIN_ON_OWNER | ||
196 | /* | 194 | /* |
197 | * In order to avoid a stampede of mutex spinners from acquiring the mutex | 195 | * After acquiring lock in the slowpath set ctx and wake up any |
198 | * more or less simultaneously, the spinners need to acquire a MCS lock | 196 | * waiters so they can recheck. |
199 | * first before spinning on the owner field. | ||
200 | * | 197 | * |
198 | * Callers must hold the mutex wait_lock. | ||
201 | */ | 199 | */ |
200 | static __always_inline void | ||
201 | ww_mutex_set_context_slowpath(struct ww_mutex *lock, | ||
202 | struct ww_acquire_ctx *ctx) | ||
203 | { | ||
204 | struct mutex_waiter *cur; | ||
202 | 205 | ||
203 | /* | 206 | ww_mutex_lock_acquired(lock, ctx); |
204 | * Mutex spinning code migrated from kernel/sched/core.c | 207 | lock->ctx = ctx; |
205 | */ | 208 | |
209 | /* | ||
210 | * Give any possible sleeping processes the chance to wake up, | ||
211 | * so they can recheck if they have to back off. | ||
212 | */ | ||
213 | list_for_each_entry(cur, &lock->base.wait_list, list) { | ||
214 | debug_mutex_wake_waiter(&lock->base, cur); | ||
215 | wake_up_process(cur->task); | ||
216 | } | ||
217 | } | ||
206 | 218 | ||
219 | #ifdef CONFIG_MUTEX_SPIN_ON_OWNER | ||
207 | static inline bool owner_running(struct mutex *lock, struct task_struct *owner) | 220 | static inline bool owner_running(struct mutex *lock, struct task_struct *owner) |
208 | { | 221 | { |
209 | if (lock->owner != owner) | 222 | if (lock->owner != owner) |
@@ -307,6 +320,11 @@ static bool mutex_optimistic_spin(struct mutex *lock, | |||
307 | if (!mutex_can_spin_on_owner(lock)) | 320 | if (!mutex_can_spin_on_owner(lock)) |
308 | goto done; | 321 | goto done; |
309 | 322 | ||
323 | /* | ||
324 | * In order to avoid a stampede of mutex spinners trying to | ||
325 | * acquire the mutex all at once, the spinners need to take a | ||
326 | * MCS (queued) lock first before spinning on the owner field. | ||
327 | */ | ||
310 | if (!osq_lock(&lock->osq)) | 328 | if (!osq_lock(&lock->osq)) |
311 | goto done; | 329 | goto done; |
312 | 330 | ||
@@ -469,7 +487,7 @@ void __sched ww_mutex_unlock(struct ww_mutex *lock) | |||
469 | EXPORT_SYMBOL(ww_mutex_unlock); | 487 | EXPORT_SYMBOL(ww_mutex_unlock); |
470 | 488 | ||
471 | static inline int __sched | 489 | static inline int __sched |
472 | __mutex_lock_check_stamp(struct mutex *lock, struct ww_acquire_ctx *ctx) | 490 | __ww_mutex_lock_check_stamp(struct mutex *lock, struct ww_acquire_ctx *ctx) |
473 | { | 491 | { |
474 | struct ww_mutex *ww = container_of(lock, struct ww_mutex, base); | 492 | struct ww_mutex *ww = container_of(lock, struct ww_mutex, base); |
475 | struct ww_acquire_ctx *hold_ctx = ACCESS_ONCE(ww->ctx); | 493 | struct ww_acquire_ctx *hold_ctx = ACCESS_ONCE(ww->ctx); |
@@ -557,7 +575,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, | |||
557 | } | 575 | } |
558 | 576 | ||
559 | if (use_ww_ctx && ww_ctx->acquired > 0) { | 577 | if (use_ww_ctx && ww_ctx->acquired > 0) { |
560 | ret = __mutex_lock_check_stamp(lock, ww_ctx); | 578 | ret = __ww_mutex_lock_check_stamp(lock, ww_ctx); |
561 | if (ret) | 579 | if (ret) |
562 | goto err; | 580 | goto err; |
563 | } | 581 | } |
@@ -569,6 +587,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, | |||
569 | schedule_preempt_disabled(); | 587 | schedule_preempt_disabled(); |
570 | spin_lock_mutex(&lock->wait_lock, flags); | 588 | spin_lock_mutex(&lock->wait_lock, flags); |
571 | } | 589 | } |
590 | __set_task_state(task, TASK_RUNNING); | ||
591 | |||
572 | mutex_remove_waiter(lock, &waiter, current_thread_info()); | 592 | mutex_remove_waiter(lock, &waiter, current_thread_info()); |
573 | /* set it to 0 if there are no waiters left: */ | 593 | /* set it to 0 if there are no waiters left: */ |
574 | if (likely(list_empty(&lock->wait_list))) | 594 | if (likely(list_empty(&lock->wait_list))) |
@@ -582,23 +602,7 @@ skip_wait: | |||
582 | 602 | ||
583 | if (use_ww_ctx) { | 603 | if (use_ww_ctx) { |
584 | struct ww_mutex *ww = container_of(lock, struct ww_mutex, base); | 604 | struct ww_mutex *ww = container_of(lock, struct ww_mutex, base); |
585 | struct mutex_waiter *cur; | 605 | ww_mutex_set_context_slowpath(ww, ww_ctx); |
586 | |||
587 | /* | ||
588 | * This branch gets optimized out for the common case, | ||
589 | * and is only important for ww_mutex_lock. | ||
590 | */ | ||
591 | ww_mutex_lock_acquired(ww, ww_ctx); | ||
592 | ww->ctx = ww_ctx; | ||
593 | |||
594 | /* | ||
595 | * Give any possible sleeping processes the chance to wake up, | ||
596 | * so they can recheck if they have to back off. | ||
597 | */ | ||
598 | list_for_each_entry(cur, &lock->wait_list, list) { | ||
599 | debug_mutex_wake_waiter(lock, cur); | ||
600 | wake_up_process(cur->task); | ||
601 | } | ||
602 | } | 606 | } |
603 | 607 | ||
604 | spin_unlock_mutex(&lock->wait_lock, flags); | 608 | spin_unlock_mutex(&lock->wait_lock, flags); |