On Mon, 26 Sep 2016 14:32:14 +0200
Peter Zijlstra <[email protected]> wrote:
> 
> --- a/kernel/futex.c
> +++ b/kernel/futex.c
> @@ -1374,9 +1374,8 @@ static int wake_futex_pi(u32 __user *uad
>        * scheduled away before the wake up can take place.
>        */
>       spin_unlock(&hb->lock);
> -     wake_up_q(&wake_q);
> -     if (deboost)
> -             rt_mutex_adjust_prio(current);
> +
> +     rt_mutex_postunlock(&wake_q, deboost);

Hmm...

>  
>       return 0;
>  }
> --- a/kernel/locking/rtmutex.c
> +++ b/kernel/locking/rtmutex.c
> @@ -1325,6 +1308,16 @@ static bool __sched rt_mutex_slowunlock(
>        */
>       mark_wakeup_next_waiter(wake_q, lock);
>  
> +     /*
> +      * We should deboost before waking the top waiter task such that
> +      * we don't run two tasks with the 'same' priority. This however
> +      * can lead to prio-inversion if we would get preempted after
> +      * the deboost but before waking our high-prio task, hence the
> +      * preempt_disable before unlock. Pairs with preempt_enable() in
> +      * rt_mutex_postunlock();

There's a preempt_enable() in rt_mutex_postunlock()? Does
wake_futex_pi() know that?

-- Steve


> +      */
> +     preempt_disable();
> +
>       raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
>  
>       /* check PI boosting */
> @@ -1390,14 +1383,23 @@ rt_mutex_fastunlock(struct rt_mutex *loc
>       } else {
>               bool deboost = slowfn(lock, &wake_q);
>  
> -             wake_up_q(&wake_q);
> -
> -             /* Undo pi boosting if necessary: */
> -             if (deboost)
> -                     rt_mutex_adjust_prio(current);
> +             rt_mutex_postunlock(&wake_q, deboost);
>       }
>  }
>  
> +
> +/*
> + * Undo pi boosting (if necessary) and wake top waiter.
> + */
> +void rt_mutex_postunlock(struct wake_q_head *wake_q, bool deboost)
> +{
> +     wake_up_q(wake_q);
> +
> +     /* Pairs with preempt_disable() in rt_mutex_slowunlock() */
> +     if (deboost)
> +             preempt_enable();
> +}
> +
>  /**
>   * rt_mutex_lock - lock a rt_mutex
>   *
> --- a/kernel/locking/rtmutex_common.h
> +++ b/kernel/locking/rtmutex_common.h
> @@ -111,6 +111,7 @@ extern int rt_mutex_finish_proxy_lock(st
>  extern int rt_mutex_timed_futex_lock(struct rt_mutex *l, struct 
> hrtimer_sleeper *to);
>  extern bool rt_mutex_futex_unlock(struct rt_mutex *lock,
>                                 struct wake_q_head *wqh);
> +extern void rt_mutex_postunlock(struct wake_q_head *wake_q, bool deboost);
>  extern void rt_mutex_adjust_prio(struct task_struct *task);
>  
>  #ifdef CONFIG_DEBUG_RT_MUTEXES
> 

Reply via email to