From: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
To: paulmck@kernel.org
Cc: frederic@kernel.org, rcu@vger.kernel.org,
linux-kernel@vger.kernel.org, kernel-team@meta.com,
rostedt@goodmis.org, kernel test robot <oliver.sang@intel.com>,
Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Kent Overstreet <kent.overstreet@linux.dev>,
bpf@vger.kernel.org
Subject: Re: [PATCH rcu 06/12] srcu: Add srcu_read_lock_lite() and srcu_read_unlock_lite()
Date: Mon, 11 Nov 2024 22:21:58 +0530 [thread overview]
Message-ID: <c15d4a80-2f27-4588-af87-9cf7cf3ad79e@amd.com> (raw)
In-Reply-To: <71a72bcc-ba85-4f86-9d41-cccfd433fa09@paulmck-laptop>
On 11/11/2024 8:56 PM, Paul E. McKenney wrote:
> On Mon, Nov 11, 2024 at 06:24:58PM +0530, Neeraj Upadhyay wrote:
>>
>>>
>>> /*
>>> - * Returns approximate total of the readers' ->srcu_lock_count[] values
>>> - * for the rank of per-CPU counters specified by idx.
>>> + * Computes approximate total of the readers' ->srcu_lock_count[] values
>>> + * for the rank of per-CPU counters specified by idx, and returns true if
>>> + * the caller did the proper barrier (gp), and if the count of the locks
>>> + * matches that of the unlocks passed in.
>>> */
>>> -static unsigned long srcu_readers_lock_idx(struct srcu_struct *ssp, int idx)
>>> +static bool srcu_readers_lock_idx(struct srcu_struct *ssp, int idx, bool gp, unsigned long unlocks)
>>> {
>>> int cpu;
>>> + unsigned long mask = 0;
>>> unsigned long sum = 0;
>>>
>>> for_each_possible_cpu(cpu) {
>>> struct srcu_data *sdp = per_cpu_ptr(ssp->sda, cpu);
>>>
>>> sum += atomic_long_read(&sdp->srcu_lock_count[idx]);
>>> + if (IS_ENABLED(CONFIG_PROVE_RCU))
>>> + mask = mask | READ_ONCE(sdp->srcu_reader_flavor);
>>> }
>>> - return sum;
>>> + WARN_ONCE(IS_ENABLED(CONFIG_PROVE_RCU) && (mask & (mask - 1)),
>>> + "Mixed reader flavors for srcu_struct at %ps.\n", ssp);
>>
>> I am trying to understand the (unlikely) case where synchronize_srcu() is done before any
>> srcu reader lock/unlock lite call is done. Can new SRCU readers fail to observe the
>> updates?
>
> If a SRCU reader fail to observe the index flip, then isn't it the case
> that the synchronize_rcu() invoked from srcu_readers_active_idx_check()
> must wait on it?
>
Below is the sequence of operations I was thinking of, where at step 4 CPU2
reads old pointer
ptr = old
CPU1 CPU2
1. Update ptr = new
2. synchronize_srcu()
<Does not use synchronize_rcu()
as SRCU_READ_FLAVOR_LITE is not
set for any sdp as srcu_read_lock_lite()
hasn't been called by any CPU>
3. srcu_read_lock_lite()
<No smp_mb() ordering>
4. Can read ptr == old ?
>>> + if (mask & SRCU_READ_FLAVOR_LITE && !gp)
>>> + return false;
>>
>> So, srcu_readers_active_idx_check() can potentially return false for very long
>> time, until the CPU executing srcu_readers_active_idx_check() does
>> at least one read lock/unlock lite call?
>
> That is correct. The theory is that until after an srcu_read_lock_lite()
> has executed, there is no need to wait on it. Does the practice match the
> theory in this case, or is there some sequence of events that I missed?
>
Below sequence
CPU1 CPU2
1. srcu_read_lock_lite()
2. srcu_read_unlock_lite()
3. synchronize_srcu()
3.1 srcu_readers_lock_idx() is
called with gp = false as
srcu_read_lock_lite() was never
called on this CPU for this
srcu_struct. So
ssp->sda->srcu_reader_flavor is not
set for CPU1's sda.
3.2 Inside srcu_readers_lock_idx()
"mask" contains SRCU_READ_FLAVOR_LITE
as CPU2's sdp->srcu_reader_flavor has it.
3.3 CPU1 keeps returning false from
below check until CPU1 does at least
one srcu_read_lock_lite() call or
the thread migrates.
if (mask & SRCU_READ_FLAVOR_LITE && !gp)
return false;
>>> + return sum == unlocks;
>>> }
>>>
>>> /*
>>> @@ -473,6 +482,7 @@ static unsigned long srcu_readers_unlock_idx(struct srcu_struct *ssp, int idx)
>>> */
>>> static bool srcu_readers_active_idx_check(struct srcu_struct *ssp, int idx)
>>> {
>>> + bool did_gp = !!(raw_cpu_read(ssp->sda->srcu_reader_flavor) & SRCU_READ_FLAVOR_LITE);
>>
>> sda->srcu_reader_flavor is only set when CONFIG_PROVE_RCU is enabled. But we
>> need the reader flavor information for srcu lite variant to work. So, lite
>> variant does not work when CONFIG_PROVE_RCU is disabled. Am I missing something
>> obvious here?
>
> At first glance, it appears that I am the one who missed something obvious.
> Including in testing, which failed to uncover this issue.
>
> Thank you for the careful reviews!
>
Sure thing, no problem!
- Neeraj
> Thanx, Paul
>
>> - Neeraj
>>
>>> unsigned long unlocks;
>>>
>>> unlocks = srcu_readers_unlock_idx(ssp, idx);
>>> @@ -482,13 +492,16 @@ static bool srcu_readers_active_idx_check(struct srcu_struct *ssp, int idx)
>>> * unlock is counted. Needs to be a smp_mb() as the read side may
>>> * contain a read from a variable that is written to before the
>>> * synchronize_srcu() in the write side. In this case smp_mb()s
>>> - * A and B act like the store buffering pattern.
>>> + * A and B (or X and Y) act like the store buffering pattern.
>>> *
>>> - * This smp_mb() also pairs with smp_mb() C to prevent accesses
>>> - * after the synchronize_srcu() from being executed before the
>>> - * grace period ends.
>>> + * This smp_mb() also pairs with smp_mb() C (or, in the case of X,
>>> + * Z) to prevent accesses after the synchronize_srcu() from being
>>> + * executed before the grace period ends.
>>> */
>>> - smp_mb(); /* A */
>>> + if (!did_gp)
>>> + smp_mb(); /* A */
>>> + else
>>> + synchronize_rcu(); /* X */
>>>
>>> /*
>>> * If the locks are the same as the unlocks, then there must have
>>> @@ -546,7 +559,7 @@ static bool srcu_readers_active_idx_check(struct srcu_struct *ssp, int idx)
>>> * which are unlikely to be configured with an address space fully
>>> * populated with memory, at least not anytime soon.
>>> */
>>> - return srcu_readers_lock_idx(ssp, idx) == unlocks;
>>> + return srcu_readers_lock_idx(ssp, idx, did_gp, unlocks);
>>> }
>>>
>>
next prev parent reply other threads:[~2024-11-11 16:52 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <ff986c31-9cd0-45e5-aa31-9aedf582325f@paulmck-laptop>
2024-10-09 18:07 ` [PATCH rcu 01/12] srcu: Rename srcu_might_be_idle() to srcu_should_expedite() Paul E. McKenney
2024-10-14 8:56 ` Neeraj Upadhyay
2024-10-09 18:07 ` [PATCH rcu 02/12] srcu: Introduce srcu_gp_is_expedited() helper function Paul E. McKenney
2024-10-14 8:57 ` Neeraj Upadhyay
2024-10-09 18:07 ` [PATCH rcu 03/12] srcu: Renaming in preparation for additional reader flavor Paul E. McKenney
2024-10-14 9:10 ` Neeraj Upadhyay
2024-10-14 16:52 ` Paul E. McKenney
2024-10-15 3:25 ` Neeraj Upadhyay
2024-10-09 18:07 ` [PATCH rcu 04/12] srcu: Bit manipulation changes " Paul E. McKenney
2024-10-14 9:12 ` Neeraj Upadhyay
2024-10-14 16:51 ` Paul E. McKenney
2024-10-15 3:32 ` Neeraj Upadhyay
2024-10-09 18:07 ` [PATCH rcu 05/12] srcu: Standardize srcu_data pointers to "sdp" and similar Paul E. McKenney
2024-10-14 9:15 ` Neeraj Upadhyay
2024-10-14 16:49 ` Paul E. McKenney
2024-10-15 0:29 ` Paul E. McKenney
2024-10-15 5:10 ` Neeraj Upadhyay
2024-10-09 18:07 ` [PATCH rcu 06/12] srcu: Add srcu_read_lock_lite() and srcu_read_unlock_lite() Paul E. McKenney
2024-11-11 12:54 ` Neeraj Upadhyay
2024-11-11 15:26 ` Paul E. McKenney
2024-11-11 16:51 ` Neeraj Upadhyay [this message]
2024-11-12 1:28 ` Paul E. McKenney
2024-11-12 3:15 ` Neeraj Upadhyay
2024-10-09 18:07 ` [PATCH rcu 07/12] srcu: Allow inlining of __srcu_read_{,un}lock_lite() Paul E. McKenney
2024-10-09 18:07 ` [PATCH rcu 08/12] rcutorture: Expand RCUTORTURE_RDR_MASK_[12] to eight bits Paul E. McKenney
2024-10-09 18:07 ` [PATCH rcu 09/12] rcutorture: Add reader_flavor parameter for SRCU readers Paul E. McKenney
2024-10-09 18:07 ` [PATCH rcu 10/12] rcutorture: Add srcu_read_lock_lite() support to rcutorture.reader_flavor Paul E. McKenney
2024-10-09 18:07 ` [PATCH rcu 11/12] rcutorture: Add light-weight SRCU scenario Paul E. McKenney
2024-10-09 18:07 ` [PATCH rcu 12/12] refscale: Add srcu_read_lock_lite() support using "srcu-lite" Paul E. McKenney
2024-10-10 15:38 ` Frederic Weisbecker
2024-10-10 16:06 ` Paul E. McKenney
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=c15d4a80-2f27-4588-af87-9cf7cf3ad79e@amd.com \
--to=neeraj.upadhyay@amd.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=frederic@kernel.org \
--cc=kent.overstreet@linux.dev \
--cc=kernel-team@meta.com \
--cc=linux-kernel@vger.kernel.org \
--cc=oliver.sang@intel.com \
--cc=paulmck@kernel.org \
--cc=peterz@infradead.org \
--cc=rcu@vger.kernel.org \
--cc=rostedt@goodmis.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