1 From 7ada876a8703f23befbb20a7465a702ee39b1704 Mon Sep 17 00:00:00 2001
2 From: Darren Hart <dvhart@linux.intel.com>
3 Date: Sun, 17 Oct 2010 08:35:04 -0700
4 Subject: futex: Fix errors in nested key ref-counting
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
9 From: Darren Hart <dvhart@linux.intel.com>
11 commit 7ada876a8703f23befbb20a7465a702ee39b1704 upstream.
13 futex_wait() is leaking key references due to futex_wait_setup()
14 acquiring an additional reference via the queue_lock() routine. The
15 nested key ref-counting has been masking bugs and complicating code
16 analysis. queue_lock() is only called with a previously ref-counted
17 key, so remove the additional ref-counting from the queue_(un)lock()
20 Also futex_wait_requeue_pi() drops one key reference too many in
21 unqueue_me_pi(). Remove the key reference handling from
22 unqueue_me_pi(). This was paired with a queue_lock() in
23 futex_lock_pi(), so the count remains unchanged.
25 Document remaining nested key ref-counting sites.
27 Signed-off-by: Darren Hart <dvhart@linux.intel.com>
28 Reported-and-tested-by: Matthieu Fertré<matthieu.fertre@kerlabs.com>
29 Reported-by: Louis Rilling<louis.rilling@kerlabs.com>
30 Cc: Peter Zijlstra <peterz@infradead.org>
31 Cc: Eric Dumazet <eric.dumazet@gmail.com>
32 Cc: John Kacur <jkacur@redhat.com>
33 Cc: Rusty Russell <rusty@rustcorp.com.au>
34 LKML-Reference: <4CBB17A8.70401@linux.intel.com>
35 Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
36 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
39 kernel/futex.c | 31 ++++++++++++++++---------------
40 1 file changed, 16 insertions(+), 15 deletions(-)
44 @@ -1363,7 +1363,6 @@ static inline struct futex_hash_bucket *
46 struct futex_hash_bucket *hb;
48 - get_futex_key_refs(&q->key);
49 hb = hash_futex(&q->key);
50 q->lock_ptr = &hb->lock;
52 @@ -1375,7 +1374,6 @@ static inline void
53 queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb)
55 spin_unlock(&hb->lock);
56 - drop_futex_key_refs(&q->key);
60 @@ -1480,8 +1478,6 @@ static void unqueue_me_pi(struct futex_q
63 spin_unlock(q->lock_ptr);
65 - drop_futex_key_refs(&q->key);
69 @@ -1812,7 +1808,10 @@ static int futex_wait(u32 __user *uaddr,
73 - /* Prepare to wait on uaddr. */
75 + * Prepare to wait on uaddr. On success, holds hb lock and increments
78 ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
81 @@ -1822,24 +1821,23 @@ retry:
83 /* If we were woken (and unqueued), we succeeded, whatever. */
85 + /* unqueue_me() drops q.key ref */
95 * We expect signal_pending(current), but we might be the
96 * victim of a spurious wakeup as well.
98 - if (!signal_pending(current)) {
99 - put_futex_key(fshared, &q.key);
100 + if (!signal_pending(current))
109 restart = ¤t_thread_info()->restart_block;
110 restart->fn = futex_wait_restart;
111 @@ -1856,8 +1854,6 @@ retry:
113 ret = -ERESTART_RESTARTBLOCK;
116 - put_futex_key(fshared, &q.key);
119 hrtimer_cancel(&to->timer);
120 @@ -2236,7 +2232,10 @@ static int futex_wait_requeue_pi(u32 __u
121 q.rt_waiter = &rt_waiter;
122 q.requeue_pi_key = &key2;
124 - /* Prepare to wait on uaddr. */
126 + * Prepare to wait on uaddr. On success, increments q.key (key1) ref
129 ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
132 @@ -2254,7 +2253,9 @@ static int futex_wait_requeue_pi(u32 __u
133 * In order for us to be here, we know our q.key == key2, and since
134 * we took the hb->lock above, we also know that futex_requeue() has
135 * completed and we no longer have to concern ourselves with a wakeup
136 - * race with the atomic proxy lock acquition by the requeue code.
137 + * race with the atomic proxy lock acquisition by the requeue code. The
138 + * futex_requeue dropped our key1 reference and incremented our key2
142 /* Check if the requeue code acquired the second futex for us. */