Skip to content

Commit 18f6943

Browse files
committed
futex: Mark the begin of futex exit explicitly
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 <[email protected]> Reviewed-by: Ingo Molnar <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent f24f224 commit 18f6943

File tree

3 files changed

+40
-41
lines changed

3 files changed

+40
-41
lines changed

include/linux/futex.h

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ union futex_key {
5252
#ifdef CONFIG_FUTEX
5353
enum {
5454
FUTEX_STATE_OK,
55+
FUTEX_STATE_EXITING,
5556
FUTEX_STATE_DEAD,
5657
};
5758

@@ -66,41 +67,15 @@ static inline void futex_init_task(struct task_struct *tsk)
6667
tsk->futex_state = FUTEX_STATE_OK;
6768
}
6869

69-
/**
70-
* futex_exit_done - Sets the tasks futex state to FUTEX_STATE_DEAD
71-
* @tsk: task to set the state on
72-
*
73-
* Set the futex exit state of the task lockless. The futex waiter code
74-
* observes that state when a task is exiting and loops until the task has
75-
* actually finished the futex cleanup. The worst case for this is that the
76-
* waiter runs through the wait loop until the state becomes visible.
77-
*
78-
* This has two callers:
79-
*
80-
* - futex_mm_release() after the futex exit cleanup has been done
81-
*
82-
* - do_exit() from the recursive fault handling path.
83-
*
84-
* In case of a recursive fault this is best effort. Either the futex exit
85-
* code has run already or not. If the OWNER_DIED bit has been set on the
86-
* futex then the waiter can take it over. If not, the problem is pushed
87-
* back to user space. If the futex exit code did not run yet, then an
88-
* already queued waiter might block forever, but there is nothing which
89-
* can be done about that.
90-
*/
91-
static inline void futex_exit_done(struct task_struct *tsk)
92-
{
93-
tsk->futex_state = FUTEX_STATE_DEAD;
94-
}
95-
70+
void futex_exit_recursive(struct task_struct *tsk);
9671
void futex_exit_release(struct task_struct *tsk);
9772
void futex_exec_release(struct task_struct *tsk);
9873

9974
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
10075
u32 __user *uaddr2, u32 val2, u32 val3);
10176
#else
10277
static inline void futex_init_task(struct task_struct *tsk) { }
103-
static inline void futex_exit_done(struct task_struct *tsk) { }
78+
static inline void futex_exit_recursive(struct task_struct *tsk) { }
10479
static inline void futex_exit_release(struct task_struct *tsk) { }
10580
static inline void futex_exec_release(struct task_struct *tsk) { }
10681
static inline long do_futex(u32 __user *uaddr, int op, u32 val,

kernel/exit.c

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -746,23 +746,12 @@ void __noreturn do_exit(long code)
746746
*/
747747
if (unlikely(tsk->flags & PF_EXITING)) {
748748
pr_alert("Fixing recursive fault but reboot is needed!\n");
749-
futex_exit_done(tsk);
749+
futex_exit_recursive(tsk);
750750
set_current_state(TASK_UNINTERRUPTIBLE);
751751
schedule();
752752
}
753753

754754
exit_signals(tsk); /* sets PF_EXITING */
755-
/*
756-
* Ensure that all new tsk->pi_lock acquisitions must observe
757-
* PF_EXITING. Serializes against futex.c:attach_to_pi_owner().
758-
*/
759-
smp_mb();
760-
/*
761-
* Ensure that we must observe the pi_state in exit_mm() ->
762-
* mm_release() -> exit_pi_state_list().
763-
*/
764-
raw_spin_lock_irq(&tsk->pi_lock);
765-
raw_spin_unlock_irq(&tsk->pi_lock);
766755

767756
if (unlikely(in_atomic())) {
768757
pr_info("note: %s[%d] exited with preempt_count %d\n",

kernel/futex.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3679,10 +3679,45 @@ void futex_exec_release(struct task_struct *tsk)
36793679
exit_pi_state_list(tsk);
36803680
}
36813681

3682+
/**
3683+
* futex_exit_recursive - Set the tasks futex state to FUTEX_STATE_DEAD
3684+
* @tsk: task to set the state on
3685+
*
3686+
* Set the futex exit state of the task lockless. The futex waiter code
3687+
* observes that state when a task is exiting and loops until the task has
3688+
* actually finished the futex cleanup. The worst case for this is that the
3689+
* waiter runs through the wait loop until the state becomes visible.
3690+
*
3691+
* This is called from the recursive fault handling path in do_exit().
3692+
*
3693+
* This is best effort. Either the futex exit code has run already or
3694+
* not. If the OWNER_DIED bit has been set on the futex then the waiter can
3695+
* take it over. If not, the problem is pushed back to user space. If the
3696+
* futex exit code did not run yet, then an already queued waiter might
3697+
* block forever, but there is nothing which can be done about that.
3698+
*/
3699+
void futex_exit_recursive(struct task_struct *tsk)
3700+
{
3701+
tsk->futex_state = FUTEX_STATE_DEAD;
3702+
}
3703+
36823704
void futex_exit_release(struct task_struct *tsk)
36833705
{
3706+
tsk->futex_state = FUTEX_STATE_EXITING;
3707+
/*
3708+
* Ensure that all new tsk->pi_lock acquisitions must observe
3709+
* FUTEX_STATE_EXITING. Serializes against attach_to_pi_owner().
3710+
*/
3711+
smp_mb();
3712+
/*
3713+
* Ensure that we must observe the pi_state in exit_pi_state_list().
3714+
*/
3715+
raw_spin_lock_irq(&tsk->pi_lock);
3716+
raw_spin_unlock_irq(&tsk->pi_lock);
3717+
36843718
futex_exec_release(tsk);
3685-
futex_exit_done(tsk);
3719+
3720+
tsk->futex_state = FUTEX_STATE_DEAD;
36863721
}
36873722

36883723
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,

0 commit comments

Comments
 (0)