futex: Move futex exit handling into futex code

commit ba31c1a48538992316cc71ce94fa9cd3e7b427c0 upstream.

The futex exit handling is #ifdeffed into mm_release() which is not pretty
to begin with. But upcoming changes to address futex exit races need to add
more functionality to this exit code.

Split it out into a function, move it into futex code and make the various
futex exit functions static.

Preparatory only and no functional change.

Folded build fix from Borislav.

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.049705556@linutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Thomas Gleixner 2019-11-06 22:55:36 +01:00 committed by Greg Kroah-Hartman
parent ba386ec3d7
commit 8012f98f92
4 changed files with 48 additions and 41 deletions

View File

@ -410,8 +410,6 @@ struct compat_kexec_segment;
struct compat_mq_attr; struct compat_mq_attr;
struct compat_msgbuf; struct compat_msgbuf;
extern void compat_exit_robust_list(struct task_struct *curr);
#define BITS_PER_COMPAT_LONG (8*sizeof(compat_long_t)) #define BITS_PER_COMPAT_LONG (8*sizeof(compat_long_t))
#define BITS_TO_COMPAT_LONGS(bits) DIV_ROUND_UP(bits, BITS_PER_COMPAT_LONG) #define BITS_TO_COMPAT_LONGS(bits) DIV_ROUND_UP(bits, BITS_PER_COMPAT_LONG)

View File

@ -2,7 +2,9 @@
#ifndef _LINUX_FUTEX_H #ifndef _LINUX_FUTEX_H
#define _LINUX_FUTEX_H #define _LINUX_FUTEX_H
#include <linux/sched.h>
#include <linux/ktime.h> #include <linux/ktime.h>
#include <uapi/linux/futex.h> #include <uapi/linux/futex.h>
struct inode; struct inode;
@ -48,15 +50,24 @@ union futex_key {
#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = NULL } } #define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = NULL } }
#ifdef CONFIG_FUTEX #ifdef CONFIG_FUTEX
extern void exit_robust_list(struct task_struct *curr);
static inline void futex_init_task(struct task_struct *tsk)
{
tsk->robust_list = NULL;
#ifdef CONFIG_COMPAT
tsk->compat_robust_list = NULL;
#endif
INIT_LIST_HEAD(&tsk->pi_state_list);
tsk->pi_state_cache = NULL;
}
void futex_mm_release(struct task_struct *tsk);
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
u32 __user *uaddr2, u32 val2, u32 val3); u32 __user *uaddr2, u32 val2, u32 val3);
#else #else
static inline void exit_robust_list(struct task_struct *curr) static inline void futex_init_task(struct task_struct *tsk) { }
{ static inline void futex_mm_release(struct task_struct *tsk) { }
}
static inline long do_futex(u32 __user *uaddr, int op, u32 val, static inline long do_futex(u32 __user *uaddr, int op, u32 val,
ktime_t *timeout, u32 __user *uaddr2, ktime_t *timeout, u32 __user *uaddr2,
u32 val2, u32 val3) u32 val2, u32 val3)
@ -65,12 +76,4 @@ static inline long do_futex(u32 __user *uaddr, int op, u32 val,
} }
#endif #endif
#ifdef CONFIG_FUTEX_PI
extern void exit_pi_state_list(struct task_struct *curr);
#else
static inline void exit_pi_state_list(struct task_struct *curr)
{
}
#endif
#endif #endif

View File

