* [patch 0/5] futex: Plug a pi_state leak and clarify the refcounting
@ 2015-12-19 20:07 Thomas Gleixner
2015-12-19 20:07 ` [patch 1/5] futex: Drop refcount if requeue_pi() acquired the rtmutex Thomas Gleixner
` (4 more replies)
0 siblings, 5 replies; 16+ messages in thread
From: Thomas Gleixner @ 2015-12-19 20:07 UTC (permalink / raw)
To: LKML
Cc: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Bhuvanesh_Surachari, Andy Lowe
A recent patch claimed that there is a double free in the requeue_pi
code, which is not the case.
While analysing the issue I found the contrary, i.e. a leak. This
series fixes the leak and clarifies the code so it's more clear how
that refcounting on the pi state works.
Thanks,
tglx
^ permalink raw reply [flat|nested] 16+ messages in thread* [patch 1/5] futex: Drop refcount if requeue_pi() acquired the rtmutex 2015-12-19 20:07 [patch 0/5] futex: Plug a pi_state leak and clarify the refcounting Thomas Gleixner @ 2015-12-19 20:07 ` Thomas Gleixner 2015-12-20 13:18 ` [tip:locking/core] " tip-bot for Thomas Gleixner 2015-12-19 20:07 ` [patch 2/5] futex: Rename free_pi_state() to put_pi_state() Thomas Gleixner ` (3 subsequent siblings) 4 siblings, 1 reply; 16+ messages in thread From: Thomas Gleixner @ 2015-12-19 20:07 UTC (permalink / raw) To: LKML Cc: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso, Bhuvanesh_Surachari, Andy Lowe [-- Attachment #1: futex--Drop-refcount-if-requeue_pi-acquired-the-rtmutex --] [-- Type: text/plain, Size: 810 bytes --] If the proxy lock in the requeue loop acquires the rtmutex for a waiter then it acquired also refcount on the pi_state related to the futex, but the waiter side does not drop the reference count. Add the missing free_pi_state() call. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: stable@vger.kernel.org --- kernel/futex.c | 5 +++++ 1 file changed, 5 insertions(+) --- a/kernel/futex.c +++ b/kernel/futex.c @@ -2755,6 +2755,11 @@ static int futex_wait_requeue_pi(u32 __u if (q.pi_state && (q.pi_state->owner != current)) { spin_lock(q.lock_ptr); ret = fixup_pi_state_owner(uaddr2, &q, current); + /* + * Drop the reference to the pi state which + * the requeue_pi() code acquired for us. + */ + free_pi_state(q.pi_state); spin_unlock(q.lock_ptr); } } else { ^ permalink raw reply [flat|nested] 16+ messages in thread
* [tip:locking/core] futex: Drop refcount if requeue_pi() acquired the rtmutex 2015-12-19 20:07 ` [patch 1/5] futex: Drop refcount if requeue_pi() acquired the rtmutex Thomas Gleixner @ 2015-12-20 13:18 ` tip-bot for Thomas Gleixner 0 siblings, 0 replies; 16+ messages in thread From: tip-bot for Thomas Gleixner @ 2015-12-20 13:18 UTC (permalink / raw) To: linux-tip-commits Cc: Andy_Lowe, tglx, hpa, linux-kernel, darren, dave, peterz, mingo Commit-ID: fb75a4282d0d9a3c7c44d940582c2d226cf3acfb Gitweb: http://git.kernel.org/tip/fb75a4282d0d9a3c7c44d940582c2d226cf3acfb Author: Thomas Gleixner <tglx@linutronix.de> AuthorDate: Sat, 19 Dec 2015 20:07:38 +0000 Committer: Thomas Gleixner <tglx@linutronix.de> CommitDate: Sun, 20 Dec 2015 12:43:24 +0100 futex: Drop refcount if requeue_pi() acquired the rtmutex If the proxy lock in the requeue loop acquires the rtmutex for a waiter then it acquired also refcount on the pi_state related to the futex, but the waiter side does not drop the reference count. Add the missing free_pi_state() call. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Darren Hart <darren@dvhart.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: Bhuvanesh_Surachari@mentor.com Cc: Andy Lowe <Andy_Lowe@mentor.com> Link: http://lkml.kernel.org/r/20151219200607.178132067@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: stable@vger.kernel.org --- kernel/futex.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/futex.c b/kernel/futex.c index 684d754..24fbc77 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -2755,6 +2755,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, if (q.pi_state && (q.pi_state->owner != current)) { spin_lock(q.lock_ptr); ret = fixup_pi_state_owner(uaddr2, &q, current); + /* + * Drop the reference to the pi state which + * the requeue_pi() code acquired for us. + */ + free_pi_state(q.pi_state); spin_unlock(q.lock_ptr); } } else { ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [patch 2/5] futex: Rename free_pi_state() to put_pi_state() 2015-12-19 20:07 [patch 0/5] futex: Plug a pi_state leak and clarify the refcounting Thomas Gleixner 2015-12-19 20:07 ` [patch 1/5] futex: Drop refcount if requeue_pi() acquired the rtmutex Thomas Gleixner @ 2015-12-19 20:07 ` Thomas Gleixner 2015-12-20 13:19 ` [tip:locking/core] futex: Rename free_pi_state() to put_pi_state( ) tip-bot for Thomas Gleixner 2015-12-19 20:07 ` [patch 3/5] futex: Document pi_state refcounting in requeue code Thomas Gleixner ` (2 subsequent siblings) 4 siblings, 1 reply; 16+ messages in thread From: Thomas Gleixner @ 2015-12-19 20:07 UTC (permalink / raw) To: LKML Cc: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso, Bhuvanesh_Surachari, Andy Lowe [-- Attachment #1: futex--Rename-free_pi_state-to-put_pi_state --] [-- Type: text/plain, Size: 2188 bytes --] free_pi_state() is confusing as it is in fact only freeing/caching the pi state when the last reference is gone. Rename it to put_pi_state() which reflects better what it is doing. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- kernel/futex.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) --- a/kernel/futex.c +++ b/kernel/futex.c @@ -725,9 +725,12 @@ static struct futex_pi_state * alloc_pi_ } /* + * Drops a reference to the pi_state object and frees or caches it + * when the last reference is gone. + * * Must be called with the hb lock held. */ -static void free_pi_state(struct futex_pi_state *pi_state) +static void put_pi_state(struct futex_pi_state *pi_state) { if (!pi_state) return; @@ -1729,7 +1732,7 @@ static int futex_requeue(u32 __user *uad case 0: break; case -EFAULT: - free_pi_state(pi_state); + put_pi_state(pi_state); pi_state = NULL; double_unlock_hb(hb1, hb2); hb_waiters_dec(hb2); @@ -1746,7 +1749,7 @@ static int futex_requeue(u32 __user *uad * exit to complete. * - The user space value changed. */ - free_pi_state(pi_state); + put_pi_state(pi_state); pi_state = NULL; double_unlock_hb(hb1, hb2); hb_waiters_dec(hb2); @@ -1815,7 +1818,7 @@ static int futex_requeue(u32 __user *uad } else if (ret) { /* -EDEADLK */ this->pi_state = NULL; - free_pi_state(pi_state); + put_pi_state(pi_state); goto out_unlock; } } @@ -1824,7 +1827,7 @@ static int futex_requeue(u32 __user *uad } out_unlock: - free_pi_state(pi_state); + put_pi_state(pi_state); double_unlock_hb(hb1, hb2); wake_up_q(&wake_q); hb_waiters_dec(hb2); @@ -1973,7 +1976,7 @@ static void unqueue_me_pi(struct futex_q __unqueue_futex(q); BUG_ON(!q->pi_state); - free_pi_state(q->pi_state); + put_pi_state(q->pi_state); q->pi_state = NULL; spin_unlock(q->lock_ptr); @@ -2759,7 +2762,7 @@ static int futex_wait_requeue_pi(u32 __u * Drop the reference to the pi state which * the requeue_pi() code acquired for us. */ - free_pi_state(q.pi_state); + put_pi_state(q.pi_state); spin_unlock(q.lock_ptr); } } else { ^ permalink raw reply [flat|nested] 16+ messages in thread
* [tip:locking/core] futex: Rename free_pi_state() to put_pi_state( ) 2015-12-19 20:07 ` [patch 2/5] futex: Rename free_pi_state() to put_pi_state() Thomas Gleixner @ 2015-12-20 13:19 ` tip-bot for Thomas Gleixner 0 siblings, 0 replies; 16+ messages in thread From: tip-bot for Thomas Gleixner @ 2015-12-20 13:19 UTC (permalink / raw) To: linux-tip-commits Cc: Andy_Lowe, linux-kernel, mingo, dave, darren, hpa, tglx, peterz Commit-ID: 29e9ee5d48c35d6cf8afe09bdf03f77125c9ac11 Gitweb: http://git.kernel.org/tip/29e9ee5d48c35d6cf8afe09bdf03f77125c9ac11 Author: Thomas Gleixner <tglx@linutronix.de> AuthorDate: Sat, 19 Dec 2015 20:07:39 +0000 Committer: Thomas Gleixner <tglx@linutronix.de> CommitDate: Sun, 20 Dec 2015 12:43:24 +0100 futex: Rename free_pi_state() to put_pi_state() free_pi_state() is confusing as it is in fact only freeing/caching the pi state when the last reference is gone. Rename it to put_pi_state() which reflects better what it is doing. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Darren Hart <darren@dvhart.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: Bhuvanesh_Surachari@mentor.com Cc: Andy Lowe <Andy_Lowe@mentor.com> Link: http://lkml.kernel.org/r/20151219200607.259636467@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- kernel/futex.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index 24fbc77..f1581ff 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -725,9 +725,12 @@ static struct futex_pi_state * alloc_pi_state(void) } /* + * Drops a reference to the pi_state object and frees or caches it + * when the last reference is gone. + * * Must be called with the hb lock held. */ -static void free_pi_state(struct futex_pi_state *pi_state) +static void put_pi_state(struct futex_pi_state *pi_state) { if (!pi_state) return; @@ -1729,7 +1732,7 @@ retry_private: case 0: break; case -EFAULT: - free_pi_state(pi_state); + put_pi_state(pi_state); pi_state = NULL; double_unlock_hb(hb1, hb2); hb_waiters_dec(hb2); @@ -1746,7 +1749,7 @@ retry_private: * exit to complete. * - The user space value changed. */ - free_pi_state(pi_state); + put_pi_state(pi_state); pi_state = NULL; double_unlock_hb(hb1, hb2); hb_waiters_dec(hb2); @@ -1815,7 +1818,7 @@ retry_private: } else if (ret) { /* -EDEADLK */ this->pi_state = NULL; - free_pi_state(pi_state); + put_pi_state(pi_state); goto out_unlock; } } @@ -1824,7 +1827,7 @@ retry_private: } out_unlock: - free_pi_state(pi_state); + put_pi_state(pi_state); double_unlock_hb(hb1, hb2); wake_up_q(&wake_q); hb_waiters_dec(hb2); @@ -1973,7 +1976,7 @@ static void unqueue_me_pi(struct futex_q *q) __unqueue_futex(q); BUG_ON(!q->pi_state); - free_pi_state(q->pi_state); + put_pi_state(q->pi_state); q->pi_state = NULL; spin_unlock(q->lock_ptr); @@ -2759,7 +2762,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, * Drop the reference to the pi state which * the requeue_pi() code acquired for us. */ - free_pi_state(q.pi_state); + put_pi_state(q.pi_state); spin_unlock(q.lock_ptr); } } else { ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [patch 3/5] futex: Document pi_state refcounting in requeue code 2015-12-19 20:07 [patch 0/5] futex: Plug a pi_state leak and clarify the refcounting Thomas Gleixner 2015-12-19 20:07 ` [patch 1/5] futex: Drop refcount if requeue_pi() acquired the rtmutex Thomas Gleixner 2015-12-19 20:07 ` [patch 2/5] futex: Rename free_pi_state() to put_pi_state() Thomas Gleixner @ 2015-12-19 20:07 ` Thomas Gleixner 2015-12-20 7:41 ` Darren Hart 2015-12-20 13:19 ` [tip:locking/core] " tip-bot for Thomas Gleixner 2015-12-19 20:07 ` [patch 4/5] futex: Remove pointless put_pi_state calls in requeue() Thomas Gleixner 2015-12-19 20:07 ` [patch 5/5] futex: Cleanup the goto confusion in requeue_pi() Thomas Gleixner 4 siblings, 2 replies; 16+ messages in thread From: Thomas Gleixner @ 2015-12-19 20:07 UTC (permalink / raw) To: LKML Cc: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso, Bhuvanesh_Surachari, Andy Lowe [-- Attachment #1: futex--Document-pi_state-refcounting-in-requeue-code --] [-- Type: text/plain, Size: 2859 bytes --] Documentation of the pi_state refcounting in the requeue code is non existent. Add it. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- kernel/futex.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1709,6 +1709,8 @@ static int futex_requeue(u32 __user *uad * exist yet, look it up one more time to ensure we have a * reference to it. If the lock was taken, ret contains the * vpid of the top waiter task. + * If the lock was not taken, we have pi_state and an initial + * refcount on it. In case of an error we have nothing. */ if (ret > 0) { WARN_ON(pi_state); @@ -1724,12 +1726,16 @@ static int futex_requeue(u32 __user *uad * it. So we rather use the known value than * rereading and handing potential crap to * lookup_pi_state. + * + * If that call succeeds then we have pi_state + * and an initial refcount on it. */ ret = lookup_pi_state(ret, hb2, &key2, &pi_state); } switch (ret) { case 0: + /* We hold a reference on the pi state. */ break; case -EFAULT: put_pi_state(pi_state); @@ -1804,19 +1810,38 @@ static int futex_requeue(u32 __user *uad * of requeue_pi if we couldn't acquire the lock atomically. */ if (requeue_pi) { - /* Prepare the waiter to take the rt_mutex. */ + /* + * Prepare the waiter to take the rt_mutex. Take a + * refcount on the pi_state and store the pointer in + * the futex_q object of the waiter. + */ atomic_inc(&pi_state->refcount); this->pi_state = pi_state; ret = rt_mutex_start_proxy_lock(&pi_state->pi_mutex, this->rt_waiter, this->task); if (ret == 1) { - /* We got the lock. */ + /* + * We got the lock. We do neither drop + * the refcount on pi_state nor clear + * this->pi_state because the waiter + * needs the pi_state for cleaning up + * the user space value. It will drop + * the refcount after doing so. + */ requeue_pi_wake_futex(this, &key2, hb2); drop_count++; continue; } else if (ret) { - /* -EDEADLK */ + /* + * rt_mutex_start_proxy_lock() + * detected a potential deadlock when + * we tried to queue that waiter. Drop + * the pi_state reference which we + * took above and remove the pointer + * to the state from the waiters + * futex_q object. + */ this->pi_state = NULL; put_pi_state(pi_state); goto out_unlock; @@ -1827,6 +1852,11 @@ static int futex_requeue(u32 __user *uad } out_unlock: + /* + * We took an extra initial reference to the pi_state either + * in futex_proxy_trylock_atomic() or in lookup_pi_state(). We + * need to drop it here again. + */ put_pi_state(pi_state); double_unlock_hb(hb1, hb2); wake_up_q(&wake_q); ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch 3/5] futex: Document pi_state refcounting in requeue code 2015-12-19 20:07 ` [patch 3/5] futex: Document pi_state refcounting in requeue code Thomas Gleixner @ 2015-12-20 7:41 ` Darren Hart 2015-12-20 13:19 ` [tip:locking/core] " tip-bot for Thomas Gleixner 1 sibling, 0 replies; 16+ messages in thread From: Darren Hart @ 2015-12-20 7:41 UTC (permalink / raw) To: Thomas Gleixner Cc: LKML, Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso, Bhuvanesh_Surachari, Andy Lowe On Sat, Dec 19, 2015 at 08:07:39PM -0000, Thomas Gleixner wrote: > Documentation of the pi_state refcounting in the requeue code is non > existent. Add it. > OK, one nitpic on this one I guess - 80 characters is pretty narrow as it is in my humble opinion, could we expand the newly added comment blocks to use all of the 80 character limit? > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > --- > kernel/futex.c | 36 +++++++++++++++++++++++++++++++++--- > 1 file changed, 33 insertions(+), 3 deletions(-) > > --- a/kernel/futex.c > +++ b/kernel/futex.c ... > - /* We got the lock. */ > + /* > + * We got the lock. We do neither drop > + * the refcount on pi_state nor clear > + * this->pi_state because the waiter > + * needs the pi_state for cleaning up > + * the user space value. It will drop > + * the refcount after doing so. > + */ > requeue_pi_wake_futex(this, &key2, hb2); > drop_count++; > continue; > } else if (ret) { > - /* -EDEADLK */ > + /* > + * rt_mutex_start_proxy_lock() > + * detected a potential deadlock when > + * we tried to queue that waiter. Drop > + * the pi_state reference which we > + * took above and remove the pointer > + * to the state from the waiters > + * futex_q object. > + */ Especially the two paragraphs above ^ -- Darren Hart Intel Open Source Technology Center ^ permalink raw reply [flat|nested] 16+ messages in thread
* [tip:locking/core] futex: Document pi_state refcounting in requeue code 2015-12-19 20:07 ` [patch 3/5] futex: Document pi_state refcounting in requeue code Thomas Gleixner 2015-12-20 7:41 ` Darren Hart @ 2015-12-20 13:19 ` tip-bot for Thomas Gleixner 1 sibling, 0 replies; 16+ messages in thread From: tip-bot for Thomas Gleixner @ 2015-12-20 13:19 UTC (permalink / raw) To: linux-tip-commits Cc: tglx, dave, linux-kernel, darren, Andy_Lowe, hpa, peterz, mingo Commit-ID: ecb38b78f698a51988ec456751b20440e54702fb Gitweb: http://git.kernel.org/tip/ecb38b78f698a51988ec456751b20440e54702fb Author: Thomas Gleixner <tglx@linutronix.de> AuthorDate: Sat, 19 Dec 2015 20:07:39 +0000 Committer: Thomas Gleixner <tglx@linutronix.de> CommitDate: Sun, 20 Dec 2015 12:43:24 +0100 futex: Document pi_state refcounting in requeue code Documentation of the pi_state refcounting in the requeue code is non existent. Add it. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Darren Hart <darren@dvhart.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: Bhuvanesh_Surachari@mentor.com Cc: Andy Lowe <Andy_Lowe@mentor.com> Link: http://lkml.kernel.org/r/20151219200607.335938312@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- kernel/futex.c | 51 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index f1581ff..20c4683 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1709,27 +1709,31 @@ retry_private: * exist yet, look it up one more time to ensure we have a * reference to it. If the lock was taken, ret contains the * vpid of the top waiter task. + * If the lock was not taken, we have pi_state and an initial + * refcount on it. In case of an error we have nothing. */ if (ret > 0) { WARN_ON(pi_state); drop_count++; task_count++; /* - * If we acquired the lock, then the user - * space value of uaddr2 should be vpid. It - * cannot be changed by the top waiter as it - * is blocked on hb2 lock if it tries to do - * so. If something fiddled with it behind our - * back the pi state lookup might unearth - * it. So we rather use the known value than - * rereading and handing potential crap to - * lookup_pi_state. + * If we acquired the lock, then the user space value + * of uaddr2 should be vpid. It cannot be changed by + * the top waiter as it is blocked on hb2 lock if it + * tries to do so. If something fiddled with it behind + * our back the pi state lookup might unearth it. So + * we rather use the known value than rereading and + * handing potential crap to lookup_pi_state. + * + * If that call succeeds then we have pi_state and an + * initial refcount on it. */ ret = lookup_pi_state(ret, hb2, &key2, &pi_state); } switch (ret) { case 0: + /* We hold a reference on the pi state. */ break; case -EFAULT: put_pi_state(pi_state); @@ -1804,19 +1808,37 @@ retry_private: * of requeue_pi if we couldn't acquire the lock atomically. */ if (requeue_pi) { - /* Prepare the waiter to take the rt_mutex. */ + /* + * Prepare the waiter to take the rt_mutex. Take a + * refcount on the pi_state and store the pointer in + * the futex_q object of the waiter. + */ atomic_inc(&pi_state->refcount); this->pi_state = pi_state; ret = rt_mutex_start_proxy_lock(&pi_state->pi_mutex, this->rt_waiter, this->task); if (ret == 1) { - /* We got the lock. */ + /* + * We got the lock. We do neither drop the + * refcount on pi_state nor clear + * this->pi_state because the waiter needs the + * pi_state for cleaning up the user space + * value. It will drop the refcount after + * doing so. + */ requeue_pi_wake_futex(this, &key2, hb2); drop_count++; continue; } else if (ret) { - /* -EDEADLK */ + /* + * rt_mutex_start_proxy_lock() detected a + * potential deadlock when we tried to queue + * that waiter. Drop the pi_state reference + * which we took above and remove the pointer + * to the state from the waiters futex_q + * object. + */ this->pi_state = NULL; put_pi_state(pi_state); goto out_unlock; @@ -1827,6 +1849,11 @@ retry_private: } out_unlock: + /* + * We took an extra initial reference to the pi_state either + * in futex_proxy_trylock_atomic() or in lookup_pi_state(). We + * need to drop it here again. + */ put_pi_state(pi_state); double_unlock_hb(hb1, hb2); wake_up_q(&wake_q); ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [patch 4/5] futex: Remove pointless put_pi_state calls in requeue() 2015-12-19 20:07 [patch 0/5] futex: Plug a pi_state leak and clarify the refcounting Thomas Gleixner ` (2 preceding siblings ...) 2015-12-19 20:07 ` [patch 3/5] futex: Document pi_state refcounting in requeue code Thomas Gleixner @ 2015-12-19 20:07 ` Thomas Gleixner 2015-12-20 13:19 ` [tip:locking/core] " tip-bot for Thomas Gleixner 2015-12-19 20:07 ` [patch 5/5] futex: Cleanup the goto confusion in requeue_pi() Thomas Gleixner 4 siblings, 1 reply; 16+ messages in thread From: Thomas Gleixner @ 2015-12-19 20:07 UTC (permalink / raw) To: LKML Cc: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso, Bhuvanesh_Surachari, Andy Lowe [-- Attachment #1: futex--Remove-pointless-free_pi_state-calls-in-requeue --] [-- Type: text/plain, Size: 889 bytes --] In the error handling cases we neither have pi_state nor a reference to it. Remove the pointless code. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- kernel/futex.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1737,9 +1737,9 @@ static int futex_requeue(u32 __user *uad case 0: /* We hold a reference on the pi state. */ break; + + /* If the above failed, then pi_state is NULL */ case -EFAULT: - put_pi_state(pi_state); - pi_state = NULL; double_unlock_hb(hb1, hb2); hb_waiters_dec(hb2); put_futex_key(&key2); @@ -1755,8 +1755,6 @@ static int futex_requeue(u32 __user *uad * exit to complete. * - The user space value changed. */ - put_pi_state(pi_state); - pi_state = NULL; double_unlock_hb(hb1, hb2); hb_waiters_dec(hb2); put_futex_key(&key2); ^ permalink raw reply [flat|nested] 16+ messages in thread
* [tip:locking/core] futex: Remove pointless put_pi_state calls in requeue() 2015-12-19 20:07 ` [patch 4/5] futex: Remove pointless put_pi_state calls in requeue() Thomas Gleixner @ 2015-12-20 13:19 ` tip-bot for Thomas Gleixner 0 siblings, 0 replies; 16+ messages in thread From: tip-bot for Thomas Gleixner @ 2015-12-20 13:19 UTC (permalink / raw) To: linux-tip-commits Cc: linux-kernel, dave, mingo, darren, Andy_Lowe, tglx, hpa, peterz Commit-ID: 4959f2de11ca532a120a337429e5576fd283700f Gitweb: http://git.kernel.org/tip/4959f2de11ca532a120a337429e5576fd283700f Author: Thomas Gleixner <tglx@linutronix.de> AuthorDate: Sat, 19 Dec 2015 20:07:40 +0000 Committer: Thomas Gleixner <tglx@linutronix.de> CommitDate: Sun, 20 Dec 2015 12:43:25 +0100 futex: Remove pointless put_pi_state calls in requeue() In the error handling cases we neither have pi_state nor a reference to it. Remove the pointless code. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Darren Hart <darren@dvhart.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: Bhuvanesh_Surachari@mentor.com Cc: Andy Lowe <Andy_Lowe@mentor.com> Link: http://lkml.kernel.org/r/20151219200607.432780944@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- kernel/futex.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index 20c4683..dcec018 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1735,9 +1735,9 @@ retry_private: case 0: /* We hold a reference on the pi state. */ break; + + /* If the above failed, then pi_state is NULL */ case -EFAULT: - put_pi_state(pi_state); - pi_state = NULL; double_unlock_hb(hb1, hb2); hb_waiters_dec(hb2); put_futex_key(&key2); @@ -1753,8 +1753,6 @@ retry_private: * exit to complete. * - The user space value changed. */ - put_pi_state(pi_state); - pi_state = NULL; double_unlock_hb(hb1, hb2); hb_waiters_dec(hb2); put_futex_key(&key2); ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [patch 5/5] futex: Cleanup the goto confusion in requeue_pi() 2015-12-19 20:07 [patch 0/5] futex: Plug a pi_state leak and clarify the refcounting Thomas Gleixner ` (3 preceding siblings ...) 2015-12-19 20:07 ` [patch 4/5] futex: Remove pointless put_pi_state calls in requeue() Thomas Gleixner @ 2015-12-19 20:07 ` Thomas Gleixner 2015-12-20 5:15 ` Darren Hart 2015-12-20 13:20 ` [tip:locking/core] " tip-bot for Thomas Gleixner 4 siblings, 2 replies; 16+ messages in thread From: Thomas Gleixner @ 2015-12-19 20:07 UTC (permalink / raw) To: LKML Cc: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso, Bhuvanesh_Surachari, Andy Lowe [-- Attachment #1: futex--Cleanup-goto-mess-in-requeue-pi --] [-- Type: text/plain, Size: 935 bytes --] out_unlock: does not only drop the locks, it also drops the refcount on the pi_state. Really intuitive. Move the label after the put_pi_state() call and use 'break' in the error handling path of the requeue loop. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- kernel/futex.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1842,20 +1842,21 @@ static int futex_requeue(u32 __user *uad */ this->pi_state = NULL; put_pi_state(pi_state); - goto out_unlock; + break; } } requeue_futex(this, hb1, hb2, &key2); drop_count++; } -out_unlock: /* * We took an extra initial reference to the pi_state either * in futex_proxy_trylock_atomic() or in lookup_pi_state(). We * need to drop it here again. */ put_pi_state(pi_state); + +out_unlock: double_unlock_hb(hb1, hb2); wake_up_q(&wake_q); hb_waiters_dec(hb2); ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch 5/5] futex: Cleanup the goto confusion in requeue_pi() 2015-12-19 20:07 ` [patch 5/5] futex: Cleanup the goto confusion in requeue_pi() Thomas Gleixner @ 2015-12-20 5:15 ` Darren Hart 2015-12-20 5:40 ` Mike Galbraith 2015-12-20 5:46 ` Darren Hart 2015-12-20 13:20 ` [tip:locking/core] " tip-bot for Thomas Gleixner 1 sibling, 2 replies; 16+ messages in thread From: Darren Hart @ 2015-12-20 5:15 UTC (permalink / raw) To: Thomas Gleixner Cc: LKML, Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso, Bhuvanesh_Surachari, Andy Lowe On Sat, Dec 19, 2015 at 08:07:41PM -0000, Thomas Gleixner wrote: > out_unlock: does not only drop the locks, it also drops the refcount > on the pi_state. Really intuitive. > > Move the label after the put_pi_state() call and use 'break' in the > error handling path of the requeue loop. > > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > --- > kernel/futex.c | 5 +++-- > 1 file changed, 3 insertions(+), 2 deletions(-) > > --- a/kernel/futex.c > +++ b/kernel/futex.c > @@ -1842,20 +1842,21 @@ static int futex_requeue(u32 __user *uad > */ > this->pi_state = NULL; > put_pi_state(pi_state); > - goto out_unlock; > + break; > } > } > requeue_futex(this, hb1, hb2, &key2); > drop_count++; > } > > -out_unlock: > /* > * We took an extra initial reference to the pi_state either > * in futex_proxy_trylock_atomic() or in lookup_pi_state(). We > * need to drop it here again. > */ > put_pi_state(pi_state); > + > +out_unlock: > double_unlock_hb(hb1, hb2); > wake_up_q(&wake_q); > hb_waiters_dec(hb2); Thanks for catching the leak Thomas, sorry I missed it :-/ I thought you missed one point early on shortly after retry_private: where we goto out_unlock, but we haven't claimed the pi_state yet - so this appears to have been another unnecessary (harmless) put_pi_state call previously. For the series: Reviewed-by: Darren Hart <dvhart@linux.intel.com> As a follow-on, I think it might be worthwhile to create a symmetrical get_pi_state() to the put_pi_state(), rather than handling the atomic_inc directly. And finally, while the break; in futex_requeue works, that function is quite long and an explicit out_put_pi_state: label would make the intention clear and also avoid inadvertently breaking the implicit behavior of the break. Thanks, -- Darren Hart Intel Open Source Technology Center ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch 5/5] futex: Cleanup the goto confusion in requeue_pi() 2015-12-20 5:15 ` Darren Hart @ 2015-12-20 5:40 ` Mike Galbraith 2015-12-20 7:37 ` Darren Hart 2015-12-20 5:46 ` Darren Hart 1 sibling, 1 reply; 16+ messages in thread From: Mike Galbraith @ 2015-12-20 5:40 UTC (permalink / raw) To: Darren Hart, Thomas Gleixner Cc: LKML, Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso, Bhuvanesh_Surachari, Andy Lowe On Sat, 2015-12-19 at 21:15 -0800, Darren Hart wrote: > As a follow-on, I think it might be worthwhile to create a symmetrical > get_pi_state() to the put_pi_state(), rather than handling the atomic_inc > directly. Ditto, immediate thought was future auditors will look for it. -Mike ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch 5/5] futex: Cleanup the goto confusion in requeue_pi() 2015-12-20 5:40 ` Mike Galbraith @ 2015-12-20 7:37 ` Darren Hart 0 siblings, 0 replies; 16+ messages in thread From: Darren Hart @ 2015-12-20 7:37 UTC (permalink / raw) To: Mike Galbraith Cc: Thomas Gleixner, LKML, Ingo Molnar, Peter Zijlstra, Davidlohr Bueso, Bhuvanesh_Surachari, Andy Lowe On Sun, Dec 20, 2015 at 06:40:07AM +0100, Mike Galbraith wrote: > On Sat, 2015-12-19 at 21:15 -0800, Darren Hart wrote: > > > As a follow-on, I think it might be worthwhile to create a symmetrical > > get_pi_state() to the put_pi_state(), rather than handling the atomic_inc > > directly. > > Ditto, immediate thought was future auditors will look for it. Hrm, well, I had just dismissed this after some digging, but OK, let's think it through a bit... Turns out there is only one open coded atomic_inc. the other occurs through attach_to_pi_state, sometimes via lookup_pi_state. We might be able to consolidate that some so it had a more symmetric and consistent usage pattern. A "get' in the futex op functions currently occurs via: 1) lookup_pi_state -> attach_to_pi_state() 2) attach_to_pi_state() (directly - nearly copying lookup_pi_state at the call site) 3) futex_lock_pi_atomic -> attach_to_pi_state() 4) atomic_inc(pi_state->ref_count) in futex_requeue_pi on behalf of the waiter in futex_wait_requeue_pi. Newly allocated or re-purposed pi_states get their refcount set to 1 which doesn't really count as a "get" until a lookup_pi_state or implicit acquisition through futex_lock_pi_atomic->attach_to_pi_state. As it turns out, lookup_pi_state is only used once in futex.c, but it really does make that section more readable. Despite an overall savings of a couple of lines, I think it's worth keeping, even if it adds another layer to the "get". As a further cleanup, Thomas removed the unnecessary calls to put_pi_state, and those that remain have no ambiguity about whether or not the pi_state is NULL. We *could* drop the NULL check in put_pi_state, which would make it's use all the more explicit. Perhaps a BUG_ON(!pi_state)? Not included below. The first get is still implicit in the way the caching of the pi_state works. This gets assigned with an existing refcount of 1 in attach_to_pi_owner from the cache via alloc_pi_state. I don't know if there is a reason for starting it off as 1 instead of 0. Perhaps we could make this more explicit by keeping it at 0 in the cache and using get_pi_state in alloc_pi_state before giving it to the waiter? Something like this perhaps? (Untested): >From 2d4cce06d36b16dcd038d7a68a6efc7740848ee1 Mon Sep 17 00:00:00 2001 Message-Id: <2d4cce06d36b16dcd038d7a68a6efc7740848ee1.1450596757.git.dvhart@linux.intel.com> From: Darren Hart <dvhart@linux.intel.com> Date: Sat, 19 Dec 2015 22:57:05 -0800 Subject: [PATCH] futex: Add a get_pi_state wrapper For audit purposes, add an inline wrapper, get_pi_state(), around atomic_inc(&pi_state->refcount) to parallel the newly renamed put_pi_state(). To make the get/set parallel and more explicit, keep the refcount at 0 while in the cache and only inc to 1 when it is allocated to a waiter via alloc_pi_state(). Signed-off-by: Darren Hart <dvhart@linux.intel.com> --- kernel/futex.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index ae83ea7..4c71c86 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -706,7 +706,7 @@ static int refill_pi_state_cache(void) INIT_LIST_HEAD(&pi_state->list); /* pi_mutex gets initialized later */ pi_state->owner = NULL; - atomic_set(&pi_state->refcount, 1); + atomic_set(&pi_state->refcount, 0); pi_state->key = FUTEX_KEY_INIT; current->pi_state_cache = pi_state; @@ -714,12 +714,21 @@ static int refill_pi_state_cache(void) return 0; } +/* + * Adds a reference to the pi_state object. + */ +static inline void get_pi_state(struct futex_pi_state *pi_state) +{ + atomic_inc(&pi_state->refcount); +} + static struct futex_pi_state * alloc_pi_state(void) { struct futex_pi_state *pi_state = current->pi_state_cache; WARN_ON(!pi_state); current->pi_state_cache = NULL; + get_pi_state(pi_state); return pi_state; } @@ -756,10 +765,9 @@ static void put_pi_state(struct futex_pi_state *pi_state) /* * pi_state->list is already empty. * clear pi_state->owner. - * refcount is at 0 - put it back to 1. + * refcount is already at 0. */ pi_state->owner = NULL; - atomic_set(&pi_state->refcount, 1); current->pi_state_cache = pi_state; } } @@ -954,7 +962,7 @@ static int attach_to_pi_state(u32 uval, struct futex_pi_state *pi_state, if (pid != task_pid_vnr(pi_state->owner)) return -EINVAL; out_state: - atomic_inc(&pi_state->refcount); + get_pi_state(pi_state); *ps = pi_state; return 0; } @@ -1813,7 +1821,7 @@ retry_private: * refcount on the pi_state and store the pointer in * the futex_q object of the waiter. */ - atomic_inc(&pi_state->refcount); + get_pi_state(pi_state); this->pi_state = pi_state; ret = rt_mutex_start_proxy_lock(&pi_state->pi_mutex, this->rt_waiter, -- 2.1.4 -- Darren Hart Intel Open Source Technology Center ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [patch 5/5] futex: Cleanup the goto confusion in requeue_pi() 2015-12-20 5:15 ` Darren Hart 2015-12-20 5:40 ` Mike Galbraith @ 2015-12-20 5:46 ` Darren Hart 1 sibling, 0 replies; 16+ messages in thread From: Darren Hart @ 2015-12-20 5:46 UTC (permalink / raw) To: Thomas Gleixner Cc: LKML, Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso, Bhuvanesh_Surachari, Andy Lowe On Sat, Dec 19, 2015 at 09:15:24PM -0800, Darren Hart wrote: > > As a follow-on, I think it might be worthwhile to create a symmetrical > get_pi_state() to the put_pi_state(), rather than handling the atomic_inc > directly. > > And finally, while the break; in futex_requeue works, that function is quite > long and an explicit out_put_pi_state: label would make the intention clear and > also avoid inadvertently breaking the implicit behavior of the break. > And while prototyping these changes, I've changed my mind, neither is a worthwhile change. The plist_for_each in futex_requeue really isn't that long and the breaks occur in a logical way and are now well documented with this series. An inadvertent change to this behavior seems unlikely. There is only one open coded atomic_inc in futex.c for the pi_state refcount, hardly worth a wrapper. Regards, -- Darren Hart Intel Open Source Technology Center ^ permalink raw reply [flat|nested] 16+ messages in thread
* [tip:locking/core] futex: Cleanup the goto confusion in requeue_pi() 2015-12-19 20:07 ` [patch 5/5] futex: Cleanup the goto confusion in requeue_pi() Thomas Gleixner 2015-12-20 5:15 ` Darren Hart @ 2015-12-20 13:20 ` tip-bot for Thomas Gleixner 1 sibling, 0 replies; 16+ messages in thread From: tip-bot for Thomas Gleixner @ 2015-12-20 13:20 UTC (permalink / raw) To: linux-tip-commits Cc: hpa, peterz, tglx, dave, Andy_Lowe, darren, mingo, linux-kernel Commit-ID: 885c2cb770b5ac2507c41bc9f91a5d1c98337bee Gitweb: http://git.kernel.org/tip/885c2cb770b5ac2507c41bc9f91a5d1c98337bee Author: Thomas Gleixner <tglx@linutronix.de> AuthorDate: Sat, 19 Dec 2015 20:07:41 +0000 Committer: Thomas Gleixner <tglx@linutronix.de> CommitDate: Sun, 20 Dec 2015 12:43:25 +0100 futex: Cleanup the goto confusion in requeue_pi() out_unlock: does not only drop the locks, it also drops the refcount on the pi_state. Really intuitive. Move the label after the put_pi_state() call and use 'break' in the error handling path of the requeue loop. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Darren Hart <darren@dvhart.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: Bhuvanesh_Surachari@mentor.com Cc: Andy Lowe <Andy_Lowe@mentor.com> Link: http://lkml.kernel.org/r/20151219200607.526665141@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- kernel/futex.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index dcec018..461d438 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1839,20 +1839,25 @@ retry_private: */ this->pi_state = NULL; put_pi_state(pi_state); - goto out_unlock; + /* + * We stop queueing more waiters and let user + * space deal with the mess. + */ + break; } } requeue_futex(this, hb1, hb2, &key2); drop_count++; } -out_unlock: /* * We took an extra initial reference to the pi_state either * in futex_proxy_trylock_atomic() or in lookup_pi_state(). We * need to drop it here again. */ put_pi_state(pi_state); + +out_unlock: double_unlock_hb(hb1, hb2); wake_up_q(&wake_q); hb_waiters_dec(hb2); ^ permalink raw reply related [flat|nested] 16+ messages in thread
end of thread, other threads:[~2015-12-20 13:20 UTC | newest] Thread overview: 16+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-12-19 20:07 [patch 0/5] futex: Plug a pi_state leak and clarify the refcounting Thomas Gleixner 2015-12-19 20:07 ` [patch 1/5] futex: Drop refcount if requeue_pi() acquired the rtmutex Thomas Gleixner 2015-12-20 13:18 ` [tip:locking/core] " tip-bot for Thomas Gleixner 2015-12-19 20:07 ` [patch 2/5] futex: Rename free_pi_state() to put_pi_state() Thomas Gleixner 2015-12-20 13:19 ` [tip:locking/core] futex: Rename free_pi_state() to put_pi_state( ) tip-bot for Thomas Gleixner 2015-12-19 20:07 ` [patch 3/5] futex: Document pi_state refcounting in requeue code Thomas Gleixner 2015-12-20 7:41 ` Darren Hart 2015-12-20 13:19 ` [tip:locking/core] " tip-bot for Thomas Gleixner 2015-12-19 20:07 ` [patch 4/5] futex: Remove pointless put_pi_state calls in requeue() Thomas Gleixner 2015-12-20 13:19 ` [tip:locking/core] " tip-bot for Thomas Gleixner 2015-12-19 20:07 ` [patch 5/5] futex: Cleanup the goto confusion in requeue_pi() Thomas Gleixner 2015-12-20 5:15 ` Darren Hart 2015-12-20 5:40 ` Mike Galbraith 2015-12-20 7:37 ` Darren Hart 2015-12-20 5:46 ` Darren Hart 2015-12-20 13:20 ` [tip:locking/core] " tip-bot for Thomas Gleixner
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox