|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH RFC v2 15/15] rcu-tasks: Kick running holdouts through the scheduler
On Fri, Sep 11, 2026 at 02:08:53PM +0000, Josef Bacik wrote:
> A holdout that is running on a CPU with nothing else runnable is only
> preempted if the tick acts on rcu_request_urgent_qs_task()'s flag, and
> there may be no tick. Now that a preemption outside a trampoline is a
> quiescent state, have check_holdout_task() call resched_cpu() on a
> running holdout as well, so the scheduler IPIs it and it goes through
> __schedule() and reports (or, if it is inside a trampoline, does not
> report) its own state with purely local ordering. Nothing reads a
> running task's rcu_tramp_nesting remotely.
>
> Only under CONFIG_RCU_TASKS_PREEMPT_QS; other architectures are
> unchanged.
>
> Suggested-by: Paul E. McKenney <paulmck@xxxxxxxxxx>
> Assisted-by: LLM
> Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
Much better! But please see below.
Thanx, Paul
> ---
> kernel/rcu/tasks.h | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
> index ba432bd922e2..02d2592ab7a3 100644
> --- a/kernel/rcu/tasks.h
> +++ b/kernel/rcu/tasks.h
> @@ -1038,8 +1038,18 @@ static bool rcu_tasks_preempted_qs(struct task_struct
> *t)
> {
> return task_call_func(t, rcu_tasks_switched_out_clean, NULL);
> }
> +
> +/* Make a running holdout pass through __schedule() soon, tick or no tick. */
> +static void rcu_tasks_kick_running(struct task_struct *t)
> +{
> + int cpu = task_cpu(t);
> +
> + if (task_curr(t) && cpu_online(cpu))
> + resched_cpu(cpu);
> +}
> #else
> static bool rcu_tasks_preempted_qs(struct task_struct *t) { return false; }
> +static void rcu_tasks_kick_running(struct task_struct *t) { }
> #endif
>
> /* Per-task initial processing. */
> @@ -1219,6 +1229,7 @@ static void check_holdout_task(struct task_struct *t,
> return;
> }
> rcu_request_urgent_qs_task(t);
> + rcu_tasks_kick_running(t);
Something I learned the hard way, though Google paid most of the tuition
for this lesson: There can be a *lot* of tasks on large systems, as
in hundreds of thousands of them. If these tasks are consuming CPU in
very short bursts, we could easily repeatedly invoke resched_cpu() on
the same CPU, and all invocations other than the last one are redundant.
I instead suggest doing something similar to force_qs_rnp(), where a
cpumask is accumulated and at the end resched_cpu() is invoked for each
CPU with a bit set in that mask.
Of course, if a CPU appears twice while traversing the tasks list, then
each of those tasks did a context switch, which would have reported a
Tasks RCU quiescent state. Unless those tasks happened to have non-zero
->rcu_tramp_nesting at that time.
Which suggests that each task have a pair of counters. Or that
rcu_tasks_trampoline_exit() should check for zero ->rcu_tramp_nesting,
and report a quiescent state at that point.
Either way, if a CPU appears only once in the tasks_list traversal,
hitting it with resched_cpu() makes sense. Though we might also
need to suppress calls to resched_cpu() for grace periods that are
(say) less than one second old.
Thoughts?
Thanx, Paul
> if (!needreport)
> return;
> if (*firstreport) {
>
> --
> 2.55.0
>
>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |