locking fixes
Subsystems (3)
Linus,
Please pull the latest locking-urgent-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking-urgent-for-linus
# HEAD: fba7cd681b6155e2d93e7862fcd6f970336b83c3 asm-generic/futex: Re-enable preemption in futex_atomic_cmpxchg_inatomic()
Misc fixes:
- pvqspinlocks: an instrumentation fix
- futexes: a preempt-count vs. pagefault_disable decouple corner case fix
- futexes: futex requeue plist race window fix
- futexes: a futex UNLOCK_PI transaction fix for a corner case
Thanks,
Ingo
------------------>
Davidlohr Bueso (2):
locking/pvqspinlock: Fix division by zero in qstat_read()
futex: Acknowledge a new waiter in counter before plist
Romain Perier (1):
asm-generic/futex: Re-enable preemption in futex_atomic_cmpxchg_inatomic()
Sebastian Andrzej Siewior (1):
futex: Handle unlock_pi race gracefully
include/asm-generic/futex.h | 8 ++++++-- kernel/futex.c | 27 +++++++++++++++++++++++---- kernel/locking/qspinlock_stat.h | 8 +++++--- 3 files changed, 34 insertions(+), 9 deletions(-)
include/asm-generic/futex.h +6 -2
@@ -108,11 +108,15 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,u32 val;preempt_disable (); -if (unlikely (get_user (val, uaddr) !=0 )) +if (unlikely (get_user (val, uaddr) !=0 )) { +preempt_enable ();return -EFAULT ; + } -if (val == oldval &&unlikely (put_user (newval, uaddr) !=0 )) +if (val == oldval &&unlikely (put_user (newval, uaddr) !=0 )) { +preempt_enable ();return -EFAULT ; + } *uval = val;preempt_enable ();
kernel/futex.c +23 -4
@@ -1295,10 +1295,20 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this,if (unlikely (should_fail_futex (true))) ret = -EFAULT ; -if (cmpxchg_futex_value_locked (&curval, uaddr, uval, newval)) +if (cmpxchg_futex_value_locked (&curval, uaddr, uval, newval)) { ret = -EFAULT ; -else if (curval != uval) - ret = -EINVAL ; + }else if (curval != uval) { +/* +* If a unconditional UNLOCK_PI operation (user space did not +* try the TID->0 transition) raced with a waiter setting the +* FUTEX_WAITERS flag between get_user() and locking the hash +* bucket lock, retry the operation. +*/ +if ((FUTEX_TID_MASK & curval) == uval) + ret = -EAGAIN ; +else + ret = -EINVAL ; + }if (ret) {raw_spin_unlock_irq (&pi_state->pi_mutex.wait_lock);return ret;
@@ -1525,8 +1535,8 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1,if (likely (&hb1->chain != &hb2->chain)) {plist_del (&q->list, &hb1->chain);hb_waiters_dec (hb1); -plist_add (&q->list, &hb2->chain);hb_waiters_inc (hb2); +plist_add (&q->list, &hb2->chain); q->lock_ptr = &hb2->lock; }get_futex_key_refs (key2);
@@ -2623,6 +2633,15 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)if (ret == -EFAULT ) goto pi_faulted;/* +* A unconditional UNLOCK_PI op raced against a waiter +* setting the FUTEX_WAITERS bit. Try again. +*/ +if (ret == -EAGAIN ) { +spin_unlock (&hb->lock); +put_futex_key (&key); + goto retry; + } +/* * wake_futex_pi has detected invalid state. Tell user * space. */
kernel/locking/qspinlock_stat.h +5 -3
@@ -136,10 +136,12 @@ static ssize_t qstat_read(struct file *file, char __user *user_buf, }if (counter == qstat_pv_hash_hops) { -u64 frac; +u64 frac =0 ; - frac =100ULL *do_div (stat, kicks); - frac =DIV_ROUND_CLOSEST_ULL (frac, kicks); +if (kicks) { + frac =100ULL *do_div (stat, kicks); + frac =DIV_ROUND_CLOSEST_ULL (frac, kicks); + }/* * Return a X.XX decimal number