Skip to content

Commit

Permalink
futex: Move futex exit handling into futex code
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Ingo Molnar <[email protected]>
Acked-by: Peter Zijlstra (Intel) <[email protected]>
Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Greg Kroah-Hartman <[email protected]>
Signed-off-by: Lee Jones <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
KAGA-KOKO authored and gregkh committed Feb 3, 2021
1 parent ad940f6 commit 8d2b511
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 33 deletions.
2 changes: 0 additions & 2 deletions include/linux/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,8 +306,6 @@ struct compat_kexec_segment;
struct compat_mq_attr;
struct compat_msgbuf;

extern void compat_exit_robust_list(struct task_struct *curr);

asmlinkage long
compat_sys_set_robust_list(struct compat_robust_list_head __user *head,
compat_size_t len);
Expand Down
24 changes: 17 additions & 7 deletions include/linux/futex.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef _LINUX_FUTEX_H
#define _LINUX_FUTEX_H

#include <linux/sched.h>

#include <uapi/linux/futex.h>

struct inode;
Expand Down Expand Up @@ -53,14 +55,22 @@ union futex_key {
#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = 0ULL } }

#ifdef CONFIG_FUTEX
extern void exit_robust_list(struct task_struct *curr);
extern void exit_pi_state_list(struct task_struct *curr);
#else
static inline void exit_robust_list(struct task_struct *curr)
{
}
static inline void exit_pi_state_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,
u32 __user *uaddr2, u32 val2, u32 val3);
#else
static inline void futex_init_task(struct task_struct *tsk) { }
static inline void futex_mm_release(struct task_struct *tsk) { }
#endif
#endif
25 changes: 3 additions & 22 deletions kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -890,20 +890,7 @@ static int wait_for_vfork_done(struct task_struct *child,
void mm_release(struct task_struct *tsk, struct mm_struct *mm)
{
/* Get rid of any futexes when releasing the mm */
#ifdef CONFIG_FUTEX
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
futex_mm_release(tsk);

uprobe_free_utask(tsk);

Expand Down Expand Up @@ -1511,14 +1498,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
#ifdef CONFIG_BLOCK
p->plug = NULL;
#endif
#ifdef CONFIG_FUTEX
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
futex_init_task(p);

/*
* sigaltstack should be cleared when sharing the same VM
*/
Expand Down
28 changes: 26 additions & 2 deletions kernel/futex.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,12 @@ static inline bool should_fail_futex(bool fshared)
}
#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)
{
atomic_inc(&key->private.mm->mm_count);
Expand Down Expand Up @@ -889,7 +895,7 @@ static struct task_struct * futex_find_get_task(pid_t pid)
* Kernel cleans up PI-state, but userspace is likely hosed.
* (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 futex_pi_state *pi_state;
Expand Down Expand Up @@ -3166,7 +3172,7 @@ static inline int fetch_robust_entry(struct robust_list __user **entry,
*
* 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 __user *entry, *next_entry, *pending;
Expand Down Expand Up @@ -3229,6 +3235,24 @@ void exit_robust_list(struct task_struct *curr)
curr, pip);
}

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,
u32 __user *uaddr2, u32 val2, u32 val3)
{
Expand Down

0 comments on commit 8d2b511

Please sign in to comment.