From: Joel Fernandes <joel@joelfernandes.org>
To: "Zhang, Qiang1" <qiang1.zhang@intel.com>
Cc: paulmck@kernel.org, frederic@kernel.org,
quic_neeraju@quicinc.com, rcu@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v4] rcu-tasks: Make rude RCU-Tasks work well with CPU hotplug
Date: Fri, 2 Dec 2022 08:25:13 -0500 [thread overview]
Message-ID: <6AC29795-0292-4FE9-9167-13122C08CD96@joelfernandes.org> (raw)
In-Reply-To: <PH0PR11MB58800E4DF4BF0B60FBFC71E2DA179@PH0PR11MB5880.namprd11.prod.outlook.com>
> On Dec 2, 2022, at 7:52 AM, Zhang, Qiang1 <qiang1.zhang@intel.com> wrote:
>
> On Thu, Dec 01, 2022 at 07:45:33AM +0800, Zqiang wrote:
>> Currently, invoke rcu_tasks_rude_wait_gp() to wait one rude
>> RCU-tasks grace period, if __num_online_cpus == 1, will return
>> directly, indicates the end of the rude RCU-task grace period.
>> suppose the system has two cpus, consider the following scenario:
>>
>> CPU0 CPU1 (going offline)
>> migration/1 task:
>> cpu_stopper_thread
>> -> take_cpu_down
>> -> _cpu_disable
>> (dec __num_online_cpus)
>> ->cpuhp_invoke_callback
>> preempt_disable
>> access old_data0
>> task1
>> del old_data0 .....
>> synchronize_rcu_tasks_rude()
>> task1 schedule out
>> ....
>> task2 schedule in
>> rcu_tasks_rude_wait_gp()
>> ->__num_online_cpus == 1
>> ->return
>> ....
>> task1 schedule in
>> ->free old_data0
>> preempt_enable
>>
>> when CPU1 dec __num_online_cpus and __num_online_cpus is equal one,
>> the CPU1 has not finished offline, stop_machine task(migration/1)
>> still running on CPU1, maybe still accessing 'old_data0', but the
>> 'old_data0' has freed on CPU0.
>>
>> In order to prevent the above scenario from happening, this commit
>> remove check for __num_online_cpus == 0 and add handling of calling
>> synchronize_rcu_tasks_generic() during early boot(when the
>> rcu_scheduler_active variable is RCU_SCHEDULER_INACTIVE, the scheduler
>> not yet initialized and only one boot-CPU online).
>>
>> Signed-off-by: Zqiang <qiang1.zhang@intel.com>
>
>> Very good, thank you! I did the usual wordsmithing, including to that
>> error message, so as usual please check to make sure that I didn't mess
>> something up.
>>
>> Thanx, Paul
>>
>> ------------------------------------------------------------------------
>>
>> commit 033ddc5d337984e20b9d49c8af4faa4689727626
>> Author: Zqiang <qiang1.zhang@intel.com>
>> Date: Thu Dec 1 07:45:33 2022 +0800
>>
>> rcu-tasks: Make rude RCU-Tasks work well with CPU hotplug
>>
>> The synchronize_rcu_tasks_rude() function invokes rcu_tasks_rude_wait_gp()
>> to wait one rude RCU-tasks grace period. The rcu_tasks_rude_wait_gp()
>> function in turn checks if there is only a single online CPU. If so, it
>> will immediately return, because a call to synchronize_rcu_tasks_rude()
>> is by definition a grace period on a single-CPU system. (We could
>> have blocked!)
>>
>> Unfortunately, this check uses num_online_cpus() without synchronization,
>> which can result in too-short grace periods. To see this, consider the
>> following scenario:
>>
>> CPU0 CPU1 (going offline)
>> migration/1 task:
>> cpu_stopper_thread
>> -> take_cpu_down
>> -> _cpu_disable
>> (dec __num_online_cpus)
>> ->cpuhp_invoke_callback
>> preempt_disable
>> access old_data0
>> task1
>> del old_data0 .....
>> synchronize_rcu_tasks_rude()
>> task1 schedule out
>> ....
>> task2 schedule in
>> rcu_tasks_rude_wait_gp()
>> ->__num_online_cpus == 1
>> ->return
>> ....
>> task1 schedule in
>> ->free old_data0
>> preempt_enable
>>
>> When CPU1 decrements __num_online_cpus, its value becomes 1. However,
>> CPU1 has not finished going offline, and will take one last trip through
>> the scheduler and the idle loop before it actually stops executing
>> instructions. Because synchronize_rcu_tasks_rude() is mostly used for
>> tracing, and because both the scheduler and the idle loop can be traced,
>> this means that CPU0's prematurely ended grace period might disrupt the
>> tracing on CPU1. Given that this disruption might include CPU1 executing
>> instructions in memory that was just now freed (and maybe reallocated),
>> this is a matter of some concern.
>>
>> This commit therefore removes that problematic single-CPU check from the
>> rcu_tasks_rude_wait_gp() function. This dispenses with the single-CPU
>> optimization, but there is no evidence indicating that this optimization
>> is important. In addition, synchronize_rcu_tasks_generic() contains a
>> similar optimization (albeit only for early boot), which also splats.
>> (As in exactly why are you invoking synchronize_rcu_tasks_rude() so
>> early in boot, anyway???)
>>
>> It is OK for the synchronize_rcu_tasks_rude() function's check to be
>> unsynchronized because the only times that this check can evaluate to
>> true is when there is only a single CPU running with preemption
>> disabled.
>>
>> While in the area, this commit also fixes a minor bug in which a
>> call to synchronize_rcu_tasks_rude() would instead be attributed to
>> synchronize_rcu_tasks().
>>
>> [ paulmck: Add "synchronize_" prefix and "()" suffix. ]
>>
>> Signed-off-by: Zqiang <qiang1.zhang@intel.com>
>> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
>>
>> diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
>> index 4dda8e6e5707f..d845723c1af41 100644
>> --- a/kernel/rcu/tasks.h
>> +++ b/kernel/rcu/tasks.h
>> @@ -560,8 +560,9 @@ static int __noreturn rcu_tasks_kthread(void *arg)
>> static void synchronize_rcu_tasks_generic(struct rcu_tasks *rtp)
>> {
>> /* Complain if the scheduler has not started. */
>> - WARN_ONCE(rcu_scheduler_active == RCU_SCHEDULER_INACTIVE,
>> - "synchronize_rcu_tasks called too soon");
>> + if (WARN_ONCE(rcu_scheduler_active == RCU_SCHEDULER_INACTIVE,
>> + "synchronize_%s() called too soon", rtp->name))
>
> Thanks Paul, detailed description and modification 😊.
True statement. Good example for everyone ;-)
- Joel
>
>
>> + return;
>>
>> // If the grace-period kthread is running, use it.
>> if (READ_ONCE(rtp->kthread_ptr)) {
>> @@ -1064,9 +1065,6 @@ static void rcu_tasks_be_rude(struct work_struct *work)
>> // Wait for one rude RCU-tasks grace period.
>> static void rcu_tasks_rude_wait_gp(struct rcu_tasks *rtp)
>> {
>> - if (num_online_cpus() <= 1)
>> - return; // Fastpath for only one CPU.
>> -
>> rtp->n_ipis += cpumask_weight(cpu_online_mask);
>> schedule_on_each_cpu(rcu_tasks_be_rude);
>> }
next prev parent reply other threads:[~2022-12-02 13:25 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-30 23:45 Zqiang
2022-12-01 0:13 ` Paul E. McKenney
2022-12-02 12:51 ` Zhang, Qiang1
2022-12-02 13:25 ` Joel Fernandes [this message]
2022-12-19 0:33 ` kernel test robot
2022-12-19 2:21 ` Zhang, Qiang1
2022-12-21 19:33 ` Paul E. McKenney
2022-12-22 9:35 ` Zhang, Qiang1
2023-01-05 18:22 ` Paul E. McKenney
2023-01-06 2:48 ` Zhang, Qiang1
2023-01-10 2:10 ` Paul E. McKenney
2023-01-10 5:02 ` Paul E. McKenney
2023-01-10 8:12 ` Zhang, Qiang1
2023-01-10 14:58 ` Paul E. McKenney
2023-01-10 17:59 ` Paul E. McKenney
2023-01-11 5:21 ` Zhang, Qiang1
2023-01-12 17:47 ` Paul E. McKenney
2023-01-13 8:58 ` Zhang, Qiang1
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=6AC29795-0292-4FE9-9167-13122C08CD96@joelfernandes.org \
--to=joel@joelfernandes.org \
--cc=frederic@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=paulmck@kernel.org \
--cc=qiang1.zhang@intel.com \
--cc=quic_neeraju@quicinc.com \
--cc=rcu@vger.kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®