* [PATCH 0/3] rcu/nocb updates v2
@ 2023-11-15 19:11 Frederic Weisbecker
2023-11-15 19:11 ` [PATCH 1/3] rcu: Rename jiffies_till_flush to jiffies_lazy_flush Frederic Weisbecker
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Frederic Weisbecker @ 2023-11-15 19:11 UTC (permalink / raw)
To: LKML
Cc: Frederic Weisbecker, Boqun Feng, Joel Fernandes, Neeraj Upadhyay,
Uladzislau Rezki, Zqiang, rcu, Paul E. McKenney
Hi,
Here is a re-issue of some leftovers from a previous patchset.
Changes since last time:
1) Use rcu_get_jiffies_lazy_flush() instead of the raw variable (thanks Joel)
2) Further comment ordering expectations between grace period end and
callbacks execution.
Thanks.
Frederic Weisbecker (3):
rcu: Rename jiffies_till_flush to jiffies_lazy_flush
rcu/nocb: Remove needless LOAD-ACQUIRE
rcu/nocb: Remove needless full barrier after callback advancing
kernel/rcu/rcu.h | 8 ++++----
kernel/rcu/rcuscale.c | 6 +++---
kernel/rcu/tree.c | 6 ++++++
kernel/rcu/tree_nocb.h | 26 ++++++++++++--------------
4 files changed, 25 insertions(+), 21 deletions(-)
--
2.42.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] rcu: Rename jiffies_till_flush to jiffies_lazy_flush
2023-11-15 19:11 [PATCH 0/3] rcu/nocb updates v2 Frederic Weisbecker
@ 2023-11-15 19:11 ` Frederic Weisbecker
2023-11-15 19:11 ` [PATCH 2/3] rcu/nocb: Remove needless LOAD-ACQUIRE Frederic Weisbecker
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Frederic Weisbecker @ 2023-11-15 19:11 UTC (permalink / raw)
To: LKML
Cc: Frederic Weisbecker, Boqun Feng, Joel Fernandes, Neeraj Upadhyay,
Uladzislau Rezki, Zqiang, rcu, Paul E. McKenney
The variable name jiffies_till_flush is too generic and therefore:
* It may shadow a global variable
* It doesn't tell on what it operates
Make the name more precise, along with the related APIs.
Reviewed-by: Joel Fernandes (Google) <joel@joelfernandes.org>
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
---
kernel/rcu/rcu.h | 8 ++++----
kernel/rcu/rcuscale.c | 6 +++---
kernel/rcu/tree_nocb.h | 22 +++++++++++-----------
3 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h
index b531c33e9545..ff41423cd61c 100644
--- a/kernel/rcu/rcu.h
+++ b/kernel/rcu/rcu.h
@@ -541,11 +541,11 @@ enum rcutorture_type {
};
#if defined(CONFIG_RCU_LAZY)
-unsigned long rcu_lazy_get_jiffies_till_flush(void);
-void rcu_lazy_set_jiffies_till_flush(unsigned long j);
+unsigned long rcu_get_jiffies_lazy_flush(void);
+void rcu_set_jiffies_lazy_flush(unsigned long j);
#else
-static inline unsigned long rcu_lazy_get_jiffies_till_flush(void) { return 0; }
-static inline void rcu_lazy_set_jiffies_till_flush(unsigned long j) { }
+static inline unsigned long rcu_get_jiffies_lazy_flush(void) { return 0; }
+static inline void rcu_set_jiffies_lazy_flush(unsigned long j) { }
#endif
#if defined(CONFIG_TREE_RCU)
diff --git a/kernel/rcu/rcuscale.c b/kernel/rcu/rcuscale.c
index ffdb30495e3c..8db4fedaaa1e 100644
--- a/kernel/rcu/rcuscale.c
+++ b/kernel/rcu/rcuscale.c
@@ -764,9 +764,9 @@ kfree_scale_init(void)
if (kfree_by_call_rcu) {
/* do a test to check the timeout. */
- orig_jif = rcu_lazy_get_jiffies_till_flush();
+ orig_jif = rcu_get_jiffies_lazy_flush();
- rcu_lazy_set_jiffies_till_flush(2 * HZ);
+ rcu_set_jiffies_lazy_flush(2 * HZ);
rcu_barrier();
jif_start = jiffies;
@@ -775,7 +775,7 @@ kfree_scale_init(void)
smp_cond_load_relaxed(&rcu_lazy_test1_cb_called, VAL == 1);
- rcu_lazy_set_jiffies_till_flush(orig_jif);
+ rcu_set_jiffies_lazy_flush(orig_jif);
if (WARN_ON_ONCE(jiffies_at_lazy_cb - jif_start < 2 * HZ)) {
pr_alert("ERROR: call_rcu() CBs are not being lazy as expected!\n");
diff --git a/kernel/rcu/tree_nocb.h b/kernel/rcu/tree_nocb.h
index 4efbf7333d4e..aecef51166c7 100644
--- a/kernel/rcu/tree_nocb.h
+++ b/kernel/rcu/tree_nocb.h
@@ -256,6 +256,7 @@ static bool wake_nocb_gp(struct rcu_data *rdp, bool force)
return __wake_nocb_gp(rdp_gp, rdp, force, flags);
}
+#ifdef CONFIG_RCU_LAZY
/*
* LAZY_FLUSH_JIFFIES decides the maximum amount of time that
* can elapse before lazy callbacks are flushed. Lazy callbacks
@@ -264,21 +265,20 @@ static bool wake_nocb_gp(struct rcu_data *rdp, bool force)
* left unsubmitted to RCU after those many jiffies.
*/
#define LAZY_FLUSH_JIFFIES (10 * HZ)
-static unsigned long jiffies_till_flush = LAZY_FLUSH_JIFFIES;
+static unsigned long jiffies_lazy_flush = LAZY_FLUSH_JIFFIES;
-#ifdef CONFIG_RCU_LAZY
// To be called only from test code.
-void rcu_lazy_set_jiffies_till_flush(unsigned long jif)
+void rcu_set_jiffies_lazy_flush(unsigned long jif)
{
- jiffies_till_flush = jif;
+ jiffies_lazy_flush = jif;
}
-EXPORT_SYMBOL(rcu_lazy_set_jiffies_till_flush);
+EXPORT_SYMBOL(rcu_set_jiffies_lazy_flush);
-unsigned long rcu_lazy_get_jiffies_till_flush(void)
+unsigned long rcu_get_jiffies_lazy_flush(void)
{
- return jiffies_till_flush;
+ return jiffies_lazy_flush;
}
-EXPORT_SYMBOL(rcu_lazy_get_jiffies_till_flush);
+EXPORT_SYMBOL(rcu_get_jiffies_lazy_flush);
#endif
/*
@@ -299,7 +299,7 @@ static void wake_nocb_gp_defer(struct rcu_data *rdp, int waketype,
*/
if (waketype == RCU_NOCB_WAKE_LAZY &&
rdp->nocb_defer_wakeup == RCU_NOCB_WAKE_NOT) {
- mod_timer(&rdp_gp->nocb_timer, jiffies + jiffies_till_flush);
+ mod_timer(&rdp_gp->nocb_timer, jiffies + rcu_get_jiffies_lazy_flush());
WRITE_ONCE(rdp_gp->nocb_defer_wakeup, waketype);
} else if (waketype == RCU_NOCB_WAKE_BYPASS) {
mod_timer(&rdp_gp->nocb_timer, jiffies + 2);
@@ -482,7 +482,7 @@ static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
// flush ->nocb_bypass to ->cblist.
if ((ncbs && !bypass_is_lazy && j != READ_ONCE(rdp->nocb_bypass_first)) ||
(ncbs && bypass_is_lazy &&
- (time_after(j, READ_ONCE(rdp->nocb_bypass_first) + jiffies_till_flush))) ||
+ (time_after(j, READ_ONCE(rdp->nocb_bypass_first) + rcu_get_jiffies_lazy_flush()))) ||
ncbs >= qhimark) {
rcu_nocb_lock(rdp);
*was_alldone = !rcu_segcblist_pend_cbs(&rdp->cblist);
@@ -723,7 +723,7 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
lazy_ncbs = READ_ONCE(rdp->lazy_len);
if (bypass_ncbs && (lazy_ncbs == bypass_ncbs) &&
- (time_after(j, READ_ONCE(rdp->nocb_bypass_first) + jiffies_till_flush) ||
+ (time_after(j, READ_ONCE(rdp->nocb_bypass_first) + rcu_get_jiffies_lazy_flush()) ||
bypass_ncbs > 2 * qhimark)) {
flush_bypass = true;
} else if (bypass_ncbs && (lazy_ncbs != bypass_ncbs) &&
--
2.42.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/3] rcu/nocb: Remove needless LOAD-ACQUIRE
2023-11-15 19:11 [PATCH 0/3] rcu/nocb updates v2 Frederic Weisbecker
2023-11-15 19:11 ` [PATCH 1/3] rcu: Rename jiffies_till_flush to jiffies_lazy_flush Frederic Weisbecker
@ 2023-11-15 19:11 ` Frederic Weisbecker
2023-11-15 19:11 ` [PATCH 3/3] rcu/nocb: Remove needless full barrier after callback advancing Frederic Weisbecker
2023-12-05 4:20 ` [PATCH 0/3] rcu/nocb updates v2 Paul E. McKenney
3 siblings, 0 replies; 5+ messages in thread
From: Frederic Weisbecker @ 2023-11-15 19:11 UTC (permalink / raw)
To: LKML
Cc: Frederic Weisbecker, Boqun Feng, Joel Fernandes, Neeraj Upadhyay,
Uladzislau Rezki, Zqiang, rcu, Paul E. McKenney
The LOAD-ACQUIRE access performed on rdp->nocb_cb_sleep advertizes
ordering callback execution against grace period completion. However
this is contradicted by the following:
* This LOAD-ACQUIRE doesn't pair with anything. The only counterpart
barrier that can be found is the smp_mb() placed after callbacks
advancing in nocb_gp_wait(). However the barrier is placed _after_
->nocb_cb_sleep write.
* Callbacks can be concurrently advanced between the LOAD-ACQUIRE on
->nocb_cb_sleep and the call to rcu_segcblist_extract_done_cbs() in
rcu_do_batch(), making any ordering based on ->nocb_cb_sleep broken.
* Both rcu_segcblist_extract_done_cbs() and rcu_advance_cbs() are called
under the nocb_lock, the latter hereby providing already the desired
ACQUIRE semantics.
Therefore it is safe to access ->nocb_cb_sleep with a simple compiler
barrier.
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
---
kernel/rcu/tree_nocb.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/kernel/rcu/tree_nocb.h b/kernel/rcu/tree_nocb.h
index aecef51166c7..eb27878d46f1 100644
--- a/kernel/rcu/tree_nocb.h
+++ b/kernel/rcu/tree_nocb.h
@@ -933,8 +933,7 @@ static void nocb_cb_wait(struct rcu_data *rdp)
swait_event_interruptible_exclusive(rdp->nocb_cb_wq,
nocb_cb_wait_cond(rdp));
- // VVV Ensure CB invocation follows _sleep test.
- if (smp_load_acquire(&rdp->nocb_cb_sleep)) { // ^^^
+ if (READ_ONCE(rdp->nocb_cb_sleep)) {
WARN_ON(signal_pending(current));
trace_rcu_nocb_wake(rcu_state.name, rdp->cpu, TPS("WokeEmpty"));
}
--
2.42.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] rcu/nocb: Remove needless full barrier after callback advancing
2023-11-15 19:11 [PATCH 0/3] rcu/nocb updates v2 Frederic Weisbecker
2023-11-15 19:11 ` [PATCH 1/3] rcu: Rename jiffies_till_flush to jiffies_lazy_flush Frederic Weisbecker
2023-11-15 19:11 ` [PATCH 2/3] rcu/nocb: Remove needless LOAD-ACQUIRE Frederic Weisbecker
@ 2023-11-15 19:11 ` Frederic Weisbecker
2023-12-05 4:20 ` [PATCH 0/3] rcu/nocb updates v2 Paul E. McKenney
3 siblings, 0 replies; 5+ messages in thread
From: Frederic Weisbecker @ 2023-11-15 19:11 UTC (permalink / raw)
To: LKML
Cc: Frederic Weisbecker, Boqun Feng, Joel Fernandes, Neeraj Upadhyay,
Uladzislau Rezki, Zqiang, rcu, Paul E. McKenney
A full barrier is issued from nocb_gp_wait() upon callbacks advancing
to order grace period completion with callbacks execution.
However these two events are already ordered by the
smp_mb__after_unlock_lock() barrier within the call to
raw_spin_lock_rcu_node() that is necessary for callbacks advancing to
happen.
The following litmus test shows the kind of guarantee that this barrier
provides:
C smp_mb__after_unlock_lock
{}
// rcu_gp_cleanup()
P0(spinlock_t *rnp_lock, int *gpnum)
{
// Grace period cleanup increase gp sequence number
spin_lock(rnp_lock);
WRITE_ONCE(*gpnum, 1);
spin_unlock(rnp_lock);
}
// nocb_gp_wait()
P1(spinlock_t *rnp_lock, spinlock_t *nocb_lock, int *gpnum, int *cb_ready)
{
int r1;
// Call rcu_advance_cbs() from nocb_gp_wait()
spin_lock(nocb_lock);
spin_lock(rnp_lock);
smp_mb__after_unlock_lock();
r1 = READ_ONCE(*gpnum);
WRITE_ONCE(*cb_ready, 1);
spin_unlock(rnp_lock);
spin_unlock(nocb_lock);
}
// nocb_cb_wait()
P2(spinlock_t *nocb_lock, int *cb_ready, int *cb_executed)
{
int r2;
// rcu_do_batch() -> rcu_segcblist_extract_done_cbs()
spin_lock(nocb_lock);
r2 = READ_ONCE(*cb_ready);
spin_unlock(nocb_lock);
// Actual callback execution
WRITE_ONCE(*cb_executed, 1);
}
P3(int *cb_executed, int *gpnum)
{
int r3;
WRITE_ONCE(*cb_executed, 2);
smp_mb();
r3 = READ_ONCE(*gpnum);
}
exists (1:r1=1 /\ 2:r2=1 /\ cb_executed=2 /\ 3:r3=0) (* Bad outcome. *)
Here the bad outcome only occurs if the smp_mb__after_unlock_lock() is
removed. This barrier orders the grace period completion against
callbacks advancing and even later callbacks invocation, thanks to the
opportunistic propagation via the ->nocb_lock to nocb_cb_wait().
Therefore the smp_mb() placed after callbacks advancing can be safely
removed.
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
---
kernel/rcu/tree.c | 6 ++++++
kernel/rcu/tree_nocb.h | 1 -
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 3ac3c846105f..c557302fc4f5 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -2113,6 +2113,12 @@ static void rcu_do_batch(struct rcu_data *rdp)
* Extract the list of ready callbacks, disabling IRQs to prevent
* races with call_rcu() from interrupt handlers. Leave the
* callback counts, as rcu_barrier() needs to be conservative.
+ *
+ * Callbacks execution is fully ordered against preceding grace period
+ * completion (materialized by rnp->gp_seq update) thanks to the
+ * smp_mb__after_unlock_lock() upon node locking required for callbacks
+ * advancing. In NOCB mode this ordering is then further relayed through
+ * the nocb locking that protects both callbacks advancing and extraction.
*/
rcu_nocb_lock_irqsave(rdp, flags);
WARN_ON_ONCE(cpu_is_offline(smp_processor_id()));
diff --git a/kernel/rcu/tree_nocb.h b/kernel/rcu/tree_nocb.h
index eb27878d46f1..d82f96a66600 100644
--- a/kernel/rcu/tree_nocb.h
+++ b/kernel/rcu/tree_nocb.h
@@ -779,7 +779,6 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
if (rcu_segcblist_ready_cbs(&rdp->cblist)) {
needwake = rdp->nocb_cb_sleep;
WRITE_ONCE(rdp->nocb_cb_sleep, false);
- smp_mb(); /* CB invocation -after- GP end. */
} else {
needwake = false;
}
--
2.42.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 0/3] rcu/nocb updates v2
2023-11-15 19:11 [PATCH 0/3] rcu/nocb updates v2 Frederic Weisbecker
` (2 preceding siblings ...)
2023-11-15 19:11 ` [PATCH 3/3] rcu/nocb: Remove needless full barrier after callback advancing Frederic Weisbecker
@ 2023-12-05 4:20 ` Paul E. McKenney
3 siblings, 0 replies; 5+ messages in thread
From: Paul E. McKenney @ 2023-12-05 4:20 UTC (permalink / raw)
To: Frederic Weisbecker
Cc: LKML, Boqun Feng, Joel Fernandes, Neeraj Upadhyay,
Uladzislau Rezki, Zqiang, rcu
On Wed, Nov 15, 2023 at 02:11:25PM -0500, Frederic Weisbecker wrote:
> Hi,
>
> Here is a re-issue of some leftovers from a previous patchset.
> Changes since last time:
>
> 1) Use rcu_get_jiffies_lazy_flush() instead of the raw variable (thanks Joel)
> 2) Further comment ordering expectations between grace period end and
> callbacks execution.
Hearing no objections, I have queued these for further review and testing.
Thanx, Paul
> Thanks.
>
> Frederic Weisbecker (3):
> rcu: Rename jiffies_till_flush to jiffies_lazy_flush
> rcu/nocb: Remove needless LOAD-ACQUIRE
> rcu/nocb: Remove needless full barrier after callback advancing
>
> kernel/rcu/rcu.h | 8 ++++----
> kernel/rcu/rcuscale.c | 6 +++---
> kernel/rcu/tree.c | 6 ++++++
> kernel/rcu/tree_nocb.h | 26 ++++++++++++--------------
> 4 files changed, 25 insertions(+), 21 deletions(-)
>
> --
> 2.42.1
>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2023-12-05 4:20 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-11-15 19:11 [PATCH 0/3] rcu/nocb updates v2 Frederic Weisbecker
2023-11-15 19:11 ` [PATCH 1/3] rcu: Rename jiffies_till_flush to jiffies_lazy_flush Frederic Weisbecker
2023-11-15 19:11 ` [PATCH 2/3] rcu/nocb: Remove needless LOAD-ACQUIRE Frederic Weisbecker
2023-11-15 19:11 ` [PATCH 3/3] rcu/nocb: Remove needless full barrier after callback advancing Frederic Weisbecker
2023-12-05 4:20 ` [PATCH 0/3] rcu/nocb updates v2 Paul E. McKenney
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.