futex: Plug a pi_state leak and clarify the refcounting
cover futex: Plug a pi_state leak and clarify the refcounting
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
PATCH 1/5 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.
--- kernel/futex.c | 5 +++++ 1 file changed, 5 insertions(+)
kernel/futex.c +5 -0
@@ -2755,6 +2755,11 @@ static int futex_wait_requeue_pi(u32 __uif (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 {
tip-bot for Thomas Gleixner
merge bot[tip:locking/core] futex: Drop refcount if requeue_pi() acquired the rtmutex
futex: Drop refcount if requeue_pi() acquired the rtmutex
Commit-ID: fb75a4282d0d9a3c7c44d940582c2d226cf3acfb Gitweb: http://git.kernel.org/tip/fb75a4282d0d9a3c7c44d940582c2d226cf3acfb Author: Thomas Gleixner <[email protected]> AuthorDate: Sat, 19 Dec 2015 20:07:38 +0000 Committer: Thomas Gleixner <[email protected]> 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.
--- kernel/futex.c | 5 +++++ 1 file changed, 5 insertions(+)
kernel/futex.c +5 -0
@@ -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 {
PATCH 2/5 futex: Rename free_pi_state() to put_pi_state()
In reply to Thomas Gleixnerfree_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.
--- kernel/futex.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
kernel/futex.c +10 -7
@@ -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 *uadcase 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 {
tip-bot for Thomas Gleixner
merge bot[tip:locking/core] futex: Rename free_pi_state() to put_pi_state( )
futex: Rename free_pi_state() to put_pi_state()
Commit-ID: 29e9ee5d48c35d6cf8afe09bdf03f77125c9ac11 Gitweb: http://git.kernel.org/tip/29e9ee5d48c35d6cf8afe09bdf03f77125c9ac11 Author: Thomas Gleixner <[email protected]> AuthorDate: Sat, 19 Dec 2015 20:07:39 +0000 Committer: Thomas Gleixner <[email protected]> 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.
--- kernel/futex.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
kernel/futex.c +10 -7
@@ -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 {
PATCH 3/5 futex: Document pi_state refcounting in requeue code
In reply to Thomas GleixnerDocumentation of the pi_state refcounting in the requeue code is non existent. Add it.
--- kernel/futex.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-)
kernel/futex.c +33 -3
@@ -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);
Re: [patch 3/5] futex: Document pi_state refcounting in requeue code
Quoted 3 lines · Thomas Gleixner
Documentation of the
pi_staterefcounting 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?
Quoted 7 lines
Signed-off-by Thomas Gleixner <[email protected]>--- kernel/futex.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-)kernel/futex.c +0
-0
...
Quoted 13 lines
kernel/futex.c +8
-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) {
kernel/futex.c static int futex_requeue(u32 __user *uad · line 1844
Quoted 10 lines
kernel/futex.c +9
-1-/* -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 ^
Signature · 2 lines
Darren Hart Intel Open Source Technology Center
tip-bot for Thomas Gleixner
merge bot[tip:locking/core] futex: Document pi_state refcounting in requeue code
In reply to Thomas Gleixnerfutex: Document pi_state refcounting in requeue code
Commit-ID: ecb38b78f698a51988ec456751b20440e54702fb Gitweb: http://git.kernel.org/tip/ecb38b78f698a51988ec456751b20440e54702fb Author: Thomas Gleixner <[email protected]> AuthorDate: Sat, 19 Dec 2015 20:07:39 +0000 Committer: Thomas Gleixner <[email protected]> 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.
--- kernel/futex.c | 51 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 12 deletions(-)
kernel/futex.c +39 -12
@@ -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);
PATCH 4/5 futex: Remove pointless put_pi_state calls in requeue()
In reply to Thomas GleixnerIn the error handling cases we neither have pi_state nor a reference to it. Remove the pointless code.
--- kernel/futex.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
kernel/futex.c +2 -4
@@ -1737,9 +1737,9 @@ static int futex_requeue(u32 __user *uadcase 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);
tip-bot for Thomas Gleixner
merge bot[tip:locking/core] futex: Remove pointless put_pi_state calls in requeue()
futex: Remove pointless put_pi_state calls in requeue()
Commit-ID: 4959f2de11ca532a120a337429e5576fd283700f Gitweb: http://git.kernel.org/tip/4959f2de11ca532a120a337429e5576fd283700f Author: Thomas Gleixner <[email protected]> AuthorDate: Sat, 19 Dec 2015 20:07:40 +0000 Committer: Thomas Gleixner <[email protected]> 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.
--- kernel/futex.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
kernel/futex.c +2 -4
@@ -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);
PATCH 5/5 futex: Cleanup the goto confusion in requeue_pi()
In reply to Thomas Gleixnerout_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.
--- kernel/futex.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
kernel/futex.c +3 -2
@@ -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);
Re: [patch 5/5] futex: Cleanup the goto confusion in requeue_pi()
Quoted 27 lines · Thomas Gleixner
out_unlock: does not only drop the locks, it also drops the refcount on thepi_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 <[email protected]>--- kernel/futex.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)kernel/futex.c +1
-2@@ -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:/*
kernel/futex.c static int futex_requeue(u32 __user *uad · line 1862
Quoted 10 lines
kernel/futex.c +2
-0* 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:
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,
Signature · 2 lines
Darren Hart Intel Open Source Technology Center
Re: [patch 5/5] futex: Cleanup the goto confusion in requeue_pi()
Quoted 3 lines · Darren Hart
As a follow-on, I think it might be worthwhile to create a symmetrical
get_pi_state()to theput_pi_state(), rather than handling theatomic_incdirectly.
Ditto, immediate thought was future auditors will look for it.
-Mike
Re: [patch 5/5] futex: Cleanup the goto confusion in requeue_pi()
Quoted 7 lines · Mike Galbraith
Quoted 3 lines · Darren Hart
As a follow-on, I think it might be worthwhile to create a symmetrical
get_pi_state()to theput_pi_state(), rather than handling theatomic_incdirectly.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):
Quoted 1 line
From
2d4cce06d36b16dcd038d7a68a6efc7740848ee1Mon Sep 17 00:00:00 2001
Message-Id: <2d4cce06d36b16dcd038d7a68a6efc7740848ee1.1450596757.git.dvhart@linux.intel.com>
From: Darren Hart <[email protected]>
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().
--- kernel/futex.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
kernel/futex.c +13 -5
@@ -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,
Signature · 6 lines
2.1.4 -- Darren Hart Intel Open Source Technology Center
Re: [patch 5/5] futex: Cleanup the goto confusion in requeue_pi()
In reply to Darren HartQuoted 9 lines · Darren Hart
As a follow-on, I think it might be worthwhile to create a symmetrical
get_pi_state()to theput_pi_state(), rather than handling theatomic_incdirectly.And finally, while the break; in
futex_requeueworks, that function is quite long and an explicitout_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,
Signature · 2 lines
Darren Hart Intel Open Source Technology Center
tip-bot for Thomas Gleixner
merge bot[tip:locking/core] futex: Cleanup the goto confusion in requeue_pi()
In reply to Thomas Gleixnerfutex: Cleanup the goto confusion in requeue_pi()
Commit-ID: 885c2cb770b5ac2507c41bc9f91a5d1c98337bee Gitweb: http://git.kernel.org/tip/885c2cb770b5ac2507c41bc9f91a5d1c98337bee Author: Thomas Gleixner <[email protected]> AuthorDate: Sat, 19 Dec 2015 20:07:41 +0000 Committer: Thomas Gleixner <[email protected]> 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.
--- kernel/futex.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
kernel/futex.c +7 -2
@@ -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);