summaryrefslogtreecommitdiff
path: root/kernel/futex.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2021-02-01 15:12:09 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-02-03 23:16:16 +0100
commit40da511f787b75a80efa3ae5d3f90753a795a9e4 (patch)
tree019104a91b851975b4c17f2cdcdc77cfe90c4580 /kernel/futex.c
parentda81e2f3e1cb8bf5bb1323370c5e331606841260 (diff)
futex: Mark the begin of futex exit explicitly
commit 18f694385c4fd77a09851fd301236746ca83f3cb upstream. Instead of relying on PF_EXITING use an explicit state for the futex exit and set it in the futex exit function. This moves the smp barrier and the lock/unlock serialization into the futex code. As with the DEAD state this is restricted to the exit path as exec continues to use the same task struct. This allows to simplify that logic in a next step. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Ingo Molnar <mingo@kernel.org> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lkml.kernel.org/r/20191106224556.539409004@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'kernel/futex.c')
-rw-r--r--kernel/futex.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index f85635ff2fce..5bd3afee4e13 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -3252,10 +3252,45 @@ void futex_exec_release(struct task_struct *tsk)
exit_pi_state_list(tsk);
}
+/**
+ * futex_exit_recursive - Set the tasks futex state to FUTEX_STATE_DEAD
+ * @tsk: task to set the state on
+ *
+ * Set the futex exit state of the task lockless. The futex waiter code
+ * observes that state when a task is exiting and loops until the task has
+ * actually finished the futex cleanup. The worst case for this is that the
+ * waiter runs through the wait loop until the state becomes visible.
+ *
+ * This is called from the recursive fault handling path in do_exit().
+ *
+ * This is best effort. Either the futex exit code has run already or
+ * not. If the OWNER_DIED bit has been set on the futex then the waiter can
+ * take it over. If not, the problem is pushed back to user space. If the
+ * futex exit code did not run yet, then an already queued waiter might
+ * block forever, but there is nothing which can be done about that.
+ */
+void futex_exit_recursive(struct task_struct *tsk)
+{
+ tsk->futex_state = FUTEX_STATE_DEAD;
+}
+
void futex_exit_release(struct task_struct *tsk)
{
+ tsk->futex_state = FUTEX_STATE_EXITING;
+ /*
+ * Ensure that all new tsk->pi_lock acquisitions must observe
+ * FUTEX_STATE_EXITING. Serializes against attach_to_pi_owner().
+ */
+ smp_mb();
+ /*
+ * Ensure that we must observe the pi_state in exit_pi_state_list().
+ */
+ raw_spin_lock_irq(&tsk->pi_lock);
+ raw_spin_unlock_irq(&tsk->pi_lock);
+
futex_exec_release(tsk);
- futex_exit_done(tsk);
+
+ tsk->futex_state = FUTEX_STATE_DEAD;
}
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,