@ -1286,20 +1286,7 @@ static int wait_for_vfork_done(struct task_struct *child,
void mm_release(struct task_struct *tsk, struct mm_struct *mm) void mm_release(struct task_struct *tsk, struct mm_struct *mm)
{ {
/* Get rid of any futexes when releasing the mm */ /* Get rid of any futexes when releasing the mm */
#ifdef CONFIG_FUTEX futex_mm_release(tsk);
if (unlikely(tsk->robust_list)) {
exit_robust_list(tsk);
tsk->robust_list = NULL;
}
#ifdef CONFIG_COMPAT
if (unlikely(tsk->compat_robust_list)) {
compat_exit_robust_list(tsk);
tsk->compat_robust_list = NULL;
}
#endif
if (unlikely(!list_empty(&tsk->pi_state_list)))
exit_pi_state_list(tsk);
#endif
uprobe_free_utask(tsk); uprobe_free_utask(tsk);
@ -2062,14 +2049,8 @@ static __latent_entropy struct task_struct *copy_process(
#ifdef CONFIG_BLOCK #ifdef CONFIG_BLOCK
p->plug = NULL; p->plug = NULL;
#endif #endif
#ifdef CONFIG_FUTEX futex_init_task(p);
p->robust_list = NULL;
#ifdef CONFIG_COMPAT
p->compat_robust_list = NULL;
#endif
INIT_LIST_HEAD(&p->pi_state_list);
p->pi_state_cache = NULL;
#endif
/* /*
* sigaltstack should be cleared when sharing the same VM * sigaltstack should be cleared when sharing the same VM
*/ */

View File

@ -325,6 +325,12 @@ static inline bool should_fail_futex(bool fshared)
} }
#endif /* CONFIG_FAIL_FUTEX */ #endif /* CONFIG_FAIL_FUTEX */
#ifdef CONFIG_COMPAT
static void compat_exit_robust_list(struct task_struct *curr);
#else
static inline void compat_exit_robust_list(struct task_struct *curr) { }
#endif
static inline void futex_get_mm(union futex_key *key) static inline void futex_get_mm(union futex_key *key)
{ {
mmgrab(key->private.mm); mmgrab(key->private.mm);
@ -890,7 +896,7 @@ static void put_pi_state(struct futex_pi_state *pi_state)
* Kernel cleans up PI-state, but userspace is likely hosed. * Kernel cleans up PI-state, but userspace is likely hosed.
* (Robust-futex cleanup is separate and might save the day for userspace.) * (Robust-futex cleanup is separate and might save the day for userspace.)
*/ */
void exit_pi_state_list(struct task_struct *curr) static void exit_pi_state_list(struct task_struct *curr)
{ {
struct list_head *next, *head = &curr->pi_state_list; struct list_head *next, *head = &curr->pi_state_list;
struct futex_pi_state *pi_state; struct futex_pi_state *pi_state;
@ -960,7 +966,8 @@ void exit_pi_state_list(struct task_struct *curr)
} }
raw_spin_unlock_irq(&curr->pi_lock); raw_spin_unlock_irq(&curr->pi_lock);
} }
#else
static inline void exit_pi_state_list(struct task_struct *curr) { }
#endif #endif
/* /*
@ -3588,7 +3595,7 @@ static inline int fetch_robust_entry(struct robust_list __user **entry,
* *
* We silently return on any sign of list-walking problem. * We silently return on any sign of list-walking problem.
*/ */
void exit_robust_list(struct task_struct *curr) static void exit_robust_list(struct task_struct *curr)
{ {
struct robust_list_head __user *head = curr->robust_list; struct robust_list_head __user *head = curr->robust_list;
struct robust_list __user *entry, *next_entry, *pending; struct robust_list __user *entry, *next_entry, *pending;
@ -3653,6 +3660,24 @@ void exit_robust_list(struct task_struct *curr)
} }
} }
void futex_mm_release(struct task_struct *tsk)
{
if (unlikely(tsk->robust_list)) {
exit_robust_list(tsk);
tsk->robust_list = NULL;
}
#ifdef CONFIG_COMPAT
if (unlikely(tsk->compat_robust_list)) {
compat_exit_robust_list(tsk);
tsk->compat_robust_list = NULL;
}
#endif
if (unlikely(!list_empty(&tsk->pi_state_list)))
exit_pi_state_list(tsk);
}
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
u32 __user *uaddr2, u32 val2, u32 val3) u32 __user *uaddr2, u32 val2, u32 val3)
{ {
@ -3780,7 +3805,7 @@ static void __user *futex_uaddr(struct robust_list __user *entry,
* *
* We silently return on any sign of list-walking problem. * We silently return on any sign of list-walking problem.
*/ */
void compat_exit_robust_list(struct task_struct *curr) static void compat_exit_robust_list(struct task_struct *curr)
{ {
struct compat_robust_list_head __user *head = curr->compat_robust_list; struct compat_robust_list_head __user *head = curr->compat_robust_list;
struct robust_list __user *entry, *next_entry, *pending; struct robust_list __user *entry, *next_entry, *pending;