From: Steven Rostedt <rostedt@goodmis.org>
To: Harshit Agarwal <harshit@nutanix.com>
Cc: Ingo Molnar <mingo@redhat.com>,
Peter Zijlstra <peterz@infradead.org>,
Juri Lelli <juri.lelli@redhat.com>,
Vincent Guittot <vincent.guittot@linaro.org>,
Dietmar Eggemann <dietmar.eggemann@arm.com>,
Ben Segall <bsegall@google.com>, Mel Gorman <mgorman@suse.de>,
Valentin Schneider <vschneid@redhat.com>,
linux-kernel@vger.kernel.org, Jon Kohler <jon@nutanix.com>,
Gauri Patwardhan <gauri.patwardhan@nutanix.com>,
Rahul Chunduru <rahul.chunduru@nutanix.com>,
Will Ton <william.ton@nutanix.com>
Subject: Re: [PATCH] sched/rt: Fix race in push_rt_task
Date: Tue, 11 Feb 2025 10:11:37 -0500 [thread overview]
Message-ID: <20250211101137.5824285d@gandalf.local.home> (raw)
In-Reply-To: <20250211054646.23987-1-harshit@nutanix.com>
On Tue, 11 Feb 2025 05:46:45 +0000
Harshit Agarwal <harshit@nutanix.com> wrote:
> Overview
> ========
> When a CPU chooses to call push_rt_task and picks a task to push to
> another CPU's runqueue then it will call find_lock_lowest_rq method
> which would take a double lock on both CPUs' runqueues. If one of the
> locks aren't readily available, it may lead to dropping the current
> runqueue lock and reacquiring both the locks at once. During this window
> it is possible that the task is already migrated and is running on some
> other CPU. These cases are already handled. However, if the task is
> migrated and has already been executed and another CPU is now trying to
> wake it up (ttwu) such that it is queued again on the runqeue
> (on_rq is 1) and also if the task was run by the same CPU, then the
> current checks will pass even though the task was migrated out and is no
> longer in the pushable tasks list.
Nice catch! And nice analysis.
> diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
> index 4b8e33c615b1..d48a9cb9ac92 100644
> --- a/kernel/sched/rt.c
> +++ b/kernel/sched/rt.c
> @@ -1885,6 +1885,27 @@ static int find_lowest_rq(struct task_struct *task)
> return -1;
> }
>
> +static struct task_struct *pick_next_pushable_task(struct rq *rq)
> +{
> + struct task_struct *p;
> +
> + if (!has_pushable_tasks(rq))
> + return NULL;
> +
> + p = plist_first_entry(&rq->rt.pushable_tasks,
> + struct task_struct, pushable_tasks);
> +
> + BUG_ON(rq->cpu != task_cpu(p));
> + BUG_ON(task_current(rq, p));
> + BUG_ON(task_current_donor(rq, p));
> + BUG_ON(p->nr_cpus_allowed <= 1);
> +
> + BUG_ON(!task_on_rq_queued(p));
> + BUG_ON(!rt_task(p));
> +
> + return p;
> +}
> +
> /* Will lock the rq it finds */
> static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq)
> {
> @@ -1920,13 +1941,18 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq)
> * It is possible the task was scheduled, set
> * "migrate_disabled" and then got preempted, so we must
> * check the task migration disable flag here too.
> + * Also, the task may have been dequeued and completed
> + * execution on the same CPU during this time, therefore
> + * check if the task is still at the head of the
> + * pushable tasks list.
> */
> if (unlikely(task_rq(task) != rq ||
> !cpumask_test_cpu(lowest_rq->cpu, &task->cpus_mask) ||
> task_on_cpu(rq, task) ||
> !rt_task(task) ||
> is_migration_disabled(task) ||
> - !task_on_rq_queued(task))) {
> + !task_on_rq_queued(task) ||
> + task != pick_next_pushable_task(rq))) {
I'm wondering? Could we replace all of these checks with just:
task != pick_next_pushable_task(rq)
?
I mean, what check above would fail and not cause that one to fail?
Maybe the is_migration_disabled(), but I'd like to remove any of those
checks that would be covered with the "pick_next_pushable_task()".
-- Steve
>
> double_unlock_balance(rq, lowest_rq);
> lowest_rq = NULL;
> @@ -1946,27 +1972,6 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq)
> return lowest_rq;
> }
>
> -static struct task_struct *pick_next_pushable_task(struct rq *rq)
> -{
> - struct task_struct *p;
> -
> - if (!has_pushable_tasks(rq))
> - return NULL;
> -
> - p = plist_first_entry(&rq->rt.pushable_tasks,
> - struct task_struct, pushable_tasks);
> -
> - BUG_ON(rq->cpu != task_cpu(p));
> - BUG_ON(task_current(rq, p));
> - BUG_ON(task_current_donor(rq, p));
> - BUG_ON(p->nr_cpus_allowed <= 1);
> -
> - BUG_ON(!task_on_rq_queued(p));
> - BUG_ON(!rt_task(p));
> -
> - return p;
> -}
> -
> /*
> * If the current CPU has more than one RT task, see if the non
> * running task can migrate over to a CPU that is running a task
next prev parent reply other threads:[~2025-02-11 15:11 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-11 5:46 [PATCH] sched/rt: Fix race in push_rt_task Harshit Agarwal
2025-02-11 15:11 ` Steven Rostedt [this message]
2025-02-11 21:08 ` Harshit Agarwal
2025-02-11 21:39 ` Steven Rostedt
2025-02-11 22:24 ` Harshit Agarwal
2025-02-13 17:54 ` [PATCH v2] " Harshit Agarwal
2025-02-17 15:50 ` Steven Rostedt
2025-02-17 16:36 ` Harshit Agarwal
2025-02-17 16:53 ` Steven Rostedt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250211101137.5824285d@gandalf.local.home \
--to=rostedt@goodmis.org \
--cc=bsegall@google.com \
--cc=dietmar.eggemann@arm.com \
--cc=gauri.patwardhan@nutanix.com \
--cc=harshit@nutanix.com \
--cc=jon@nutanix.com \
--cc=juri.lelli@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mgorman@suse.de \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=rahul.chunduru@nutanix.com \
--cc=vincent.guittot@linaro.org \
--cc=vschneid@redhat.com \
--cc=william.ton@nutanix.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.