diff --git a/kernel/futex/futex.h b/kernel/futex/futex.h index 547f509b2c87..33835b81e0c3 100644 --- a/kernel/futex/futex.h +++ b/kernel/futex/futex.h @@ -219,6 +219,7 @@ extern int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags, struct futex_q *q, struct futex_hash_bucket **hb); extern void futex_wait_queue(struct futex_hash_bucket *hb, struct futex_q *q, struct hrtimer_sleeper *timeout); +extern bool __futex_wake_mark(struct futex_q *q); extern void futex_wake_mark(struct wake_q_head *wake_q, struct futex_q *q); extern int fault_in_user_writeable(u32 __user *uaddr); diff --git a/kernel/futex/waitwake.c b/kernel/futex/waitwake.c index 35c6a637a4bb..6fcf5f723719 100644 --- a/kernel/futex/waitwake.c +++ b/kernel/futex/waitwake.c @@ -106,6 +106,24 @@ * double_lock_hb() and double_unlock_hb(), respectively. */ +bool __futex_wake_mark(struct futex_q *q) +{ + if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n")) + return false; + + __futex_unqueue(q); + /* + * The waiting task can free the futex_q as soon as q->lock_ptr = NULL + * is written, without taking any locks. This is possible in the event + * of a spurious wakeup, for example. A memory barrier is required here + * to prevent the following store to lock_ptr from getting ahead of the + * plist_del in __futex_unqueue(). + */ + smp_store_release(&q->lock_ptr, NULL); + + return true; +} + /* * The hash bucket lock must be held when this is called. * Afterwards, the futex_q must not be accessed. Callers @@ -116,19 +134,12 @@ void futex_wake_mark(struct wake_q_head *wake_q, struct futex_q *q) { struct task_struct *p = q->task; - if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n")) - return; - get_task_struct(p); - __futex_unqueue(q); - /* - * The waiting task can free the futex_q as soon as q->lock_ptr = NULL - * is written, without taking any locks. This is possible in the event - * of a spurious wakeup, for example. A memory barrier is required here - * to prevent the following store to lock_ptr from getting ahead of the - * plist_del in __futex_unqueue(). - */ - smp_store_release(&q->lock_ptr, NULL); + + if (!__futex_wake_mark(q)) { + put_task_struct(p); + return; + } /* * Queue the task for later wakeup for after we've released