aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/futex.c
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2015-06-17 04:33:50 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-06-19 15:26:38 -0400
commit802ab58da74bb49ab348d2872190ef26ddc1a3e0 (patch)
treec62e2f4927ba283ddd5a8fd493c57fa7b9b2dbaf /kernel/futex.c
parent45ab4effc3bee6f8a5cb05652b7bb895ec5b6a7a (diff)
futex: Lower the lock contention on the HB lock during wake up
wake_futex_pi() wakes the task before releasing the hash bucket lock (HB). The first thing the woken up task usually does is to acquire the lock which requires the HB lock. On SMP Systems this leads to blocking on the HB lock which is released by the owner shortly after. This patch rearranges the unlock path by first releasing the HB lock and then waking up the task. [ tglx: Fixed up the rtmutex unlock path ] Originally-from: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Mike Galbraith <umgwanakikbuti@gmail.com> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Link: http://lkml.kernel.org/r/20150617083350.GA2433@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/futex.c')
-rw-r--r--kernel/futex.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index f9984c363e9a..a0cf6fa953de 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1117,11 +1117,14 @@ static void mark_wake_futex(struct wake_q_head *wake_q, struct futex_q *q)
1117 q->lock_ptr = NULL; 1117 q->lock_ptr = NULL;
1118} 1118}
1119 1119
1120static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) 1120static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this,
1121 struct futex_hash_bucket *hb)
1121{ 1122{
1122 struct task_struct *new_owner; 1123 struct task_struct *new_owner;
1123 struct futex_pi_state *pi_state = this->pi_state; 1124 struct futex_pi_state *pi_state = this->pi_state;
1124 u32 uninitialized_var(curval), newval; 1125 u32 uninitialized_var(curval), newval;
1126 WAKE_Q(wake_q);
1127 bool deboost;
1125 int ret = 0; 1128 int ret = 0;
1126 1129
1127 if (!pi_state) 1130 if (!pi_state)
@@ -1173,7 +1176,19 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
1173 raw_spin_unlock_irq(&new_owner->pi_lock); 1176 raw_spin_unlock_irq(&new_owner->pi_lock);
1174 1177
1175 raw_spin_unlock(&pi_state->pi_mutex.wait_lock); 1178 raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
1176 rt_mutex_unlock(&pi_state->pi_mutex); 1179
1180 deboost = rt_mutex_futex_unlock(&pi_state->pi_mutex, &wake_q);
1181
1182 /*
1183 * First unlock HB so the waiter does not spin on it once he got woken
1184 * up. Second wake up the waiter before the priority is adjusted. If we
1185 * deboost first (and lose our higher priority), then the task might get
1186 * scheduled away before the wake up can take place.
1187 */
1188 spin_unlock(&hb->lock);
1189 wake_up_q(&wake_q);
1190 if (deboost)
1191 rt_mutex_adjust_prio(current);
1177 1192
1178 return 0; 1193 return 0;
1179} 1194}
@@ -2413,13 +2428,23 @@ retry:
2413 */ 2428 */
2414 match = futex_top_waiter(hb, &key); 2429 match = futex_top_waiter(hb, &key);
2415 if (match) { 2430 if (match) {
2416 ret = wake_futex_pi(uaddr, uval, match); 2431 ret = wake_futex_pi(uaddr, uval, match, hb);
2432 /*
2433 * In case of success wake_futex_pi dropped the hash
2434 * bucket lock.
2435 */
2436 if (!ret)
2437 goto out_putkey;
2417 /* 2438 /*
2418 * The atomic access to the futex value generated a 2439 * The atomic access to the futex value generated a
2419 * pagefault, so retry the user-access and the wakeup: 2440 * pagefault, so retry the user-access and the wakeup:
2420 */ 2441 */
2421 if (ret == -EFAULT) 2442 if (ret == -EFAULT)
2422 goto pi_faulted; 2443 goto pi_faulted;
2444 /*
2445 * wake_futex_pi has detected invalid state. Tell user
2446 * space.
2447 */
2423 goto out_unlock; 2448 goto out_unlock;
2424 } 2449 }
2425 2450
@@ -2440,6 +2465,7 @@ retry:
2440 2465
2441out_unlock: 2466out_unlock:
2442 spin_unlock(&hb->lock); 2467 spin_unlock(&hb->lock);
2468out_putkey:
2443 put_futex_key(&key); 2469 put_futex_key(&key);
2444 return ret; 2470 return ret;
2445 2471