aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/futex.c
diff options
context:
space:
mode:
authorDarren Hart <dvhart@linux.intel.com>2010-10-17 11:35:04 -0400
committerThomas Gleixner <tglx@linutronix.de>2010-10-19 05:41:54 -0400
commit7ada876a8703f23befbb20a7465a702ee39b1704 (patch)
treeadee9cf8676fed56a0a6ad1d270ae5fb84d32553 /kernel/futex.c
parent2b666ca4a68cbc22483b0f2e1ba3c0e59b01ae9e (diff)
futex: Fix errors in nested key ref-counting
futex_wait() is leaking key references due to futex_wait_setup() acquiring an additional reference via the queue_lock() routine. The nested key ref-counting has been masking bugs and complicating code analysis. queue_lock() is only called with a previously ref-counted key, so remove the additional ref-counting from the queue_(un)lock() functions. Also futex_wait_requeue_pi() drops one key reference too many in unqueue_me_pi(). Remove the key reference handling from unqueue_me_pi(). This was paired with a queue_lock() in futex_lock_pi(), so the count remains unchanged. Document remaining nested key ref-counting sites. Signed-off-by: Darren Hart <dvhart@linux.intel.com> Reported-and-tested-by: Matthieu Fertré<matthieu.fertre@kerlabs.com> Reported-by: Louis Rilling<louis.rilling@kerlabs.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: John Kacur <jkacur@redhat.com> Cc: Rusty Russell <rusty@rustcorp.com.au> LKML-Reference: <4CBB17A8.70401@linux.intel.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: stable@kernel.org
Diffstat (limited to 'kernel/futex.c')
-rw-r--r--kernel/futex.c31
1 files changed, 16 insertions, 15 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index 6a3a5fa1526d..e328f574c97c 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1363,7 +1363,6 @@ static inline struct futex_hash_bucket *queue_lock(struct futex_q *q)
1363{ 1363{
1364 struct futex_hash_bucket *hb; 1364 struct futex_hash_bucket *hb;
1365 1365
1366 get_futex_key_refs(&q->key);
1367 hb = hash_futex(&q->key); 1366 hb = hash_futex(&q->key);
1368 q->lock_ptr = &hb->lock; 1367 q->lock_ptr = &hb->lock;
1369 1368
@@ -1375,7 +1374,6 @@ static inline void
1375queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb) 1374queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb)
1376{ 1375{
1377 spin_unlock(&hb->lock); 1376 spin_unlock(&hb->lock);
1378 drop_futex_key_refs(&q->key);
1379} 1377}
1380 1378
1381/** 1379/**
@@ -1480,8 +1478,6 @@ static void unqueue_me_pi(struct futex_q *q)
1480 q->pi_state = NULL; 1478 q->pi_state = NULL;
1481 1479
1482 spin_unlock(q->lock_ptr); 1480 spin_unlock(q->lock_ptr);
1483
1484 drop_futex_key_refs(&q->key);
1485} 1481}
1486 1482
1487/* 1483/*
@@ -1812,7 +1808,10 @@ static int futex_wait(u32 __user *uaddr, int fshared,
1812 } 1808 }
1813 1809
1814retry: 1810retry:
1815 /* Prepare to wait on uaddr. */ 1811 /*
1812 * Prepare to wait on uaddr. On success, holds hb lock and increments
1813 * q.key refs.
1814 */
1816 ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); 1815 ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
1817 if (ret) 1816 if (ret)
1818 goto out; 1817 goto out;
@@ -1822,24 +1821,23 @@ retry:
1822 1821
1823 /* If we were woken (and unqueued), we succeeded, whatever. */ 1822 /* If we were woken (and unqueued), we succeeded, whatever. */
1824 ret = 0; 1823 ret = 0;
1824 /* unqueue_me() drops q.key ref */
1825 if (!unqueue_me(&q)) 1825 if (!unqueue_me(&q))
1826 goto out_put_key; 1826 goto out;
1827 ret = -ETIMEDOUT; 1827 ret = -ETIMEDOUT;
1828 if (to && !to->task) 1828 if (to && !to->task)
1829 goto out_put_key; 1829 goto out;
1830 1830
1831 /* 1831 /*
1832 * We expect signal_pending(current), but we might be the 1832 * We expect signal_pending(current), but we might be the
1833 * victim of a spurious wakeup as well. 1833 * victim of a spurious wakeup as well.
1834 */ 1834 */
1835 if (!signal_pending(current)) { 1835 if (!signal_pending(current))
1836 put_futex_key(fshared, &q.key);
1837 goto retry; 1836 goto retry;
1838 }
1839 1837
1840 ret = -ERESTARTSYS; 1838 ret = -ERESTARTSYS;
1841 if (!abs_time) 1839 if (!abs_time)
1842 goto out_put_key; 1840 goto out;
1843 1841
1844 restart = &current_thread_info()->restart_block; 1842 restart = &current_thread_info()->restart_block;
1845 restart->fn = futex_wait_restart; 1843 restart->fn = futex_wait_restart;
@@ -1856,8 +1854,6 @@ retry:
1856 1854
1857 ret = -ERESTART_RESTARTBLOCK; 1855 ret = -ERESTART_RESTARTBLOCK;
1858 1856
1859out_put_key:
1860 put_futex_key(fshared, &q.key);
1861out: 1857out:
1862 if (to) { 1858 if (to) {
1863 hrtimer_cancel(&to->timer); 1859 hrtimer_cancel(&to->timer);
@@ -2236,7 +2232,10 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
2236 q.rt_waiter = &rt_waiter; 2232 q.rt_waiter = &rt_waiter;
2237 q.requeue_pi_key = &key2; 2233 q.requeue_pi_key = &key2;
2238 2234
2239 /* Prepare to wait on uaddr. */ 2235 /*
2236 * Prepare to wait on uaddr. On success, increments q.key (key1) ref
2237 * count.
2238 */
2240 ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); 2239 ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
2241 if (ret) 2240 if (ret)
2242 goto out_key2; 2241 goto out_key2;
@@ -2254,7 +2253,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
2254 * In order for us to be here, we know our q.key == key2, and since 2253 * In order for us to be here, we know our q.key == key2, and since
2255 * we took the hb->lock above, we also know that futex_requeue() has 2254 * we took the hb->lock above, we also know that futex_requeue() has
2256 * completed and we no longer have to concern ourselves with a wakeup 2255 * completed and we no longer have to concern ourselves with a wakeup
2257 * race with the atomic proxy lock acquition by the requeue code. 2256 * race with the atomic proxy lock acquisition by the requeue code. The
2257 * futex_requeue dropped our key1 reference and incremented our key2
2258 * reference count.
2258 */ 2259 */
2259 2260
2260 /* Check if the requeue code acquired the second futex for us. */ 2261 /* Check if the requeue code acquired the second futex for us. */