[Devel] [PATCH 07/17] Port diff-sched-introduce-cond_resched_may_throttle

Kirill Tkhai ktkhai at odin.com
Thu Sep 3 05:12:25 PDT 2015



On 03.09.2015 13:14, Vladimir Davydov wrote:
> On Thu, Sep 03, 2015 at 11:56:57AM +0300, Kirill Tkhai wrote:
> ...
>>> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
>>> index 167d0f66387b..49a93569b5e6 100644
>>> --- a/kernel/sched/fair.c
>>> +++ b/kernel/sched/fair.c
>>> @@ -965,7 +965,8 @@ static inline void update_entity_boost(struct sched_entity *se)
>>>  					p->woken_while_running;
>>>  			p->woken_while_running = 0;
>>>  		} else
>>> -			se->boosted = sched_feat(BOOST_PREEMPT);
>>> +			se->boosted = sched_feat(BOOST_PREEMPT) &&
>>> +					!p->may_throttle;
>>
>> This function is unsafe, because there is case where put_prev_task() is made
>> before dequeue_task() in scheduler. This lead to we clear boosted flag and leave
>> se linked in boosted list, while it mustn't be there.
> 
> AFAICS the only such a place is cpu offline handling, so this is an
> extremely rare case. Anyway, it's a separate issue, which has to be
> fixed separately.

Yeah, will wait.

>>
>> I suggest to unconditionally dequeue bootsted entities, where you do that,
>> without checking for entity_boosted(). Of course, you need to use list_del_init()
>> instead of plain list_del(). In this case you will be able to change se->boosted
>> flag like you want in this function.
> 
> I'd prefer to just skip updating ->boosted flag when p != current. In
> fact, when this code was initially written I simply overlooked the fact
> that update_entity_boost may be called from another task's context (like
> from setprio). Doing this is completely wrong, because checking
> preempt_count or altering a bit field on task_struct must only be done
> from the current context.
> 
> Here it goes:
> ---
> From: Vladimir Davydov <vdavydov at parallels.com>
> Date: Thu, 3 Sep 2015 12:46:53 +0300
> Subject: [PATCH] sched/fair: only update current task boost
> 
> put_prev_task, which calls update_entity_boost, may be invoked for prev
> != current (e.g. on setprio). In rare cases (e.g. cpu offline), this is
> done before dequeue_task. As a result, a task might not get removed from
> the list of boosted entity on dequeue, leading to a crash.
> 
> Anyway, it only makes sense to call update_entity_boost on current task,
> because it relies on preempt_count and flips task_struct bit fields. So
> insert the appropriate check to this function in order to fix this
> issue.
> 
> Reported-by: Kirill Tkhai <ktkhai at odin.com>
> Signed-off-by: Vladimir Davydov <vdavydov at parallels.com>

Acked-by: Kirill Tkhai <ktkhai at odin.com>

> 
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index 49a93569b5e6..f7e8ba7df643 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -960,6 +960,9 @@ static inline void update_entity_boost(struct sched_entity *se)
>  	else {
>  		struct task_struct *p = task_of(se);
>  
> +		if (unlikely(p != current))
> +			return;
> +
>  		if (!(preempt_count() & PREEMPT_ACTIVE)) {
>  			se->boosted = sched_feat(BOOST_WAKEUPS) &&
>  					p->woken_while_running;
> 



More information about the Devel mailing list