Re: [PATCH v3] sched/rt: fix bad task migration for rt tasks

From: Schspa Shi
Date: Fri Jul 08 2022 - 01:05:05 EST




Steven Rostedt <rostedt@xxxxxxxxxxx> writes:

On Fri, 8 Jul 2022 00:50:14 +0800
Schspa Shi <schspa@xxxxxxxxx> wrote:

Please refer to the following scenarios.

I'm not sure this is what is happening. Do you have a trace to back this up?


I don't have a trace. This is inferred from the exception log.


CPU0 CPU1
------------------------------------------------------------------
push_rt_task
check is_migration_disabled(next_task)
task not running and
migration_disabled == 0
find_lock_lowest_rq(next_task, rq);
_double_lock_balance(this_rq, busiest);
raw_spin_rq_unlock(this_rq);
double_rq_lock(this_rq, busiest);
<<wait for busiest rq>>
<wakeup>

Here's the problem I have. next_task is queued on CPU0, (otherwise CPU0
would not be pushing it). As CPU0 is currently running push_rt_task, how
did next_task start running to set its migrate_disable flag?

THe next_task wasn't queued on CPU0, it's queued on CPU1 in this
scenarios.

And it's because when task wakup, the rq argument is not the
current running CPU rq, it's next_task's rq
(i.e. CPU1's rq in this sample scenarios).

And you can check this with the Call trace from the crash log.

[123671.996969] Call trace:
[123671.996975] set_task_cpu+0x8c/0x108
[123671.996984] push_rt_task.part.0+0x144/0x184
[123671.996995] push_rt_tasks+0x28/0x3c
[123671.997002] task_woken_rt+0x58/0x68
[123671.997009] ttwu_do_wakeup+0x5c/0xd0
[123671.997019] ttwu_do_activate+0xc0/0xd4
[123671.997028] try_to_wake_up+0x244/0x288
[123671.997036] wake_up_process+0x18/0x24
[123671.997045] __irq_wake_thread+0x64/0x80
[123671.997056] __handle_irq_event_percpu+0x110/0x124

Function ttwu_do_wakeup will lock the task's rq, not current running
cpu rq.


Even if it was woken up on another CPU and ran there, by setting
migrate_disable, it would not be put back to CPU0, because its
migrate_disable flag is set (if it is, then there's the bug).


It no needs to put it back to CPU0 for this issue, it's still on CPU1.

After releasing the rq lock and retaking it, we check that the next_task is
still the next task on CPU0 to push.


task become running
migrate_disable();
<context out>
deactivate_task(rq, next_task, 0);
set_task_cpu(next_task, lowest_rq->cpu);
WARN_ON_ONCE(is_migration_disabled(p));
---------OOPS-------------

I don't see how this can happen.

-- Steve

--
BRs
Schspa Shi