| Subject: futex: Provide and use pi_state_update_owner() |
| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Tue Jan 19 15:21:35 2021 +0100 |
| |
| From: Thomas Gleixner <tglx@linutronix.de> |
| |
| commit c5cade200ab9a2a3be9e7f32a752c8d86b502ec7 upstream |
| |
| Updating pi_state::owner is done at several places with the same |
| code. Provide a function for it and use that at the obvious places. |
| |
| This is also a preparation for a bug fix to avoid yet another copy of the |
| same code or alternatively introducing a completely unpenetratable mess of |
| gotos. |
| |
| Originally-by: Peter Zijlstra <peterz@infradead.org> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| kernel/futex.c | 66 ++++++++++++++++++++++++++++----------------------------- |
| 1 file changed, 33 insertions(+), 33 deletions(-) |
| |
| --- a/kernel/futex.c |
| +++ b/kernel/futex.c |
| @@ -857,6 +857,29 @@ static struct futex_pi_state *alloc_pi_s |
| return pi_state; |
| } |
| |
| +static void pi_state_update_owner(struct futex_pi_state *pi_state, |
| + struct task_struct *new_owner) |
| +{ |
| + struct task_struct *old_owner = pi_state->owner; |
| + |
| + lockdep_assert_held(&pi_state->pi_mutex.wait_lock); |
| + |
| + if (old_owner) { |
| + raw_spin_lock(&old_owner->pi_lock); |
| + WARN_ON(list_empty(&pi_state->list)); |
| + list_del_init(&pi_state->list); |
| + raw_spin_unlock(&old_owner->pi_lock); |
| + } |
| + |
| + if (new_owner) { |
| + raw_spin_lock(&new_owner->pi_lock); |
| + WARN_ON(!list_empty(&pi_state->list)); |
| + list_add(&pi_state->list, &new_owner->pi_state_list); |
| + pi_state->owner = new_owner; |
| + raw_spin_unlock(&new_owner->pi_lock); |
| + } |
| +} |
| + |
| static void get_pi_state(struct futex_pi_state *pi_state) |
| { |
| WARN_ON_ONCE(!refcount_inc_not_zero(&pi_state->refcount)); |
| @@ -1614,26 +1637,15 @@ static int wake_futex_pi(u32 __user *uad |
| ret = -EINVAL; |
| } |
| |
| - if (ret) |
| - goto out_unlock; |
| - |
| - /* |
| - * This is a point of no return; once we modify the uval there is no |
| - * going back and subsequent operations must not fail. |
| - */ |
| - |
| - raw_spin_lock(&pi_state->owner->pi_lock); |
| - WARN_ON(list_empty(&pi_state->list)); |
| - list_del_init(&pi_state->list); |
| - raw_spin_unlock(&pi_state->owner->pi_lock); |
| - |
| - raw_spin_lock(&new_owner->pi_lock); |
| - WARN_ON(!list_empty(&pi_state->list)); |
| - list_add(&pi_state->list, &new_owner->pi_state_list); |
| - pi_state->owner = new_owner; |
| - raw_spin_unlock(&new_owner->pi_lock); |
| - |
| - postunlock = __rt_mutex_futex_unlock(&pi_state->pi_mutex, &wake_q); |
| + if (!ret) { |
| + /* |
| + * This is a point of no return; once we modified the uval |
| + * there is no going back and subsequent operations must |
| + * not fail. |
| + */ |
| + pi_state_update_owner(pi_state, new_owner); |
| + postunlock = __rt_mutex_futex_unlock(&pi_state->pi_mutex, &wake_q); |
| + } |
| |
| out_unlock: |
| raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock); |
| @@ -2566,19 +2578,7 @@ retry: |
| * We fixed up user space. Now we need to fix the pi_state |
| * itself. |
| */ |
| - if (pi_state->owner != NULL) { |
| - raw_spin_lock(&pi_state->owner->pi_lock); |
| - WARN_ON(list_empty(&pi_state->list)); |
| - list_del_init(&pi_state->list); |
| - raw_spin_unlock(&pi_state->owner->pi_lock); |
| - } |
| - |
| - pi_state->owner = newowner; |
| - |
| - raw_spin_lock(&newowner->pi_lock); |
| - WARN_ON(!list_empty(&pi_state->list)); |
| - list_add(&pi_state->list, &newowner->pi_state_list); |
| - raw_spin_unlock(&newowner->pi_lock); |
| + pi_state_update_owner(pi_state, newowner); |
| raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock); |
| |
| return argowner == current; |