Miscellaneous fixes for 4.4
Subsystems (6)
cover Miscellaneous fixes for 4.4
Hello!
This series contains miscellaneous fixes:
1. Export sched_setscheduler_nocheck() so that the new locktorture
rtmutex_lock tests can be run as modules, courtesy of Davidlohr Bueso.
2. Use rcu_callback_t in call_rcu*() and friends to improve
readability and to make cscope able to find them, courtesy of Boqun Feng.
3. Use call_rcu_func_t to replace explicit type equivalents when
defining RCU callback functions, courtesy of Boqun Feng.
4. Don't unnecessarily disable preemption for Tiny and Tree
RCU readers (only for preemptible RCU readers), courtesy of Boqun Feng.
5. Eliminate boot-time panic when a silly boot-time fanout is
specified.
6. Add online/offline info to help debug stall-warning messages.
7. Move preemption disabling out of __srcu_read_lock() into
srcu_read_lock().
8. Finish folding ->fqs_state into ->gp_state, courtesy of Petr Mladek.
9. Correct comment for values of ->gp_state field.
10. Add rcu_pointer_handoff() to allow explicit marking of handing
off protection from RCU to some other means, such as locking or reference counting.
11. Make list_entry_rcu() use lockless_dereference(), courtesy
of Patrick Marlier. Despite the fact that this patch does nothing more than eliminate a single store and a single load of an unshared stack variable it nevertheless manages to provide a measurable performance increase:
http://people.csail.mit.edu/amatveev/RLU_SOSP2015.pdf
12. Remove deprecated rcu_lockdep_assert().
Thanx, Paul
------------------------------------------------------------------------
b/Documentation/kernel-parameters.txt | 9 +++-- b/include/linux/list.h | 5 +- b/include/linux/list_bl.h | 5 +- b/include/linux/list_nulls.h | 3 + b/include/linux/rculist.h | 5 -- b/include/linux/rcupdate.h | 59 +++++++++++++++++----------------- b/include/linux/rcutiny.h | 3 + b/include/linux/rcutree.h | 2 - b/include/linux/srcu.h | 5 ++ b/kernel/exit.c | 2 + b/kernel/rcu/rcutorture.c | 6 +-- b/kernel/rcu/srcu.c | 4 -- b/kernel/rcu/tiny.c | 8 ++-- b/kernel/rcu/tree.c | 55 ++++++++++++++++++------------- b/kernel/rcu/tree.h | 21 +++--------- b/kernel/rcu/tree_plugin.h | 10 ++++- b/kernel/rcu/tree_trace.c | 2 - b/kernel/rcu/update.c | 2 - b/kernel/sched/core.c | 1 19 files changed, 111 insertions(+), 96 deletions(-)
PATCH 6/13 rcu: Add online/offline info to stall warning message
In reply to Paul E. McKenneyThis commit makes the RCU CPU stall warning message print online/offline indications immediately after the CPU number. A "?" indicates global offline, a "," global online, and a "!" indicates RCU believes that the CPU is offline and "." otherwise, both right after the CPU number. So for CPU 10, you would normally see "10,.:" indicating that everything believes that the CPU is online.
--- kernel/rcu/tree_plugin.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
kernel/rcu/tree_plugin.h +6 -2
@@ -1702,8 +1702,12 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu) ticks_value = rsp->gpnum - rdp->gpnum; }print_cpu_stall_fast_no_hz (fast_no_hz, cpu); - pr_err("\t%d: (%lu %s) idle=%03x/%llx/%d softirq=%u/%u fqs=%ld %s\n", - cpu, ticks_value, ticks_title, + pr_err("\t%d-%c%c%c: (%lu %s) idle=%03x/%llx/%d softirq=%u/%u fqs=%ld %s\n", + cpu, + "O."[!!cpu_online(cpu)], + "o."[!!(rdp->grpmask & rdp->mynode->qsmaskinit)], + "N."[!!(rdp->grpmask & rdp->mynode->qsmaskinitnext)], + ticks_value, ticks_title, atomic_read(&rdtp->dynticks) & 0xfff, rdtp->dynticks_nesting, rdtp->dynticks_nmi_nesting, rdp->softirq_snap, kstat_softirqs_cpu(RCU_SOFTIRQ, cpu),
Signature · 1 line
2.5.2
PATCH 8/13 rcu: Finish folding ->fqs_state into ->gp_state
In reply to Paul E. McKenneyFrom: Petr Mladek <[email protected]>
Commit commit 4cdfc175c25c89ee ("rcu: Move quiescent-state forcing into kthread") started the process of folding the old ->fqs_state into ->gp_state, but did not complete it. This situation does not cause any malfunction, but can result in extremely confusing trace output. This commit completes this task of eliminating ->fqs_state in favor of ->gp_state.
The old ->fqs_state was also used to decide when to collect dyntick-idle snapshots. For this purpose, we add a boolean variable into the kthread, which is set on the first call to rcu_gp_fqs() for a given grace period and clear otherwise.
--- kernel/rcu/tree.c | 18 ++++++++---------- kernel/rcu/tree.h | 14 +++----------- kernel/rcu/tree_trace.c | 2 +- 3 files changed, 12 insertions(+), 22 deletions(-)
kernel/rcu/tree.c +8 -10
@@ -98,7 +98,7 @@ struct rcu_state sname##_state = { \ .level = { &sname##_state.node[0] }, \ .rda = &sname##_data, \ .call = cr, \ - .fqs_state = RCU_GP_IDLE, \ + .gp_state = RCU_GP_IDLE, \ .gpnum = 0UL - 300UL, \ .completed = 0UL - 300UL, \ .orphan_lock = __RAW_SPIN_LOCK_UNLOCKED(&sname##_state.orphan_lock), \
@@ -1936,16 +1936,15 @@ static bool rcu_gp_fqs_check_wake(struct rcu_state *rsp, int *gfp)/* * Do one round of quiescent-state forcing. */ -static int rcu_gp_fqs (struct rcu_state *rsp,int fqs_state_in) +static void rcu_gp_fqs (struct rcu_state *rsp,bool first_time) { -int fqs_state = fqs_state_in;bool isidle = false;unsigned long maxj;struct rcu_node *rnp =rcu_get_root (rsp);WRITE_ONCE (rsp->gp_activity, jiffies); rsp->n_force_qs++; -if (fqs_state ==RCU_SAVE_DYNTICK ) { +if (first_time) {/* Collect dyntick-idle snapshots. */ if (is_sysidle_rcu_state (rsp)) { isidle = true;
@@ -1954,7 +1953,6 @@ static int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in)force_qs_rnp (rsp, dyntick_save_progress_counter, &isidle, &maxj);rcu_sysidle_report_gp (rsp, isidle, maxj); - fqs_state =RCU_FORCE_QS ; }else {/* Handle dyntick-idle and offline CPUs. */ isidle = true;
@@ -1968,7 +1966,6 @@ static int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in) READ_ONCE(rsp->gp_flags) & ~RCU_GP_FLAG_FQS);raw_spin_unlock_irq (&rnp->lock); } -return fqs_state; }/*
@@ -2032,7 +2029,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)/* Declare grace period done. */ WRITE_ONCE (rsp->completed, rsp->gpnum);trace_rcu_grace_period (rsp->name, rsp->completed,TPS ("end" )); - rsp->fqs_state =RCU_GP_IDLE ; + rsp->gp_state =RCU_GP_IDLE ; rdp =this_cpu_ptr (rsp->rda);/* Advance CBs to reduce false positives below. */ needgp =rcu_advance_cbs (rsp, rnp, rdp) || needgp;
@@ -2050,7 +2047,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)*/ static int __noreturn rcu_gp_kthread (void *arg) { -int fqs_state; +bool first_gp_fqs;int gf;unsigned long j;int ret;
@@ -2082,7 +2079,7 @@ static int __noreturn rcu_gp_kthread(void *arg) }/* Handle quiescent-state forcing. */ - fqs_state =RCU_SAVE_DYNTICK ; + first_gp_fqs = true; j = jiffies_till_first_fqs;if (j >HZ ) { j =HZ ;
@@ -2110,7 +2107,8 @@ static int __noreturn rcu_gp_kthread(void *arg)trace_rcu_grace_period (rsp->name,READ_ONCE (rsp->gpnum),TPS ("fqsstart" )); - fqs_state =rcu_gp_fqs (rsp, fqs_state); +rcu_gp_fqs (rsp, first_gp_fqs); + first_gp_fqs = false;trace_rcu_grace_period (rsp->name,READ_ONCE (rsp->gpnum),TPS ("fqsend" ));
kernel/rcu/tree.h +3 -11
@@ -412,13 +412,6 @@ struct rcu_data {struct rcu_state *rsp; }; -/* Values for fqs_state field in struct rcu_state. */ -#define RCU_GP_IDLE 0/* No grace period in progress. */ -#define RCU_GP_INIT 1/* Grace period being initialized. */ -#define RCU_SAVE_DYNTICK 2/* Need to scan dyntick state. */ -#define RCU_FORCE_QS 3/* Need to force quiescent state. */ -#define RCU_SIGNAL_INIT RCU_SAVE_DYNTICK -/* Values for nocb_defer_wakeup field in struct rcu_data. */ #define RCU_NOGP_WAKE_NOT 0#define RCU_NOGP_WAKE 1
@@ -468,9 +461,8 @@ struct rcu_state {/* The following fields are guarded by the root rcu_node's lock. */ -u8 fqs_state____cacheline_internodealigned_in_smp ; -/* Force QS state. */ -u8 boost;/* Subject to priority boost. */ +u8 boost____cacheline_internodealigned_in_smp ; +/* Subject to priority boost. */ unsigned long gpnum;/* Current gp number. */ unsigned long completed;/* # of last completed gp. */ struct task_struct *gp_kthread;/* Task for grace periods. */
@@ -538,7 +530,7 @@ struct rcu_state {#define RCU_GP_FLAG_FQS 0x2/* Need grace-period quiescent-state forcing. */ /* Values for rcu_state structure's gp_flags field. */ -#define RCU_GP_WAIT_INIT 0/* Initial state. */ +#define RCU_GP_IDLE 0/* Initial state and no GP in progress. */ #define RCU_GP_WAIT_GPS 1/* Wait for grace-period start. */ #define RCU_GP_DONE_GPS 2/* Wait done for grace-period start. */ #define RCU_GP_WAIT_FQS 3/* Wait for force-quiescent-state time. */
kernel/rcu/tree_trace.c +1 -1
@@ -268,7 +268,7 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) gpnum = rsp->gpnum;seq_printf (m,"c=%ld g=%ld s=%d jfq=%ld j=%x " ,ulong2long (rsp->completed),ulong2long (gpnum), - rsp->fqs_state, + rsp->gp_state, (long )(rsp->jiffies_force_qs - jiffies), (int )(jiffies &0xffff )); seq_printf(m, "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld/%ld\n",
Signature · 1 line
2.5.2
PATCH 11/13 rculist: Make list_entry_rcu() use lockless_dereference()
In reply to Paul E. McKenneyFrom: Patrick Marlier <[email protected]>
The current list_entry_rcu() implementation copies the pointer to a stack variable, then invokes rcu_dereference_raw() on it. This results in an additional store-load pair. Now, most compilers will emit normal store and load instructions, which might seem to be of negligible overhead, but this results in a load-hit-store situation that can cause surprisingly long pipeline stalls, even on modern microprocessors. The problem is that it takes time for the store to get the store buffer updated, which can delay the subsequent load, which immediately follows.
This commit therefore switches to the lockless_dereference() primitive, which does not expect the __rcu annotations (that are anyway not present in the list_head structure) and which, like rcu_dereference_raw(), does not check for an enclosing RCU read-side critical section. Most importantly, it does not copy the pointer, thus avoiding the load-hit-store overhead.
--- include/linux/rculist.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
include/linux/rculist.h +1 -4
@@ -247,10 +247,7 @@ static inline void list_splice_init_rcu(struct list_head *list,* primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). */ #define list_entry_rcu (ptr, type, member) \ -({ \ - typeof(*ptr) __rcu *__ptr = (typeof(*ptr) __rcu __force *)ptr; \ - container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member); \ -}) + container_of(lockless_dereference(ptr), type, member)/** * Where are list_empty_rcu() and list_first_entry_rcu()?
Signature · 1 line
2.5.2
PATCH 9/13 rcu: Correct comment for values of ->gp_state field
In reply to Paul E. McKenneyThis commit corrects the comment for the values of the ->gp_state field, which previously incorrectly said that these were for the ->gp_flags field.
--- kernel/rcu/tree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/rcu/tree.h +1 -1
@@ -529,7 +529,7 @@ struct rcu_state {#define RCU_GP_FLAG_INIT 0x1/* Need grace-period initialization. */ #define RCU_GP_FLAG_FQS 0x2/* Need grace-period quiescent-state forcing. */ -/* Values for rcu_state structure's gp_flags field. */ +/* Values for rcu_state structure's gp_state field. */ #define RCU_GP_IDLE 0/* Initial state and no GP in progress. */ #define RCU_GP_WAIT_GPS 1/* Wait for grace-period start. */ #define RCU_GP_DONE_GPS 2/* Wait done for grace-period start. */
Signature · 1 line
2.5.2
PATCH 1/13 sched: Export sched_setscheduler_nocheck
In reply to Paul E. McKenneyFrom: Davidlohr Bueso <[email protected]>
The new locktorture rtmutex_lock tests exercise priority boosting, which means that they need to set some tasks to real-time priority. To do this, they use sched_setscheduler_nocheck(). However, this is not exported to modules, which results in the following error when building locktorture as a module:
ERROR: "sched_setscheduler_nocheck" [kernel/locking/locktorture.ko] undefined!
This commit therefore adds an EXPORT_SYMBOL_GPL() to allow this function to be invoked from locktorture when built as a module.
--- kernel/sched/core.c | 1 + 1 file changed, 1 insertion(+)
kernel/sched/core.c +1 -0
@@ -4022,6 +4022,7 @@ int sched_setscheduler_nocheck(struct task_struct *p, int policy, {return _sched_setscheduler (p, policy, param, false); } +EXPORT_SYMBOL_GPL (sched_setscheduler_nocheck);static int do_sched_setscheduler (pid_t pid,int policy,struct sched_param __user *param)
Signature · 1 line
2.5.2
PATCH 4/13 rcu: Don't disable preemption for Tiny and Tree RCU readers
From: Boqun Feng <[email protected]>
Because preempt_disable() maps to barrier() for non-debug builds, it forces the compiler to spill and reload registers. Because Tree RCU and Tiny RCU now only appear in CONFIG_PREEMPT=n builds, these barrier() instances generate needless extra code for each instance of rcu_read_lock() and rcu_read_unlock(). This extra code slows down Tree RCU and bloats Tiny RCU.
This commit therefore removes the preempt_disable() and preempt_enable() from the non-preemptible implementations of __rcu_read_lock() and __rcu_read_unlock(), respectively. However, for debug purposes, preempt_disable() and preempt_enable() are still invoked if CONFIG_PREEMPT_COUNT=y, because this allows detection of sleeping inside atomic sections in non-preemptible kernels.
This is based on an earlier patch by Paul E. McKenney, fixing a bug encountered in kernels built with CONFIG_PREEMPT=n and CONFIG_PREEMPT_COUNT=y.
--- include/linux/rcupdate.h | 6 ++++-- include/linux/rcutiny.h | 1 + kernel/rcu/tree.c | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-)
include/linux/rcupdate.h +4 -2
@@ -297,12 +297,14 @@ void synchronize_rcu(void);static inline void __rcu_read_lock (void ) { -preempt_disable (); +if (IS_ENABLED (CONFIG_PREEMPT_COUNT )) +preempt_disable (); }static inline void __rcu_read_unlock (void ) { -preempt_enable (); +if (IS_ENABLED (CONFIG_PREEMPT_COUNT )) +preempt_enable (); }static inline void synchronize_rcu (void )
include/linux/rcutiny.h +1 -0
@@ -216,6 +216,7 @@ static inline bool rcu_is_watching(void)static inline void rcu_all_qs (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking across. */ }#endif /* __LINUX_RCUTINY_H */
kernel/rcu/tree.c +9 -0
@@ -337,12 +337,14 @@ static void rcu_momentary_dyntick_idle(void)*/ void rcu_note_context_switch (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ trace_rcu_utilization (TPS ("Start context switch" ));rcu_sched_qs ();rcu_preempt_note_context_switch ();if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();trace_rcu_utilization (TPS ("End context switch" )); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_note_context_switch);
@@ -353,12 +355,19 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch);* RCU flavors in desperate need of a quiescent state, which will normally * be none of them). Either way, do a lightweight quiescent state for * all RCU flavors. +* +* The barrier() calls are redundant in the common case when this is +* called externally, but just in case this is called from within this +* file. +* */ void rcu_all_qs (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();this_cpu_inc (rcu_qs_ctr); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_all_qs);
Signature · 1 line
2.5.2
PATCH 2/13 rcu: Use rcu_callback_t in call_rcu*() and friends
In reply to Paul E. McKenneyFrom: Boqun Feng <[email protected]>
As we now have rcu_callback_t typedefs as the type of rcu callbacks, we should use it in call_rcu*() and friends as the type of parameters. This could save us a few lines of code and make it clear which function requires an rcu callbacks rather than other callbacks as its argument.
Besides, this can also help cscope to generate a better database for code reading.
--- include/linux/rcupdate.h | 10 +++++----- include/linux/rcutiny.h | 2 +- include/linux/rcutree.h | 2 +- kernel/rcu/rcutorture.c | 4 ++-- kernel/rcu/srcu.c | 2 +- kernel/rcu/tiny.c | 8 ++++---- kernel/rcu/tree.c | 8 ++++---- kernel/rcu/tree.h | 2 +- kernel/rcu/tree_plugin.h | 2 +- kernel/rcu/update.c | 2 +- 10 files changed, 21 insertions(+), 21 deletions(-)
include/linux/rcupdate.h +5 -5
@@ -160,7 +160,7 @@ void do_trace_rcu_torture_read(const char *rcutorturename,* more than one CPU). */ void call_rcu (struct rcu_head *head, -void (*func)(struct rcu_head *head)); +rcu_callback_t func);#else /* #ifdef CONFIG_PREEMPT_RCU */
@@ -191,7 +191,7 @@ void call_rcu(struct rcu_head *head,* memory ordering guarantees. */ void call_rcu_bh (struct rcu_head *head, -void (*func)(struct rcu_head *head)); +rcu_callback_t func);/** * call_rcu_sched() - Queue an RCU for invocation after sched grace period.
@@ -213,7 +213,7 @@ void call_rcu_bh(struct rcu_head *head,* memory ordering guarantees. */ void call_rcu_sched (struct rcu_head *head, -void (*func)(struct rcu_head *rcu)); +rcu_callback_t func);void synchronize_sched (void );
@@ -274,7 +274,7 @@ do { \* See the description of call_rcu() for more detailed information on * memory ordering guarantees. */ -void call_rcu_tasks (struct rcu_head *head,void (*func)(struct rcu_head *head)); +void call_rcu_tasks (struct rcu_head *head,rcu_callback_t func);void synchronize_rcu_tasks (void );void rcu_barrier_tasks (void );
@@ -1065,7 +1065,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)#define __kfree_rcu (head, offset) \ do { \ BUILD_BUG_ON(!__is_kfree_rcu_offset(offset)); \ - kfree_call_rcu(head, (void (*)(struct rcu_head *))(unsigned long)(offset)); \ + kfree_call_rcu(head, (rcu_callback_t)(unsigned long)(offset)); \ } while (0)/**
include/linux/rcutiny.h +1 -1
@@ -83,7 +83,7 @@ static inline void synchronize_sched_expedited(void) }static inline void kfree_call_rcu (struct rcu_head *head, -void (*func)(struct rcu_head *rcu)) +rcu_callback_t func) {call_rcu (head, func); }
include/linux/rcutree.h +1 -1
@@ -48,7 +48,7 @@ void synchronize_rcu_bh(void);void synchronize_sched_expedited (void );void synchronize_rcu_expedited (void ); -void kfree_call_rcu (struct rcu_head *head,void (*func)(struct rcu_head *rcu)); +void kfree_call_rcu (struct rcu_head *head,rcu_callback_t func);/** * synchronize_rcu_bh_expedited - Brute-force RCU-bh grace period
kernel/rcu/rcutorture.c +2 -2
@@ -448,7 +448,7 @@ static void synchronize_rcu_busted(void) }static void -call_rcu_busted (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) +call_rcu_busted (struct rcu_head *head,rcu_callback_t func) {/* This is a deliberate bug for testing purposes only! */ func (head);
@@ -523,7 +523,7 @@ static void srcu_torture_synchronize(void) }static void srcu_torture_call (struct rcu_head *head, -void (*func)(struct rcu_head *head)) +rcu_callback_t func) {call_srcu (srcu_ctlp, head, func); }
kernel/rcu/srcu.c +1 -1
@@ -387,7 +387,7 @@ static void srcu_flip(struct srcu_struct *sp)* srcu_struct structure. */ void call_srcu (struct srcu_struct *sp,struct rcu_head *head, -void (*func)(struct rcu_head *head)) +rcu_callback_t func) {unsigned long flags;
kernel/rcu/tiny.c +4 -4
@@ -44,7 +44,7 @@ struct rcu_ctrlblk;static void __rcu_process_callbacks (struct rcu_ctrlblk *rcp);static void rcu_process_callbacks (struct softirq_action *unused);static void __call_rcu (struct rcu_head *head, -void (*func)(struct rcu_head *rcu), +rcu_callback_t func,struct rcu_ctrlblk *rcp);#include "tiny_plugin.h"
@@ -203,7 +203,7 @@ EXPORT_SYMBOL_GPL(synchronize_sched);* Helper function for call_rcu() and call_rcu_bh(). */ static void __call_rcu (struct rcu_head *head, -void (*func)(struct rcu_head *rcu), +rcu_callback_t func,struct rcu_ctrlblk *rcp) {unsigned long flags;
@@ -229,7 +229,7 @@ static void __call_rcu(struct rcu_head *head,* period. But since we have but one CPU, that would be after any * quiescent state. */ -void call_rcu_sched (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) +void call_rcu_sched (struct rcu_head *head,rcu_callback_t func) {__call_rcu (head, func, &rcu_sched_ctrlblk); }
@@ -239,7 +239,7 @@ EXPORT_SYMBOL_GPL(call_rcu_sched);* Post an RCU bottom-half callback to be invoked after any subsequent * quiescent state. */ -void call_rcu_bh (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) +void call_rcu_bh (struct rcu_head *head,rcu_callback_t func) {__call_rcu (head, func, &rcu_bh_ctrlblk); }
kernel/rcu/tree.c +4 -4
@@ -3017,7 +3017,7 @@ static void rcu_leak_callback(struct rcu_head *rhp)* is expected to specify a CPU. */ static void -__call_rcu (struct rcu_head *head,void (*func)(struct rcu_head *rcu), +__call_rcu (struct rcu_head *head,rcu_callback_t func,struct rcu_state *rsp,int cpu,bool lazy) {unsigned long flags;
@@ -3088,7 +3088,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),/* * Queue an RCU-sched callback for invocation after a grace period. */ -void call_rcu_sched (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) +void call_rcu_sched (struct rcu_head *head,rcu_callback_t func) {__call_rcu (head, func, &rcu_sched_state,-1 ,0 ); }
@@ -3097,7 +3097,7 @@ EXPORT_SYMBOL_GPL(call_rcu_sched);/* * Queue an RCU callback for invocation after a quicker grace period. */ -void call_rcu_bh (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) +void call_rcu_bh (struct rcu_head *head,rcu_callback_t func) {__call_rcu (head, func, &rcu_bh_state,-1 ,0 ); }
@@ -3111,7 +3111,7 @@ EXPORT_SYMBOL_GPL(call_rcu_bh);* function may only be called from __kfree_rcu(). */ void kfree_call_rcu (struct rcu_head *head, -void (*func)(struct rcu_head *rcu)) +rcu_callback_t func) {__call_rcu (head, func, rcu_state_p,-1 ,1 ); }
kernel/rcu/tree.h +1 -1
@@ -584,7 +584,7 @@ static void rcu_print_detail_task_stall(struct rcu_state *rsp);static int rcu_print_task_stall (struct rcu_node *rnp);static void rcu_preempt_check_blocked_tasks (struct rcu_node *rnp);static void rcu_preempt_check_callbacks (void ); -void call_rcu (struct rcu_head *head,void (*func)(struct rcu_head *rcu)); +void call_rcu (struct rcu_head *head,rcu_callback_t func);static void __init __rcu_init_preempt (void );static void rcu_initiate_boost (struct rcu_node *rnp,unsigned long flags);static void rcu_preempt_boost_start_gp (struct rcu_node *rnp);
kernel/rcu/tree_plugin.h +1 -1
@@ -500,7 +500,7 @@ static void rcu_preempt_do_callbacks(void)/* * Queue a preemptible-RCU callback for invocation after a grace period. */ -void call_rcu (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) +void call_rcu (struct rcu_head *head,rcu_callback_t func) {__call_rcu (head, func, rcu_state_p,-1 ,0 ); }
kernel/rcu/update.c +1 -1
@@ -534,7 +534,7 @@ static void rcu_spawn_tasks_kthread(void);* Post an RCU-tasks callback. First call must be from process context * after the scheduler if fully operational. */ -void call_rcu_tasks (struct rcu_head *rhp,void (*func)(struct rcu_head *rhp)) +void call_rcu_tasks (struct rcu_head *rhp,rcu_callback_t func) {unsigned long flags;bool needwake;
Signature · 1 line
2.5.2
PATCH 12/13 rcu: Remove deprecated rcu_lockdep_assert()
In reply to Paul E. McKenneyThe old rcu_lockdep_assert() was retained to ease handling of incoming patches, but any use will result in deprecated warnings. However, its replacement, RCU_LOCKDEP_WARN(), is now upstream. It is therefore time to remove rcu_lockdep_assert(), which this commit does.
--- include/linux/rcupdate.h | 21 --------------------- 1 file changed, 21 deletions(-)
include/linux/rcupdate.h +0 -21
@@ -537,29 +537,9 @@ static inline int rcu_read_lock_sched_held(void)#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ -/* Deprecate rcu_lockdep_assert(): Use RCU_LOCKDEP_WARN() instead. */ -static inline void __attribute((deprecated))deprecate_rcu_lockdep_assert (void ) -{ -} -#ifdef CONFIG_PROVE_RCU /** -* rcu_lockdep_assert - emit lockdep splat if specified condition not met -* @c: condition to check -* @s: informative message -*/ -#define rcu_lockdep_assert (c, s) \ - do { \ - static bool __section(.data.unlikely) __warned; \ - deprecate_rcu_lockdep_assert(); \ - if (debug_lockdep_rcu_enabled() && !__warned && !(c)) { \ - __warned = true; \ - lockdep_rcu_suspicious(__FILE__, __LINE__, s); \ - } \ - } while (0) - -/** * RCU_LOCKDEP_WARN - emit lockdep splat if specified condition is met * @c: condition to check * @s: informative message
@@ -596,7 +576,6 @@ static inline void rcu_preempt_sleep_check(void)#else /* #ifdef CONFIG_PROVE_RCU */ -#define rcu_lockdep_assert (c, s) deprecate_rcu_lockdep_assert()#define RCU_LOCKDEP_WARN (c, s) do { } while (0)#define rcu_sleep_check () do { } while (0)
Signature · 1 line
2.5.2
PATCH 7/13 rcu: Move preemption disabling out of __srcu_read_lock()
In reply to Paul E. McKenneyCurrently, __srcu_read_lock() cannot be invoked from restricted environments because it contains calls to preempt_disable() and preempt_enable(), both of which can invoke lockdep, which is a bad idea in some restricted execution modes. This commit therefore moves the preempt_disable() and preempt_enable() from __srcu_read_lock() to srcu_read_lock(). It also inserts the preempt_disable() and preempt_enable() around the call to __srcu_read_lock() in do_exit().
--- include/linux/srcu.h | 5 ++++- kernel/exit.c | 2 ++ kernel/rcu/srcu.c | 2 -- 3 files changed, 6 insertions(+), 3 deletions(-)
include/linux/srcu.h +4 -1
@@ -215,8 +215,11 @@ static inline int srcu_read_lock_held(struct srcu_struct *sp)*/ static inline int srcu_read_lock (struct srcu_struct *sp)__acquires (sp) { -int retval =__srcu_read_lock (sp); +int retval; +preempt_disable (); + retval =__srcu_read_lock (sp); +preempt_enable ();rcu_lock_acquire (&(sp)->dep_map);return retval; }
kernel/exit.c +2 -0
@@ -761,7 +761,9 @@ void do_exit(long code)*/ flush_ptrace_hw_breakpoint (tsk); +TASKS_RCU (preempt_disable ());TASKS_RCU (tasks_rcu_i =__srcu_read_lock (&tasks_rcu_exit_srcu)); +TASKS_RCU (preempt_enable ());exit_notify (tsk, group_dead);proc_exit_connector (tsk);#ifdef CONFIG_NUMA
kernel/rcu/srcu.c +0 -2
@@ -298,11 +298,9 @@ int __srcu_read_lock(struct srcu_struct *sp)int idx; idx =READ_ONCE (sp->completed) &0x1 ; -preempt_disable ();__this_cpu_inc (sp->per_cpu_ref->c[idx]);smp_mb ();/* B */ /* Avoid leaking the critical section. */ __this_cpu_inc (sp->per_cpu_ref->seq[idx]); -preempt_enable ();return idx; }EXPORT_SYMBOL_GPL (__srcu_read_lock);
Signature · 1 line
2.5.2
PATCH 5/13 rcu: Eliminate panic when silly boot-time fanout specified
In reply to Paul E. McKenneyThis commit loosens rcutree.rcu_fanout_leaf range checks
and replaces a panic() with a fallback to compile-time values. This fallback is accompanied by a WARN_ON(), and both occur when the rcutree.rcu_fanout_leaf value is too small to accommodate the number of CPUs. For example, given the current four-level limit for the rcu_node tree, a system with more than 16 CPUs built with CONFIG_FANOUT=2 must have rcutree.rcu_fanout_leaf larger than 2.
--- Documentation/kernel-parameters.txt | 9 ++++++--- kernel/rcu/tree.c | 20 +++++++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-)
Documentation/kernel-parameters.txt +6 -3
@@ -3074,9 +3074,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. cache-to-cache transfer latencies. rcutree.rcu_fanout_leaf= [KNL] - Increase the number of CPUs assigned to each - leaf rcu_node structure. Useful for very large - systems. + Change the number of CPUs assigned to each + leaf rcu_node structure. Useful for very + large systems, which will choose the value 64, + and for NUMA systems with large remote-access + latencies, which will choose a value aligned + with the appropriate hardware boundaries. rcutree.jiffies_till_sched_qs= [KNL] Set required age in jiffies for a
kernel/rcu/tree.c +11 -9
@@ -4230,13 +4230,12 @@ static void __init rcu_init_geometry(void) rcu_fanout_leaf, nr_cpu_ids);/* -* The boot-time rcu_fanout_leaf parameter is only permitted -* to increase the leaf-level fanout, not decrease it. Of course, -* the leaf-level fanout cannot exceed the number of bits in -* the rcu_node masks. Complain and fall back to the compile- -* time values if these limits are exceeded. +* The boot-time rcu_fanout_leaf parameter must be at least two +* and cannot exceed the number of bits in the rcu_node masks. +* Complain and fall back to the compile-time values if this +* limit is exceeded. */ -if (rcu_fanout_leaf <RCU_FANOUT_LEAF || +if (rcu_fanout_leaf <2 || rcu_fanout_leaf >sizeof (unsigned long ) *8 ) { rcu_fanout_leaf =RCU_FANOUT_LEAF ;WARN_ON (1 );
@@ -4253,10 +4252,13 @@ static void __init rcu_init_geometry(void)/* * The tree must be able to accommodate the configured number of CPUs. -* If this limit is exceeded than we have a serious problem elsewhere. +* If this limit is exceeded, fall back to the compile-time values. */ -if (nr_cpu_ids > rcu_capacity[RCU_NUM_LVLS -1 ]) -panic ("rcu_init_geometry: rcu_capacity[] is too small" ); +if (nr_cpu_ids > rcu_capacity[RCU_NUM_LVLS -1 ]) { + rcu_fanout_leaf =RCU_FANOUT_LEAF ; +WARN_ON (1 ); +return ; + }/* Calculate the number of levels in the tree. */ for (i =0 ; nr_cpu_ids > rcu_capacity[i]; i++) {
Signature · 1 line
2.5.2
PATCH 10/13 rcu: Add rcu_pointer_handoff()
In reply to Paul E. McKenneyThis commit adds an rcu_pointer_handoff() that is intended to mark situations where a structure's protection transitions from RCU to some other mechanism (locking, reference counting, whatever). These markings should allow external tools to more easily spot bugs involving leaking pointers out of RCU read-side critical sections.
--- include/linux/rcupdate.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
include/linux/rcupdate.h +22 -0
@@ -813,6 +813,28 @@ static inline void rcu_preempt_sleep_check(void)#define rcu_dereference_sched (p) rcu_dereference_sched_check(p, 0)/** +* rcu_pointer_handoff() - Hand off a pointer from RCU to other mechanism +* @p: The pointer to hand off +* +* This is simply an identity function, but it documents where a pointer +* is handed off from RCU to some other synchronization mechanism, for +* example, reference counting or locking. In C11, it would map to +* kill_dependency(). It could be used as follows: +* +* rcu_read_lock(); +* p = rcu_dereference(gp); +* long_lived = is_long_lived(p); +* if (long_lived) { +* if (!atomic_inc_not_zero(p->refcnt)) +* long_lived = false; +* else +* p = rcu_pointer_handoff(p); +* } +* rcu_read_unlock(); +*/ +#define rcu_pointer_handoff (p) (p) + +/** * rcu_read_lock() - mark the beginning of an RCU read-side critical section * * When synchronize_rcu() is invoked on one CPU while other CPUs
Signature · 1 line
2.5.2
PATCH 3/13 rcu: Use call_rcu_func_t to replace explicit type equivalents
In reply to Paul E. McKenneyFrom: Boqun Feng <[email protected]>
We have had the call_rcu_func_t typedef for a quite awhile, but we still use explicit function pointer types in some places. These types can confuse cscope and can be hard to read. This patch therefore replaces these types with the call_rcu_func_t typedef.
--- kernel/rcu/rcutorture.c | 2 +- kernel/rcu/tree.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-)
kernel/rcu/rcutorture.c +1 -1
@@ -252,7 +252,7 @@ struct rcu_torture_ops {void (*exp_sync)(void );unsigned long (*get_state)(void );void (*cond_sync)(unsigned long oldstate); -void (*call)(struct rcu_head *head,void (*func)(struct rcu_head *rcu)); +call_rcu_func_t call;void (*cb_barrier)(void );void (*fqs)(void );void (*stats)(void );
kernel/rcu/tree.h +1 -2
@@ -464,8 +464,7 @@ struct rcu_state {/* shut bogus gcc warning) */ u8 flavor_mask;/* bit in flavor mask. */ struct rcu_data __percpu *rda;/* pointer of percu rcu_data. */ -void (*call)(struct rcu_head *head,/* call_rcu() flavor. */ -void (*func)(struct rcu_head *head)); +call_rcu_func_t call;/* call_rcu() flavor. */ /* The following fields are guarded by the root rcu_node's lock. */
Signature · 1 line
2.5.2
PATCH 13/13 rculist: Use WRITE_ONCE() when deleting from reader-visible list
In reply to Paul E. McKenneyThe various RCU list-deletion macros (list_del_rcu(), hlist_del_init_rcu(), hlist_del_rcu(), hlist_bl_del_init_rcu(), hlist_bl_del_rcu(), hlist_nulls_del_init_rcu(), and hlist_nulls_del_rcu()) do plain stores into the ->next pointer of the preceding list elemment. Unfortunately, the compiler is within its rights to (for example) use byte-at-a-time writes to update the pointer, which would fatally confuse concurrent readers. This patch therefore adds the needed WRITE_ONCE() macros.
KernelThreadSanitizer (KTSAN) reported the __hlist_del() issue, which is a problem when __hlist_del() is invoked by hlist_del_rcu().
--- include/linux/list.h | 5 +++-- include/linux/list_bl.h | 5 +++-- include/linux/list_nulls.h | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-)
include/linux/list.h +3 -2
@@ -87,7 +87,7 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head)static inline void __list_del (struct list_head * prev,struct list_head * next) { next->prev = prev; - prev->next = next; +WRITE_ONCE (prev->next, next); }/**
@@ -615,7 +615,8 @@ static inline void __hlist_del(struct hlist_node *n) {struct hlist_node *next = n->next;struct hlist_node **pprev = n->pprev; - *pprev = next; + +WRITE_ONCE (*pprev, next);if (next) next->pprev = pprev; }
include/linux/list_bl.h +3 -2
@@ -93,9 +93,10 @@ static inline void __hlist_bl_del(struct hlist_bl_node *n)LIST_BL_BUG_ON ((unsigned long )n &LIST_BL_LOCKMASK );/* pprev may be `first`, so be careful not to lose the lock bit */ - *pprev = (struct hlist_bl_node *) +WRITE_ONCE (*pprev, + (struct hlist_bl_node *) ((unsigned long )next | - ((unsigned long )*pprev &LIST_BL_LOCKMASK )); + ((unsigned long )*pprev &LIST_BL_LOCKMASK )));if (next) next->pprev = pprev; }
include/linux/list_nulls.h +2 -1
@@ -76,7 +76,8 @@ static inline void __hlist_nulls_del(struct hlist_nulls_node *n) {struct hlist_nulls_node *next = n->next;struct hlist_nulls_node **pprev = n->pprev; - *pprev = next; + +WRITE_ONCE (*pprev, next);if (!is_a_nulls (next)) next->pprev = pprev; }
Signature · 1 line
2.5.2
Re: [Kernel networking modules.] OSI levels 2 & 3, Assistance - If anyone knows anyone in the US. North West region
In reply to Paul E. McKenneyOSI levels 2 & 3, Assistance - If anyone knows anyone in the US. North West region, please advise.
Welcome assistance on Kernel developments on the networking side.
thanks in advance.
Regards, John.
Quoted 6 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Josh Triplett
maintainerRe: [PATCH tip/core/rcu 04/13] rcu: Don't disable preemption for Tiny and Tree RCU readers
In reply to Paul E. McKenneyQuoted 16 lines · Paul E. McKenney
From: Boqun Feng <[email protected]>
Because
preempt_disable()maps tobarrier()for non-debug builds, it forces the compiler to spill and reload registers. Because Tree RCU and Tiny RCU now only appear inCONFIG_PREEMPT=nbuilds, thesebarrier()instances generate needless extra code for each instance ofrcu_read_lock()andrcu_read_unlock(). This extra code slows down Tree RCU and bloats Tiny RCU.This commit therefore removes the
preempt_disable()andpreempt_enable()from the non-preemptible implementations of__rcu_read_lock()and__rcu_read_unlock(), respectively. However, for debug purposes,preempt_disable()andpreempt_enable()are still invoked ifCONFIG_PREEMPT_COUNT=y, because this allows detection of sleeping inside atomic sections in non-preemptible kernels.
Quoted 3 lines
This is based on an earlier patch by Paul E. McKenney, fixing a bug encountered in kernels built with
CONFIG_PREEMPT=nandCONFIG_PREEMPT_COUNT=y.
This also adds explicit barrier() calls to several internal RCU functions, but the commit message doesn't explain those at all.
Quoted 83 lines
Signed-off-by Boqun Feng <[email protected]>Signed-off-by Paul E. McKenney <[email protected]>--- include/linux/rcupdate.h | 6 ++++-- include/linux/rcutiny.h | 1 + kernel/rcu/tree.c | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-)include/linux/rcupdate.h +4
-2@@ -297,12 +297,14 @@ void synchronize_rcu(void);static inline void __rcu_read_lock (void ) { -preempt_disable (); +if (IS_ENABLED (CONFIG_PREEMPT_COUNT )) +preempt_disable (); }static inline void __rcu_read_unlock (void ) { -preempt_enable (); +if (IS_ENABLED (CONFIG_PREEMPT_COUNT )) +preempt_enable (); }static inline void synchronize_rcu (void )include/linux/rcutiny.h +1
-0@@ -216,6 +216,7 @@ static inline bool rcu_is_watching(void)static inline void rcu_all_qs (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking across. */ }#endif /* __LINUX_RCUTINY_H */ kernel/rcu/tree.c +9
-0@@ -337,12 +337,14 @@ static void rcu_momentary_dyntick_idle(void)*/ void rcu_note_context_switch (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ trace_rcu_utilization (TPS ("Start context switch" ));rcu_sched_qs ();rcu_preempt_note_context_switch ();if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();trace_rcu_utilization (TPS ("End context switch" )); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_note_context_switch);@@ -353,12 +355,19 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch);* RCU flavors in desperate need of a quiescent state, which will normally * be none of them). Either way, do a lightweight quiescent state for * all RCU flavors. +* +* The barrier() calls are redundant in the common case when this is +* called externally, but just in case this is called from within this +* file. +* */ void rcu_all_qs (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();this_cpu_inc (rcu_qs_ctr); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_all_qs);Signature · 1 line
2.5.2
Re: [PATCH tip/core/rcu 04/13] rcu: Don't disable preemption for Tiny and Tree RCU readers
Quoted 17 lines · Josh Triplett
Quoted 16 lines · Paul E. McKenney
From: Boqun Feng <[email protected]>
Because
preempt_disable()maps tobarrier()for non-debug builds, it forces the compiler to spill and reload registers. Because Tree RCU and Tiny RCU now only appear inCONFIG_PREEMPT=nbuilds, thesebarrier()instances generate needless extra code for each instance ofrcu_read_lock()andrcu_read_unlock(). This extra code slows down Tree RCU and bloats Tiny RCU.This commit therefore removes the
preempt_disable()andpreempt_enable()from the non-preemptible implementations of__rcu_read_lock()and__rcu_read_unlock(), respectively. However, for debug purposes,preempt_disable()andpreempt_enable()are still invoked ifCONFIG_PREEMPT_COUNT=y, because this allows detection of sleeping inside atomic sections in non-preemptible kernels.
Quoted 6 lines
Quoted 3 lines
This is based on an earlier patch by Paul E. McKenney, fixing a bug encountered in kernels built with
CONFIG_PREEMPT=nandCONFIG_PREEMPT_COUNT=y.This also adds explicit
barrier()calls to several internal RCU functions, but the commit message doesn't explain those at all.
To compensate for them being removed from rcu_read_lock() and rcu_read_unlock(), but yes, I will update.
And good catch!
Thanx, Paul
Quoted 84 lines
Quoted 83 lines
Signed-off-by Boqun Feng <[email protected]>Signed-off-by Paul E. McKenney <[email protected]>--- include/linux/rcupdate.h | 6 ++++-- include/linux/rcutiny.h | 1 + kernel/rcu/tree.c | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-)include/linux/rcupdate.h +4
-2@@ -297,12 +297,14 @@ void synchronize_rcu(void);static inline void __rcu_read_lock (void ) { -preempt_disable (); +if (IS_ENABLED (CONFIG_PREEMPT_COUNT )) +preempt_disable (); }static inline void __rcu_read_unlock (void ) { -preempt_enable (); +if (IS_ENABLED (CONFIG_PREEMPT_COUNT )) +preempt_enable (); }static inline void synchronize_rcu (void )include/linux/rcutiny.h +1
-0@@ -216,6 +216,7 @@ static inline bool rcu_is_watching(void)static inline void rcu_all_qs (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking across. */ }#endif /* __LINUX_RCUTINY_H */ kernel/rcu/tree.c +9
-0@@ -337,12 +337,14 @@ static void rcu_momentary_dyntick_idle(void)*/ void rcu_note_context_switch (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ trace_rcu_utilization (TPS ("Start context switch" ));rcu_sched_qs ();rcu_preempt_note_context_switch ();if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();trace_rcu_utilization (TPS ("End context switch" )); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_note_context_switch);@@ -353,12 +355,19 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch);* RCU flavors in desperate need of a quiescent state, which will normally * be none of them). Either way, do a lightweight quiescent state for * all RCU flavors. +* +* The barrier() calls are redundant in the common case when this is +* called externally, but just in case this is called from within this +* file. +* */ void rcu_all_qs (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();this_cpu_inc (rcu_qs_ctr); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_all_qs);Signature · 1 line
2.5.2
Josh Triplett
maintainerRe: [PATCH tip/core/rcu 06/13] rcu: Add online/offline info to stall warning message
In reply to Paul E. McKenneyQuoted 6 lines · Paul E. McKenney
This commit makes the RCU CPU stall warning message print online/offline indications immediately after the CPU number. A "?" indicates global offline, a "," global online, and a "!" indicates RCU believes that the CPU is offline and "." otherwise, both right after the CPU number. So for CPU 10, you would normally see "10,.:" indicating that everything believes that the CPU is online.
This explanation doesn't seem to agree with the actual characters used. These use 'O', 'o', and 'N', instead, with '.' for "true" in all three cases. And the output from the code includes a '-' after the CPU number.
Also, this output needs matching documentation in src/linux/Documentation/RCU/stallwarn.txt, ideally added as part of the same commit.
Quoted 27 lines
Signed-off-by Paul E. McKenney <[email protected]>--- kernel/rcu/tree_plugin.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)kernel/rcu/tree_plugin.h +6
-2@@ -1702,8 +1702,12 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu) ticks_value = rsp->gpnum - rdp->gpnum; }print_cpu_stall_fast_no_hz (fast_no_hz, cpu); - pr_err("\t%d: (%lu %s) idle=%03x/%llx/%d softirq=%u/%u fqs=%ld %s\n", - cpu, ticks_value, ticks_title, + pr_err("\t%d-%c%c%c: (%lu %s) idle=%03x/%llx/%d softirq=%u/%u fqs=%ld %s\n", + cpu, + "O."[!!cpu_online(cpu)], + "o."[!!(rdp->grpmask & rdp->mynode->qsmaskinit)], + "N."[!!(rdp->grpmask & rdp->mynode->qsmaskinitnext)], + ticks_value, ticks_title, atomic_read(&rdtp->dynticks) & 0xfff, rdtp->dynticks_nesting, rdtp->dynticks_nmi_nesting, rdp->softirq_snap, kstat_softirqs_cpu(RCU_SOFTIRQ, cpu),Signature · 1 line
2.5.2
Josh Triplett
maintainerRe: [PATCH tip/core/rcu 04/13] rcu: Don't disable preemption for Tiny and Tree RCU readers
In reply to Paul E. McKenneyQuoted 22 lines · Paul E. McKenney
Quoted 21 lines · Josh Triplett
Quoted 19 lines · Paul E. McKenney
From: Boqun Feng <[email protected]>
Because
preempt_disable()maps tobarrier()for non-debug builds, it forces the compiler to spill and reload registers. Because Tree RCU and Tiny RCU now only appear inCONFIG_PREEMPT=nbuilds, thesebarrier()instances generate needless extra code for each instance ofrcu_read_lock()andrcu_read_unlock(). This extra code slows down Tree RCU and bloats Tiny RCU.This commit therefore removes the
preempt_disable()andpreempt_enable()from the non-preemptible implementations of__rcu_read_lock()and__rcu_read_unlock(), respectively. However, for debug purposes,preempt_disable()andpreempt_enable()are still invoked ifCONFIG_PREEMPT_COUNT=y, because this allows detection of sleeping inside atomic sections in non-preemptible kernels.This is based on an earlier patch by Paul E. McKenney, fixing a bug encountered in kernels built with
CONFIG_PREEMPT=nandCONFIG_PREEMPT_COUNT=y.
Quoted 5 lines
Quoted 2 lines
This also adds explicit
barrier()calls to several internal RCU functions, but the commit message doesn't explain those at all.To compensate for them being removed from
rcu_read_lock()andrcu_read_unlock(), but yes, I will update.
That much seemed clear from the comments, but that doesn't explain *why* those functions need barriers of their own even though rcu_read_lock() and rcu_read_unlock() don't.
Quoted 85 lines
Quoted 84 lines
Quoted 83 lines
Signed-off-by Boqun Feng <[email protected]>Signed-off-by Paul E. McKenney <[email protected]>--- include/linux/rcupdate.h | 6 ++++-- include/linux/rcutiny.h | 1 + kernel/rcu/tree.c | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-)include/linux/rcupdate.h +4
-2@@ -297,12 +297,14 @@ void synchronize_rcu(void);static inline void __rcu_read_lock (void ) { -preempt_disable (); +if (IS_ENABLED (CONFIG_PREEMPT_COUNT )) +preempt_disable (); }static inline void __rcu_read_unlock (void ) { -preempt_enable (); +if (IS_ENABLED (CONFIG_PREEMPT_COUNT )) +preempt_enable (); }static inline void synchronize_rcu (void )include/linux/rcutiny.h +1
-0@@ -216,6 +216,7 @@ static inline bool rcu_is_watching(void)static inline void rcu_all_qs (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking across. */ }#endif /* __LINUX_RCUTINY_H */ kernel/rcu/tree.c +9
-0@@ -337,12 +337,14 @@ static void rcu_momentary_dyntick_idle(void)*/ void rcu_note_context_switch (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ trace_rcu_utilization (TPS ("Start context switch" ));rcu_sched_qs ();rcu_preempt_note_context_switch ();if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();trace_rcu_utilization (TPS ("End context switch" )); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_note_context_switch);@@ -353,12 +355,19 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch);* RCU flavors in desperate need of a quiescent state, which will normally * be none of them). Either way, do a lightweight quiescent state for * all RCU flavors. +* +* The barrier() calls are redundant in the common case when this is +* called externally, but just in case this is called from within this +* file. +* */ void rcu_all_qs (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();this_cpu_inc (rcu_qs_ctr); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_all_qs);Signature · 1 line
2.5.2
Josh Triplett
maintainerRe: [PATCH tip/core/rcu 07/13] rcu: Move preemption disabling out of __srcu_read_lock()
In reply to Paul E. McKenneyQuoted 7 lines · Paul E. McKenney
Currently,
__srcu_read_lock()cannot be invoked from restricted environments because it contains calls topreempt_disable()andpreempt_enable(), both of which can invoke lockdep, which is a bad idea in some restricted execution modes. This commit therefore moves thepreempt_disable()andpreempt_enable()from__srcu_read_lock()tosrcu_read_lock(). It also inserts thepreempt_disable()andpreempt_enable()around the call to__srcu_read_lock()indo_exit().
What restricted environments do you intend to invoke __srcu_read_lock from?
This change seems fine, but I don't see any change in this patch series that needs this, hence my curiosity.
Quoted 57 lines
Signed-off-by Paul E. McKenney <[email protected]>--- include/linux/srcu.h | 5 ++++- kernel/exit.c | 2 ++ kernel/rcu/srcu.c | 2 -- 3 files changed, 6 insertions(+), 3 deletions(-)include/linux/srcu.h +4
-1@@ -215,8 +215,11 @@ static inline int srcu_read_lock_held(struct srcu_struct *sp)*/ static inline int srcu_read_lock (struct srcu_struct *sp)__acquires (sp) { -int retval =__srcu_read_lock (sp); +int retval; +preempt_disable (); + retval =__srcu_read_lock (sp); +preempt_enable ();rcu_lock_acquire (&(sp)->dep_map);return retval; }kernel/exit.c +2
-0@@ -761,7 +761,9 @@ void do_exit(long code)*/ flush_ptrace_hw_breakpoint (tsk); +TASKS_RCU (preempt_disable ());TASKS_RCU (tasks_rcu_i =__srcu_read_lock (&tasks_rcu_exit_srcu)); +TASKS_RCU (preempt_enable ());exit_notify (tsk, group_dead);proc_exit_connector (tsk);#ifdef CONFIG_NUMA kernel/rcu/srcu.c +0
-2@@ -298,11 +298,9 @@ int __srcu_read_lock(struct srcu_struct *sp)int idx; idx =READ_ONCE (sp->completed) &0x1 ; -preempt_disable ();__this_cpu_inc (sp->per_cpu_ref->c[idx]);smp_mb ();/* B */ /* Avoid leaking the critical section. */ __this_cpu_inc (sp->per_cpu_ref->seq[idx]); -preempt_enable ();return idx; }EXPORT_SYMBOL_GPL (__srcu_read_lock);Signature · 1 line
2.5.2
Josh Triplett
maintainerRe: [PATCH tip/core/rcu 10/13] rcu: Add rcu_pointer_handoff()
In reply to Paul E. McKenneyQuoted 7 lines · Paul E. McKenney
This commit adds an
rcu_pointer_handoff()that is intended to mark situations where a structure's protection transitions from RCU to some other mechanism (locking, reference counting, whatever). These markings should allow external tools to more easily spot bugs involving leaking pointers out of RCU read-side critical sections.Signed-off-by Paul E. McKenney <[email protected]>
Shouldn't this expect the __rcu address space on the pointer, and cast away the __rcu with __force?
Quoted 39 lines
include/linux/rcupdate.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)include/linux/rcupdate.h +22
-0@@ -813,6 +813,28 @@ static inline void rcu_preempt_sleep_check(void)#define rcu_dereference_sched (p) rcu_dereference_sched_check(p, 0)/** +* rcu_pointer_handoff() - Hand off a pointer from RCU to other mechanism +* @p: The pointer to hand off +* +* This is simply an identity function, but it documents where a pointer +* is handed off from RCU to some other synchronization mechanism, for +* example, reference counting or locking. In C11, it would map to +* kill_dependency(). It could be used as follows: +* +* rcu_read_lock(); +* p = rcu_dereference(gp); +* long_lived = is_long_lived(p); +* if (long_lived) { +* if (!atomic_inc_not_zero(p->refcnt)) +* long_lived = false; +* else +* p = rcu_pointer_handoff(p); +* } +* rcu_read_unlock(); +*/ +#define rcu_pointer_handoff (p) (p) + +/** * rcu_read_lock() - mark the beginning of an RCU read-side critical section * * When synchronize_rcu() is invoked on one CPU while other CPUs Signature · 1 line
2.5.2
Quoted 35 lines · Paul E. McKenney
Hello!
This series contains miscellaneous fixes:
1. Export
sched_setscheduler_nocheck()so that the new locktorture
rtmutex_locktests can be run as modules, courtesy of Davidlohr Bueso.2. Use
rcu_callback_tin call_rcu*() and friends to improve
readability and to make cscope able to find them, courtesy of Boqun Feng.3. Use
call_rcu_func_tto replace explicit type equivalents when
defining RCU callback functions, courtesy of Boqun Feng.4. Don't unnecessarily disable preemption for Tiny and Tree
RCU readers (only for preemptible RCU readers), courtesy of Boqun Feng.5. Eliminate boot-time panic when a silly boot-time fanout is
specified.6. Add online/offline info to help debug stall-warning messages.
7. Move preemption disabling out of
__srcu_read_lock()intosrcu_read_lock().8. Finish folding ->fqs_state into ->gp_state, courtesy of Petr Mladek.
9. Correct comment for values of ->gp_state field.
10. Add
rcu_pointer_handoff()to allow explicit marking of handing
off protection from RCU to some other means, such as locking or reference counting.
Quoted 8 lines
11. Make
list_entry_rcu()uselockless_dereference(), courtesy
of Patrick Marlier. Despite the fact that this patch does nothing more than eliminate a single store and a single load of an unshared stack variable it nevertheless manages to provide a measurable performance increase:
http://people.csail.mit.edu/amatveev/RLU_SOSP2015.pdf12. Remove deprecated
rcu_lockdep_assert().
(And a patch 13 not mentioned here.)
I responded to patches 4, 6, and 10 with feedback; for the rest (and for those with the issues addressed):
Re: [PATCH tip/core/rcu 10/13] rcu: Add rcu_pointer_handoff()
In reply to Josh TriplettQuoted 11 lines · Josh Triplett
Quoted 7 lines · Paul E. McKenney
This commit adds an
rcu_pointer_handoff()that is intended to mark situations where a structure's protection transitions from RCU to some other mechanism (locking, reference counting, whatever). These markings should allow external tools to more easily spot bugs involving leaking pointers out of RCU read-side critical sections.Signed-off-by Paul E. McKenney <[email protected]>Shouldn't this expect the
__rcuaddress space on the pointer, and cast away the__rcuwith__force?
I do not believe so, given that the __rcu was already removed by a preceding rcu_dereference(). Or am I missing something?
Thanx, Paul
Quoted 40 lines
Quoted 39 lines
include/linux/rcupdate.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)include/linux/rcupdate.h +22
-0@@ -813,6 +813,28 @@ static inline void rcu_preempt_sleep_check(void)#define rcu_dereference_sched (p) rcu_dereference_sched_check(p, 0)/** +* rcu_pointer_handoff() - Hand off a pointer from RCU to other mechanism +* @p: The pointer to hand off +* +* This is simply an identity function, but it documents where a pointer +* is handed off from RCU to some other synchronization mechanism, for +* example, reference counting or locking. In C11, it would map to +* kill_dependency(). It could be used as follows: +* +* rcu_read_lock(); +* p = rcu_dereference(gp); +* long_lived = is_long_lived(p); +* if (long_lived) { +* if (!atomic_inc_not_zero(p->refcnt)) +* long_lived = false; +* else +* p = rcu_pointer_handoff(p); +* } +* rcu_read_unlock(); +*/ +#define rcu_pointer_handoff (p) (p) + +/** * rcu_read_lock() - mark the beginning of an RCU read-side critical section * * When synchronize_rcu() is invoked on one CPU while other CPUs Signature · 1 line
2.5.2
Josh Triplett
maintainerRe: [PATCH tip/core/rcu 10/13] rcu: Add rcu_pointer_handoff()
Quoted 8 lines · Paul E. McKenney
Quoted 7 lines · Josh Triplett
Quoted 6 lines · Paul E. McKenney
This commit adds an
rcu_pointer_handoff()that is intended to mark situations where a structure's protection transitions from RCU to some other mechanism (locking, reference counting, whatever). These markings should allow external tools to more easily spot bugs involving leaking pointers out of RCU read-side critical sections.
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
Signed-off-by Paul E. McKenney <[email protected]>Shouldn't this expect the
__rcuaddress space on the pointer, and cast away the__rcuwith__force?I do not believe so, given that the
__rcuwas already removed by a precedingrcu_dereference(). Or am I missing something?
Ah, I see. Per the example, you don't call this on an __rcu pointer directly, only on a pointer you've already obtained from RCU after giving it a lifetime of its own. Nevermind.
Quoted 41 lines
Quoted 40 lines
Quoted 39 lines
include/linux/rcupdate.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)include/linux/rcupdate.h +22
-0@@ -813,6 +813,28 @@ static inline void rcu_preempt_sleep_check(void)#define rcu_dereference_sched (p) rcu_dereference_sched_check(p, 0)/** +* rcu_pointer_handoff() - Hand off a pointer from RCU to other mechanism +* @p: The pointer to hand off +* +* This is simply an identity function, but it documents where a pointer +* is handed off from RCU to some other synchronization mechanism, for +* example, reference counting or locking. In C11, it would map to +* kill_dependency(). It could be used as follows: +* +* rcu_read_lock(); +* p = rcu_dereference(gp); +* long_lived = is_long_lived(p); +* if (long_lived) { +* if (!atomic_inc_not_zero(p->refcnt)) +* long_lived = false; +* else +* p = rcu_pointer_handoff(p); +* } +* rcu_read_unlock(); +*/ +#define rcu_pointer_handoff (p) (p) + +/** * rcu_read_lock() - mark the beginning of an RCU read-side critical section * * When synchronize_rcu() is invoked on one CPU while other CPUs Signature · 1 line
2.5.2
Re: [PATCH tip/core/rcu 07/13] rcu: Move preemption disabling out of __srcu_read_lock()
In reply to Josh TriplettQuoted 9 lines · Josh Triplett
Quoted 7 lines · Paul E. McKenney
Currently,
__srcu_read_lock()cannot be invoked from restricted environments because it contains calls topreempt_disable()andpreempt_enable(), both of which can invoke lockdep, which is a bad idea in some restricted execution modes. This commit therefore moves thepreempt_disable()andpreempt_enable()from__srcu_read_lock()tosrcu_read_lock(). It also inserts thepreempt_disable()andpreempt_enable()around the call to__srcu_read_lock()indo_exit().
Quoted 5 lines
What restricted environments do you intend to invoke
__srcu_read_lockfrom?This change seems fine, but I don't see any change in this patch series that needs this, hence my curiosity.
Someone asked me for it, and now I cannot find it. :-(
Something to the effect of when running unmapped during exception entry or something like that. I guess one way to find out would be to remove the commit and see who complained, but on the other hand, it arguably makes more sense to have only the bare mechanism is __srcu_read_lock() and put the environmental protection into srcu_read_lock().
Thanx, Paul
Quoted 58 lines
Quoted 57 lines
Signed-off-by Paul E. McKenney <[email protected]>--- include/linux/srcu.h | 5 ++++- kernel/exit.c | 2 ++ kernel/rcu/srcu.c | 2 -- 3 files changed, 6 insertions(+), 3 deletions(-)include/linux/srcu.h +4
-1@@ -215,8 +215,11 @@ static inline int srcu_read_lock_held(struct srcu_struct *sp)*/ static inline int srcu_read_lock (struct srcu_struct *sp)__acquires (sp) { -int retval =__srcu_read_lock (sp); +int retval; +preempt_disable (); + retval =__srcu_read_lock (sp); +preempt_enable ();rcu_lock_acquire (&(sp)->dep_map);return retval; }kernel/exit.c +2
-0@@ -761,7 +761,9 @@ void do_exit(long code)*/ flush_ptrace_hw_breakpoint (tsk); +TASKS_RCU (preempt_disable ());TASKS_RCU (tasks_rcu_i =__srcu_read_lock (&tasks_rcu_exit_srcu)); +TASKS_RCU (preempt_enable ());exit_notify (tsk, group_dead);proc_exit_connector (tsk);#ifdef CONFIG_NUMA kernel/rcu/srcu.c +0
-2@@ -298,11 +298,9 @@ int __srcu_read_lock(struct srcu_struct *sp)int idx; idx =READ_ONCE (sp->completed) &0x1 ; -preempt_disable ();__this_cpu_inc (sp->per_cpu_ref->c[idx]);smp_mb ();/* B */ /* Avoid leaking the critical section. */ __this_cpu_inc (sp->per_cpu_ref->seq[idx]); -preempt_enable ();return idx; }EXPORT_SYMBOL_GPL (__srcu_read_lock);Signature · 1 line
2.5.2
Quoted 43 lines · Josh Triplett
Quoted 42 lines · Paul E. McKenney
Hello!
This series contains miscellaneous fixes:
1. Export
sched_setscheduler_nocheck()so that the new locktorture
rtmutex_locktests can be run as modules, courtesy of Davidlohr Bueso.2. Use
rcu_callback_tin call_rcu*() and friends to improve
readability and to make cscope able to find them, courtesy of Boqun Feng.3. Use
call_rcu_func_tto replace explicit type equivalents when
defining RCU callback functions, courtesy of Boqun Feng.4. Don't unnecessarily disable preemption for Tiny and Tree
RCU readers (only for preemptible RCU readers), courtesy of Boqun Feng.5. Eliminate boot-time panic when a silly boot-time fanout is
specified.6. Add online/offline info to help debug stall-warning messages.
7. Move preemption disabling out of
__srcu_read_lock()intosrcu_read_lock().8. Finish folding ->fqs_state into ->gp_state, courtesy of Petr Mladek.
9. Correct comment for values of ->gp_state field.
10. Add
rcu_pointer_handoff()to allow explicit marking of handing
off protection from RCU to some other means, such as locking or reference counting.11. Make
list_entry_rcu()uselockless_dereference(), courtesy
of Patrick Marlier. Despite the fact that this patch does nothing more than eliminate a single store and a single load of an unshared stack variable it nevertheless manages to provide a measurable performance increase:
http://people.csail.mit.edu/amatveev/RLU_SOSP2015.pdf
Quoted 3 lines
Quoted 1 line
12. Remove deprecated
rcu_lockdep_assert().(And a patch 13 not mentioned here.)
Oops... "Use WRITE_ONCE() when deleting from reader-visible list" included to make KTSAN happier.
Quoted 4 lines
I responded to patches 4, 6, and 10 with feedback; for the rest (and for those with the issues addressed):
Reviewed-by Josh Triplett <[email protected]>
Thank you for the review and comments!
Thanx, Paul
Re: [PATCH tip/core/rcu 04/13] rcu: Don't disable preemption for Tiny and Tree RCU readers
In reply to Josh TriplettQuoted 26 lines · Josh Triplett
Quoted 25 lines · Paul E. McKenney
Quoted 23 lines · Josh Triplett
Quoted 16 lines · Paul E. McKenney
From: Boqun Feng <[email protected]>
Because
preempt_disable()maps tobarrier()for non-debug builds, it forces the compiler to spill and reload registers. Because Tree RCU and Tiny RCU now only appear inCONFIG_PREEMPT=nbuilds, thesebarrier()instances generate needless extra code for each instance ofrcu_read_lock()andrcu_read_unlock(). This extra code slows down Tree RCU and bloats Tiny RCU.This commit therefore removes the
preempt_disable()andpreempt_enable()from the non-preemptible implementations of__rcu_read_lock()and__rcu_read_unlock(), respectively. However, for debug purposes,preempt_disable()andpreempt_enable()are still invoked ifCONFIG_PREEMPT_COUNT=y, because this allows detection of sleeping inside atomic sections in non-preemptible kernels.Quoted 3 lines
This is based on an earlier patch by Paul E. McKenney, fixing a bug encountered in kernels built with
CONFIG_PREEMPT=nandCONFIG_PREEMPT_COUNT=y.This also adds explicit
barrier()calls to several internal RCU functions, but the commit message doesn't explain those at all.
Quoted 6 lines
Quoted 2 lines
To compensate for them being removed from
rcu_read_lock()andrcu_read_unlock(), but yes, I will update.That much seemed clear from the comments, but that doesn't explain *why* those functions need barriers of their own even though
rcu_read_lock()andrcu_read_unlock()don't.
Ah. The reason is that Tiny RCU and Tree RCU (the !PREEMPT ones) act by implicitly extending (and, if need be, merging) the RCU read-side critical sections to include all the code between successive quiescent states, for example, all the code between a pair of calls to schedule().
Therefore, there need to be barrier() calls in the quiescent-state functions. Some could be argued to be implicitly present due to translation-unit boundaries, but paranoia and all that.
Would adding that sort of explanation help?
Thanx, Paul
Quoted 86 lines
Quoted 85 lines
Quoted 84 lines
Quoted 83 lines
Signed-off-by Boqun Feng <[email protected]>Signed-off-by Paul E. McKenney <[email protected]>--- include/linux/rcupdate.h | 6 ++++-- include/linux/rcutiny.h | 1 + kernel/rcu/tree.c | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-)include/linux/rcupdate.h +4
-2@@ -297,12 +297,14 @@ void synchronize_rcu(void);static inline void __rcu_read_lock (void ) { -preempt_disable (); +if (IS_ENABLED (CONFIG_PREEMPT_COUNT )) +preempt_disable (); }static inline void __rcu_read_unlock (void ) { -preempt_enable (); +if (IS_ENABLED (CONFIG_PREEMPT_COUNT )) +preempt_enable (); }static inline void synchronize_rcu (void )include/linux/rcutiny.h +1
-0@@ -216,6 +216,7 @@ static inline bool rcu_is_watching(void)static inline void rcu_all_qs (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking across. */ }#endif /* __LINUX_RCUTINY_H */ kernel/rcu/tree.c +9
-0@@ -337,12 +337,14 @@ static void rcu_momentary_dyntick_idle(void)*/ void rcu_note_context_switch (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ trace_rcu_utilization (TPS ("Start context switch" ));rcu_sched_qs ();rcu_preempt_note_context_switch ();if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();trace_rcu_utilization (TPS ("End context switch" )); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_note_context_switch);@@ -353,12 +355,19 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch);* RCU flavors in desperate need of a quiescent state, which will normally * be none of them). Either way, do a lightweight quiescent state for * all RCU flavors. +* +* The barrier() calls are redundant in the common case when this is +* called externally, but just in case this is called from within this +* file. +* */ void rcu_all_qs (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();this_cpu_inc (rcu_qs_ctr); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_all_qs);Signature · 1 line
2.5.2
Josh Triplett
maintainerRe: [PATCH tip/core/rcu 07/13] rcu: Move preemption disabling out of __srcu_read_lock()
In reply to Paul E. McKenneyQuoted 16 lines · Paul E. McKenney
Quoted 9 lines · Josh Triplett
Quoted 7 lines · Paul E. McKenney
Currently,
__srcu_read_lock()cannot be invoked from restricted environments because it contains calls topreempt_disable()andpreempt_enable(), both of which can invoke lockdep, which is a bad idea in some restricted execution modes. This commit therefore moves thepreempt_disable()andpreempt_enable()from__srcu_read_lock()tosrcu_read_lock(). It also inserts thepreempt_disable()andpreempt_enable()around the call to__srcu_read_lock()indo_exit().Quoted 5 lines
What restricted environments do you intend to invoke
__srcu_read_lockfrom?This change seems fine, but I don't see any change in this patch series that needs this, hence my curiosity.
Quoted 7 lines
Someone asked me for it, and now I cannot find it. :-(
Something to the effect of when running unmapped during exception entry or something like that. I guess one way to find out would be to remove the commit and see who complained, but on the other hand, it arguably makes more sense to have only the bare mechanism is
__srcu_read_lock()and put the environmental protection intosrcu_read_lock().
I agree; I just find the idea that someone would need to call __srcu_read_lock rather than srcu_read_lock odd and worthy of further understanding. :)
Josh Triplett
maintainerRe: [PATCH tip/core/rcu 04/13] rcu: Don't disable preemption for Tiny and Tree RCU readers
In reply to Paul E. McKenneyQuoted 39 lines · Paul E. McKenney
Quoted 26 lines · Josh Triplett
Quoted 25 lines · Paul E. McKenney
Quoted 23 lines · Josh Triplett
Quoted 16 lines · Paul E. McKenney
From: Boqun Feng <[email protected]>
Because
preempt_disable()maps tobarrier()for non-debug builds, it forces the compiler to spill and reload registers. Because Tree RCU and Tiny RCU now only appear inCONFIG_PREEMPT=nbuilds, thesebarrier()instances generate needless extra code for each instance ofrcu_read_lock()andrcu_read_unlock(). This extra code slows down Tree RCU and bloats Tiny RCU.This commit therefore removes the
preempt_disable()andpreempt_enable()from the non-preemptible implementations of__rcu_read_lock()and__rcu_read_unlock(), respectively. However, for debug purposes,preempt_disable()andpreempt_enable()are still invoked ifCONFIG_PREEMPT_COUNT=y, because this allows detection of sleeping inside atomic sections in non-preemptible kernels.Quoted 3 lines
This is based on an earlier patch by Paul E. McKenney, fixing a bug encountered in kernels built with
CONFIG_PREEMPT=nandCONFIG_PREEMPT_COUNT=y.This also adds explicit
barrier()calls to several internal RCU functions, but the commit message doesn't explain those at all.Quoted 6 lines
Quoted 2 lines
To compensate for them being removed from
rcu_read_lock()andrcu_read_unlock(), but yes, I will update.That much seemed clear from the comments, but that doesn't explain *why* those functions need barriers of their own even though
rcu_read_lock()andrcu_read_unlock()don't.Ah. The reason is that Tiny RCU and Tree RCU (the !PREEMPT ones) act by implicitly extending (and, if need be, merging) the RCU read-side critical sections to include all the code between successive quiescent states, for example, all the code between a pair of calls to
schedule().
Quoted 5 lines
Therefore, there need to be
barrier()calls in the quiescent-state functions. Some could be argued to be implicitly present due to translation-unit boundaries, but paranoia and all that.Would adding that sort of explanation help?
Yes, it would.
Re: [PATCH tip/core/rcu 07/13] rcu: Move preemption disabling out of __srcu_read_lock()
In reply to Josh TriplettQuoted 25 lines · Josh Triplett
Quoted 16 lines · Paul E. McKenney
Quoted 9 lines · Josh Triplett
Quoted 7 lines · Paul E. McKenney
Currently,
__srcu_read_lock()cannot be invoked from restricted environments because it contains calls topreempt_disable()andpreempt_enable(), both of which can invoke lockdep, which is a bad idea in some restricted execution modes. This commit therefore moves thepreempt_disable()andpreempt_enable()from__srcu_read_lock()tosrcu_read_lock(). It also inserts thepreempt_disable()andpreempt_enable()around the call to__srcu_read_lock()indo_exit().Quoted 5 lines
What restricted environments do you intend to invoke
__srcu_read_lockfrom?This change seems fine, but I don't see any change in this patch series that needs this, hence my curiosity.
Quoted 7 lines
Someone asked me for it, and now I cannot find it. :-(
Something to the effect of when running unmapped during exception entry or something like that. I guess one way to find out would be to remove the commit and see who complained, but on the other hand, it arguably makes more sense to have only the bare mechanism is
__srcu_read_lock()and put the environmental protection intosrcu_read_lock().
Quoted 3 lines
I agree; I just find the idea that someone would need to call
__srcu_read_lockrather thansrcu_read_lockodd and worthy of further understanding. :)
And they did supply an explanation that seemed satisfactory at the time, but I cannot find that either. I clearly need to track that sort of stuff better!
Thanx, Paul
Peter Zijlstra
maintainerRe: [PATCH tip/core/rcu 04/13] rcu: Don't disable preemption for Tiny and Tree RCU readers
In reply to Paul E. McKenneyQuoted 14 lines · Paul E. McKenney
Ah. The reason is that Tiny RCU and Tree RCU (the !PREEMPT ones) act by implicitly extending (and, if need be, merging) the RCU read-side critical sections to include all the code between successive quiescent states, for example, all the code between a pair of calls to
schedule().Therefore, there need to be
barrier()calls in the quiescent-state functions. Some could be argued to be implicitly present due to translation-unit boundaries, but paranoia and all that.Would adding that sort of explanation help?
+++
b/include/linux/rcutiny.h
include/linux/rcutiny.h static inline bool rcu_is_watching(void) · line 222
Quoted 7 lines
include/linux/rcutiny.h +1
-0@@ -216,6 +216,7 @@ static inline bool rcu_is_watching(void)static inline void rcu_all_qs (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking across. */ }#endif /* __LINUX_RCUTINY_H */
This is more than sheer paranoia I think, inlined functions are not a compiler barrier.
Quoted 8 lines
kernel/rcu/tree.c +0
-0@@ -337,12 +337,14 @@ static void rcu_momentary_dyntick_idle(void)*/ void rcu_note_context_switch (void ) {
kernel/rcu/tree.c static void rcu_momentary_dyntick_idle(void) · line 349
Quoted 10 lines
kernel/rcu/tree.c +2
-0+barrier ();/* Avoid RCU read-side critical sections leaking down. */ trace_rcu_utilization (TPS ("Start context switch" ));rcu_sched_qs ();rcu_preempt_note_context_switch ();if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();trace_rcu_utilization (TPS ("End context switch" )); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_note_context_switch);
These OTOH could be fixed with a noinline, such that the compiler may never inline it, even with whole-program-optimizations, thereby guaranteeing a function call boundary or compiler barrier.
Peter Zijlstra
maintainerRe: [PATCH tip/core/rcu 07/13] rcu: Move preemption disabling out of __srcu_read_lock()
In reply to Paul E. McKenneyQuoted 7 lines · Paul E. McKenney
Currently,
__srcu_read_lock()cannot be invoked from restricted environments because it contains calls topreempt_disable()andpreempt_enable(), both of which can invoke lockdep, which is a bad idea in some restricted execution modes. This commit therefore moves thepreempt_disable()andpreempt_enable()from__srcu_read_lock()tosrcu_read_lock(). It also inserts thepreempt_disable()andpreempt_enable()around the call to__srcu_read_lock()indo_exit().
Did you not simply want to use: preempt_disable_notrace() ?
Re: [PATCH tip/core/rcu 04/13] rcu: Don't disable preemption for Tiny and Tree RCU readers
In reply to Peter ZijlstraQuoted 22 lines · Peter Zijlstra
Quoted 20 lines · Paul E. McKenney
Ah. The reason is that Tiny RCU and Tree RCU (the !PREEMPT ones) act by implicitly extending (and, if need be, merging) the RCU read-side critical sections to include all the code between successive quiescent states, for example, all the code between a pair of calls to
schedule().Therefore, there need to be
barrier()calls in the quiescent-state functions. Some could be argued to be implicitly present due to translation-unit boundaries, but paranoia and all that.Would adding that sort of explanation help?
+++
b/include/linux/rcutiny.hinclude/linux/rcutiny.h +1
-0@@ -216,6 +216,7 @@ static inline bool rcu_is_watching(void)static inline void rcu_all_qs (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking across. */ }
Quoted 4 lines
include/linux/rcutiny.h static inline bool rcu_is_watching(void) · line 222
Quoted 1 line
include/linux/rcutiny.h +0
-0#endif /* __LINUX_RCUTINY_H */ This is more than sheer paranoia I think, inlined functions are not a compiler barrier.
Yep, agreed.
Quoted 14 lines
Quoted 14 lines
kernel/rcu/tree.c +1
-0@@ -337,12 +337,14 @@ static void rcu_momentary_dyntick_idle(void)*/ void rcu_note_context_switch (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ trace_rcu_utilization (TPS ("Start context switch" ));rcu_sched_qs ();rcu_preempt_note_context_switch ();if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();
Quoted 8 lines
kernel/rcu/tree.c static void rcu_momentary_dyntick_idle(void) · line 349
Quoted 4 lines
kernel/rcu/tree.c +1
-0trace_rcu_utilization (TPS ("End context switch" )); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_note_context_switch);These OTOH could be fixed with a noinline, such that the compiler may never inline it, even with whole-program-optimizations, thereby guaranteeing a function call boundary or compiler barrier.
I like the barrier() with the comment. I expect it will be a bit more robust against toolchain changes.
Thanx, Paul
Re: [PATCH tip/core/rcu 07/13] rcu: Move preemption disabling out of __srcu_read_lock()
In reply to Peter ZijlstraQuoted 10 lines · Peter Zijlstra
Quoted 7 lines · Paul E. McKenney
Currently,
__srcu_read_lock()cannot be invoked from restricted environments because it contains calls topreempt_disable()andpreempt_enable(), both of which can invoke lockdep, which is a bad idea in some restricted execution modes. This commit therefore moves thepreempt_disable()andpreempt_enable()from__srcu_read_lock()tosrcu_read_lock(). It also inserts thepreempt_disable()andpreempt_enable()around the call to__srcu_read_lock()indo_exit().Did you not simply want to use:
preempt_disable_notrace()?
I believe that tracing the preempt_disable() in srcu_read_lock() and srcu_read_unlock() is actually a good thing. Or am I missing your point?
Thanx, Paul
Peter Zijlstra
maintainerRe: [PATCH tip/core/rcu 10/13] rcu: Add rcu_pointer_handoff()
In reply to Paul E. McKenneyQuoted 13 lines · Paul E. McKenney
/**
+ *rcu_pointer_handoff()- Hand off a pointer from RCU to other mechanism
+ * @p: The pointer to hand off
+ *
+ * This is simply an identity function, but it documents where a pointer
+ * is handed off from RCU to some other synchronization mechanism, for
+ * example, reference counting or locking. In C11, it would map to
+ *kill_dependency(). It could be used as follows:
+ *
+ *rcu_read_lock();
+ * p =rcu_dereference(gp);
+ *long_lived=is_long_lived(p);
+ * if (long_lived) {
Quoted 8 lines
+ * if (!atomic_inc_not_zero(p->refcnt))
+ *long_lived= false;
+ * else
+ * p =rcu_pointer_handoff(p);
+ * }
+ *rcu_read_unlock();
+ */
+#definercu_pointer_handoff(p)(p)
Will you actually be using this? It seems a tad pointless to add if you don't.
Peter Zijlstra
maintainerRe: [PATCH tip/core/rcu 07/13] rcu: Move preemption disabling out of __srcu_read_lock()
In reply to Paul E. McKenneyQuoted 10 lines · Paul E. McKenney
Quoted 9 lines · Peter Zijlstra
Quoted 7 lines · Paul E. McKenney
Currently,
__srcu_read_lock()cannot be invoked from restricted environments because it contains calls topreempt_disable()andpreempt_enable(), both of which can invoke lockdep, which is a bad idea in some restricted execution modes. This commit therefore moves thepreempt_disable()andpreempt_enable()from__srcu_read_lock()tosrcu_read_lock(). It also inserts thepreempt_disable()andpreempt_enable()around the call to__srcu_read_lock()indo_exit().
Quoted 5 lines
Quoted 1 line
Did you not simply want to use:
preempt_disable_notrace()?I believe that tracing the
preempt_disable()insrcu_read_lock()andsrcu_read_unlock()is actually a good thing. Or am I missing your point?
Depends a bit on why we needed this change in the first place -- which, going by the other branch of this thread, seems lost. However, preempt_{dis,en}able_notrace() will not end up in any tracer/lockdep and generate the minimum code that preserves the required semantics.
Peter Zijlstra
maintainerRe: [PATCH tip/core/rcu 04/13] rcu: Don't disable preemption for Tiny and Tree RCU readers
In reply to Paul E. McKenneyQuoted 25 lines · Paul E. McKenney
Quoted 14 lines · Peter Zijlstra
Quoted 14 lines
kernel/rcu/tree.c +1
-0@@ -337,12 +337,14 @@ static void rcu_momentary_dyntick_idle(void)*/ void rcu_note_context_switch (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ trace_rcu_utilization (TPS ("Start context switch" ));rcu_sched_qs ();rcu_preempt_note_context_switch ();if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();Quoted 8 lines
kernel/rcu/tree.c static void rcu_momentary_dyntick_idle(void) · line 349
Quoted 4 lines
kernel/rcu/tree.c +1
-0trace_rcu_utilization (TPS ("End context switch" )); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_note_context_switch);These OTOH could be fixed with a noinline, such that the compiler may never inline it, even with whole-program-optimizations, thereby guaranteeing a function call boundary or compiler barrier.
Quoted 2 lines
I like the
barrier()with the comment. I expect it will be a bit more robust against toolchain changes.
Don't you in fact already rely on the fact that schedule() is a function call and will not be inlined? (it doesn't have noinline and I suppose whole program optimizers could go funny on it).
Re: [PATCH tip/core/rcu 10/13] rcu: Add rcu_pointer_handoff()
In reply to Peter ZijlstraQuoted 23 lines · Peter Zijlstra
Quoted 13 lines · Paul E. McKenney
/**
+ *rcu_pointer_handoff()- Hand off a pointer from RCU to other mechanism
+ * @p: The pointer to hand off
+ *
+ * This is simply an identity function, but it documents where a pointer
+ * is handed off from RCU to some other synchronization mechanism, for
+ * example, reference counting or locking. In C11, it would map to
+ *kill_dependency(). It could be used as follows:
+ *
+ *rcu_read_lock();
+ * p =rcu_dereference(gp);
+ *long_lived=is_long_lived(p);
+ * if (long_lived) {Quoted 8 lines
+ * if (!atomic_inc_not_zero(p->refcnt))
+ *long_lived= false;
+ * else
+ * p =rcu_pointer_handoff(p);
+ * }
+ *rcu_read_unlock();
+ */
+#definercu_pointer_handoff(p)(p)
Quoted 2 lines
Will you actually be using this? It seems a tad pointless to add if you don't.
Some of the LLVM guys believe that they can diagnose RCU pointer leaks if this is used. But yes, it does need to be used.
Thanx, Paul
Re: [PATCH tip/core/rcu 07/13] rcu: Move preemption disabling out of __srcu_read_lock()
In reply to Peter ZijlstraQuoted 13 lines · Peter Zijlstra
Quoted 12 lines · Paul E. McKenney
Quoted 10 lines · Peter Zijlstra
Quoted 7 lines · Paul E. McKenney
Currently,
__srcu_read_lock()cannot be invoked from restricted environments because it contains calls topreempt_disable()andpreempt_enable(), both of which can invoke lockdep, which is a bad idea in some restricted execution modes. This commit therefore moves thepreempt_disable()andpreempt_enable()from__srcu_read_lock()tosrcu_read_lock(). It also inserts thepreempt_disable()andpreempt_enable()around the call to__srcu_read_lock()indo_exit().Did you not simply want to use:
preempt_disable_notrace()?
Quoted 8 lines
Quoted 3 lines
I believe that tracing the
preempt_disable()insrcu_read_lock()andsrcu_read_unlock()is actually a good thing. Or am I missing your point?Depends a bit on why we needed this change in the first place -- which, going by the other branch of this thread, seems lost. However, preempt_{dis,en}able_notrace() will not end up in any tracer/lockdep and generate the minimum code that preserves the required semantics.
True enough! But can all architectures locate the TIF in all contexts?
Thanx, Paul
Re: [PATCH tip/core/rcu 04/13] rcu: Don't disable preemption for Tiny and Tree RCU readers
In reply to Peter ZijlstraQuoted 26 lines · Peter Zijlstra
Quoted 25 lines · Paul E. McKenney
Quoted 22 lines · Peter Zijlstra
Quoted 8 lines
kernel/rcu/tree.c +0
-0@@ -337,12 +337,14 @@ static void rcu_momentary_dyntick_idle(void)*/ void rcu_note_context_switch (void ) {kernel/rcu/tree.c static void rcu_momentary_dyntick_idle(void) · line 349
Quoted 10 lines
kernel/rcu/tree.c +2
-0+barrier ();/* Avoid RCU read-side critical sections leaking down. */ trace_rcu_utilization (TPS ("Start context switch" ));rcu_sched_qs ();rcu_preempt_note_context_switch ();if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();trace_rcu_utilization (TPS ("End context switch" )); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_note_context_switch);These OTOH could be fixed with a noinline, such that the compiler may never inline it, even with whole-program-optimizations, thereby guaranteeing a function call boundary or compiler barrier.
Quoted 6 lines
Quoted 2 lines
I like the
barrier()with the comment. I expect it will be a bit more robust against toolchain changes.Don't you in fact already rely on the fact that
schedule()is a function call and will not be inlined? (it doesn't have noinline and I suppose whole program optimizers could go funny on it).
Probably pretty much everywhere I call schedule(). But I was thinking that barrier() and the beginning and end of an external function didn't need to do anything. Is that incorrect?
Thanx, Paul
Peter Zijlstra
maintainerRe: [PATCH tip/core/rcu 04/13] rcu: Don't disable preemption for Tiny and Tree RCU readers
Quoted 30 lines · Paul E. McKenney
Quoted 29 lines · Peter Zijlstra
Quoted 27 lines · Paul E. McKenney
Quoted 14 lines · Peter Zijlstra
Quoted 14 lines
kernel/rcu/tree.c +1
-0@@ -337,12 +337,14 @@ static void rcu_momentary_dyntick_idle(void)*/ void rcu_note_context_switch (void ) { +barrier ();/* Avoid RCU read-side critical sections leaking down. */ trace_rcu_utilization (TPS ("Start context switch" ));rcu_sched_qs ();rcu_preempt_note_context_switch ();if (unlikely (raw_cpu_read (rcu_sched_qs_mask)))rcu_momentary_dyntick_idle ();Quoted 8 lines
kernel/rcu/tree.c static void rcu_momentary_dyntick_idle(void) · line 349
Quoted 4 lines
kernel/rcu/tree.c +1
-0trace_rcu_utilization (TPS ("End context switch" )); +barrier ();/* Avoid RCU read-side critical sections leaking up. */ }EXPORT_SYMBOL_GPL (rcu_note_context_switch);These OTOH could be fixed with a noinline, such that the compiler may never inline it, even with whole-program-optimizations, thereby guaranteeing a function call boundary or compiler barrier.
I like the
barrier()with the comment. I expect it will be a bit more robust against toolchain changes.
Quoted 7 lines
Quoted 3 lines
Don't you in fact already rely on the fact that
schedule()is a function call and will not be inlined? (it doesn't have noinline and I suppose whole program optimizers could go funny on it).Probably pretty much everywhere I call
schedule(). But I was thinking thatbarrier()and the beginning and end of an external function didn't need to do anything. Is that incorrect?
No. My point was more that by removing barrier() from rcu_read_{un,}lock() you hard rely on schedule() being a compiler barrier, and I was thinking you need it to be a function call for that, but this is incorrect.
Even without it being a function call, there's explicit compiler barriers in there that even whole program optimizers cannot make go away, so my bad for creating confusion.
Peter Zijlstra
maintainerRe: [PATCH tip/core/rcu 07/13] rcu: Move preemption disabling out of __srcu_read_lock()
In reply to Paul E. McKenneyQuoted 18 lines · Paul E. McKenney
Quoted 17 lines · Peter Zijlstra
Quoted 15 lines · Paul E. McKenney
Quoted 10 lines · Peter Zijlstra
Quoted 7 lines · Paul E. McKenney
Currently,
__srcu_read_lock()cannot be invoked from restricted environments because it contains calls topreempt_disable()andpreempt_enable(), both of which can invoke lockdep, which is a bad idea in some restricted execution modes. This commit therefore moves thepreempt_disable()andpreempt_enable()from__srcu_read_lock()tosrcu_read_lock(). It also inserts thepreempt_disable()andpreempt_enable()around the call to__srcu_read_lock()indo_exit().Did you not simply want to use:
preempt_disable_notrace()?I believe that tracing the
preempt_disable()insrcu_read_lock()andsrcu_read_unlock()is actually a good thing. Or am I missing your point?
Quoted 6 lines
Quoted 4 lines
Depends a bit on why we needed this change in the first place -- which, going by the other branch of this thread, seems lost. However, preempt_{dis,en}able_notrace() will not end up in any tracer/lockdep and generate the minimum code that preserves the required semantics.
True enough! But can all architectures locate the TIF in all contexts?
They had better, otherwise we have a problem with NMIs touching it :-)
Peter Zijlstra
maintainerRe: [PATCH tip/core/rcu 10/13] rcu: Add rcu_pointer_handoff()
In reply to Paul E. McKenneyQuoted 24 lines · Paul E. McKenney
Quoted 23 lines · Peter Zijlstra
Quoted 21 lines · Paul E. McKenney
/**
+ *rcu_pointer_handoff()- Hand off a pointer from RCU to other mechanism
+ * @p: The pointer to hand off
+ *
+ * This is simply an identity function, but it documents where a pointer
+ * is handed off from RCU to some other synchronization mechanism, for
+ * example, reference counting or locking. In C11, it would map to
+ *kill_dependency(). It could be used as follows:
+ *
+ *rcu_read_lock();
+ * p =rcu_dereference(gp);
+ *long_lived=is_long_lived(p);
+ * if (long_lived) {
+ * if (!atomic_inc_not_zero(p->refcnt))
+ *long_lived= false;
+ * else
+ * p =rcu_pointer_handoff(p);
+ * }
+ *rcu_read_unlock();
+ */
+#definercu_pointer_handoff(p)(p)
Quoted 5 lines
Quoted 2 lines
Will you actually be using this? It seems a tad pointless to add if you don't.
Some of the LLVM guys believe that they can diagnose RCU pointer leaks if this is used. But yes, it does need to be used.
The thing is, I'm not convinced this is a 'sane' interface. Its _far_ too easy to forget. It doesn't make any kind of sense either, which is part of why its hard to remember.
Re: [PATCH tip/core/rcu 07/13] rcu: Move preemption disabling out of __srcu_read_lock()
In reply to Peter ZijlstraQuoted 19 lines · Peter Zijlstra
Quoted 18 lines · Paul E. McKenney
Quoted 17 lines · Peter Zijlstra
Quoted 15 lines · Paul E. McKenney
Quoted 10 lines · Peter Zijlstra
Quoted 7 lines · Paul E. McKenney
Currently,
__srcu_read_lock()cannot be invoked from restricted environments because it contains calls topreempt_disable()andpreempt_enable(), both of which can invoke lockdep, which is a bad idea in some restricted execution modes. This commit therefore moves thepreempt_disable()andpreempt_enable()from__srcu_read_lock()tosrcu_read_lock(). It also inserts thepreempt_disable()andpreempt_enable()around the call to__srcu_read_lock()indo_exit().Did you not simply want to use:
preempt_disable_notrace()?I believe that tracing the
preempt_disable()insrcu_read_lock()andsrcu_read_unlock()is actually a good thing. Or am I missing your point?
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
Depends a bit on why we needed this change in the first place -- which, going by the other branch of this thread, seems lost. However, preempt_{dis,en}able_notrace() will not end up in any tracer/lockdep and generate the minimum code that preserves the required semantics.
True enough! But can all architectures locate the TIF in all contexts?
They had better, otherwise we have a problem with NMIs touching it :-)
Fair enough! ;-)
Thanx, Paul
Re: [PATCH tip/core/rcu 10/13] rcu: Add rcu_pointer_handoff()
In reply to Peter ZijlstraQuoted 28 lines · Peter Zijlstra
Quoted 27 lines · Paul E. McKenney
Quoted 25 lines · Peter Zijlstra
Quoted 13 lines · Paul E. McKenney
/**
+ *rcu_pointer_handoff()- Hand off a pointer from RCU to other mechanism
+ * @p: The pointer to hand off
+ *
+ * This is simply an identity function, but it documents where a pointer
+ * is handed off from RCU to some other synchronization mechanism, for
+ * example, reference counting or locking. In C11, it would map to
+ *kill_dependency(). It could be used as follows:
+ *
+ *rcu_read_lock();
+ * p =rcu_dereference(gp);
+ *long_lived=is_long_lived(p);
+ * if (long_lived) {Quoted 8 lines
+ * if (!atomic_inc_not_zero(p->refcnt))
+ *long_lived= false;
+ * else
+ * p =rcu_pointer_handoff(p);
+ * }
+ *rcu_read_unlock();
+ */
+#definercu_pointer_handoff(p)(p)Will you actually be using this? It seems a tad pointless to add if you don't.
Quoted 6 lines
Quoted 2 lines
Some of the LLVM guys believe that they can diagnose RCU pointer leaks if this is used. But yes, it does need to be used.
The thing is, I'm not convinced this is a 'sane' interface. Its _far_ too easy to forget. It doesn't make any kind of sense either, which is part of why its hard to remember.
Indeed, the only thing that would make it easy to remember is if there are tools that check for pointer leaks from RCU read-side critical sections. But without this interface, such tools are insanely difficult to create. So there is a chicken-and-egg problem here, which I am attempting to deal with by providing an egg. Hopefully not laying an egg, but time will tell. ;-)
Thanx, Paul
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference()
In reply to Paul E. McKenneyQuoted 30 lines · Paul E. McKenney
From: Patrick Marlier <[email protected]>
The current
list_entry_rcu()implementation copies the pointer to a stack variable, then invokesrcu_dereference_raw()on it. This results in an additional store-load pair. Now, most compilers will emit normal store and load instructions, which might seem to be of negligible overhead, but this results in a load-hit-store situation that can cause surprisingly long pipeline stalls, even on modern microprocessors. The problem is that it takes time for the store to get the store buffer updated, which can delay the subsequent load, which immediately follows.This commit therefore switches to the
lockless_dereference()primitive, which does not expect the__rcuannotations (that are anyway not present in thelist_headstructure) and which, likercu_dereference_raw(), does not check for an enclosing RCU read-side critical section. Most importantly, it does not copy the pointer, thus avoiding the load-hit-store overhead.Signed-off-by Patrick Marlier <[email protected]>[ paulmck: Switched to lockless_dereference() to suppress sparse warnings. ]Signed-off-by Paul E. McKenney <[email protected]>--- include/linux/rculist.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)include/linux/rculist.h +0
-0
include/linux/rculist.h static inline void list_splice_init_rcu(struct list_head *list, · line 250
Quoted 8 lines
include/linux/rculist.h +1
-4@@ -247,10 +247,7 @@ static inline void list_splice_init_rcu(struct list_head *list,* primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). */ #define list_entry_rcu (ptr, type, member) \ -({ \ - typeof(*ptr) __rcu *__ptr = (typeof(*ptr) __rcu __force *)ptr; \ - container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member); \ -}) + container_of(lockless_dereference(ptr), type, member)
So this commit:
8db70b132dd5 ("rculist: Make list_entry_rcu() use lockless_dereference()")
when merged with Linus's latest tree, triggers the following build failure on allyesconfig/allmodconfig x86:
triton:~/tip> make fs/fs-writeback.o
CHK include/config/kernel.release
CHK include/generated/uapi/linux/version.h
CHK include/generated/utsrelease.h
CHK include/generated/bounds.h
CHK include/generated/timeconst.h
CHK include/generated/asm-offsets.h
CALL scripts/checksyscalls.sh
CC fs/fs-writeback.o
In file included from fs/fs-writeback.c:16:0:
fs/fs-writeback.c: In function ‘bdi_split_work_to_wbs’:
include/linux/compiler.h:281:20: error: lvalue required as unary ‘&’ operand
__read_once_size(&(x), __u.__c, sizeof(x)); \
^
include/linux/kernel.h:811:49: note: in definition of macro ‘container_of’
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
^
include/linux/compiler.h:286:22: note: in expansion of macro ‘__READ_ONCE’
#define READ_ONCE(x) __READ_ONCE(x, 1)
^
include/linux/compiler.h:533:26: note: in expansion of macro ‘READ_ONCE’
typeof(p) _________p1 = READ_ONCE(p); \
^
include/linux/rculist.h:250:15: note: in expansion of macro ‘lockless_dereference’
container_of(lockless_dereference(ptr), type, member)
^
fs/fs-writeback.c:782:29: note: in expansion of macro ‘list_entry_rcu’
struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
^
include/linux/compiler.h:283:28: error: lvalue required as unary ‘&’ operand
__read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \
^
include/linux/kernel.h:811:49: note: in definition of macro ‘container_of’
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
^
include/linux/compiler.h:286:22: note: in expansion of macro ‘__READ_ONCE’
#define READ_ONCE(x) __READ_ONCE(x, 1)
^
include/linux/compiler.h:533:26: note: in expansion of macro ‘READ_ONCE’
typeof(p) _________p1 = READ_ONCE(p); \
^
include/linux/rculist.h:250:15: note: in expansion of macro ‘lockless_dereference’
container_of(lockless_dereference(ptr), type, member)
^
fs/fs-writeback.c:782:29: note: in expansion of macro ‘list_entry_rcu’
struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
^scripts/Makefile.build:258: recipe for target 'fs/fs-writeback.o' failed make[1]: *** [fs/fs-writeback.o] Error 1
Makefile:1526: recipe for target 'fs/fs-writeback.o' failed
make: *** [fs/fs-writeback.o] Error 2
It's this new usage in fs/fs-writeback.c:
static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
struct wb_writeback_work *base_work, bool skip_if_busy)
{
struct bdi_writeback *last_wb = NULL;
struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
struct bdi_writeback, bdi_node);so AFAICS the problem is lockless_dereference() not being able to take this valid but non-lvalue list head, because READ_ONCE() does not take non-lvalues. All other existing uses of list_entry_rcu() happen to use lvalues, so this bug didn't get triggered before.
For now I've reverted this commit locally, to make the kernel build and so, but we need a cleaner solution I suspect.
Thanks,
Ingo
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference()
Quoted 101 lines · Ingo Molnar
Quoted 30 lines · Paul E. McKenney
From: Patrick Marlier <[email protected]>
The current
list_entry_rcu()implementation copies the pointer to a stack variable, then invokesrcu_dereference_raw()on it. This results in an additional store-load pair. Now, most compilers will emit normal store and load instructions, which might seem to be of negligible overhead, but this results in a load-hit-store situation that can cause surprisingly long pipeline stalls, even on modern microprocessors. The problem is that it takes time for the store to get the store buffer updated, which can delay the subsequent load, which immediately follows.This commit therefore switches to the
lockless_dereference()primitive, which does not expect the__rcuannotations (that are anyway not present in thelist_headstructure) and which, likercu_dereference_raw(), does not check for an enclosing RCU read-side critical section. Most importantly, it does not copy the pointer, thus avoiding the load-hit-store overhead.Signed-off-by Patrick Marlier <[email protected]>[ paulmck: Switched to lockless_dereference() to suppress sparse warnings. ]Signed-off-by Paul E. McKenney <[email protected]>--- include/linux/rculist.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)include/linux/rculist.h +0
-0include/linux/rculist.h static inline void list_splice_init_rcu(struct list_head *list, · line 250
Quoted 8 lines
include/linux/rculist.h +1
-4@@ -247,10 +247,7 @@ static inline void list_splice_init_rcu(struct list_head *list,* primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). */ #define list_entry_rcu (ptr, type, member) \ -({ \ - typeof(*ptr) __rcu *__ptr = (typeof(*ptr) __rcu __force *)ptr; \ - container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member); \ -}) + container_of(lockless_dereference(ptr), type, member)So this commit:
8db70b132dd5("rculist: Makelist_entry_rcu()uselockless_dereference()")when merged with Linus's latest tree, triggers the following build failure on allyesconfig/allmodconfig x86:
triton:~/tip> make
fs/fs-writeback.oCHK include/config/kernel.release CHK include/generated/uapi/linux/version.h CHK include/generated/utsrelease.h CHK include/generated/bounds.h CHK include/generated/timeconst.h CHK include/generated/asm-offsets.h CALL scripts/checksyscalls.sh CC fs/fs-writeback.o In file included from fs/fs-writeback.c:16:0: fs/fs-writeback.c: In function ‘bdi_split_work_to_wbs’: include/linux/compiler.h:281:20: error: lvalue required as unary ‘&’ operand __read_once_size(&(x), __u.__c, sizeof(x)); \ ^ include/linux/kernel.h:811:49: note: in definition of macro ‘container_of’ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ include/linux/compiler.h:286:22: note: in expansion of macro ‘__READ_ONCE’ #define READ_ONCE(x) __READ_ONCE(x, 1) ^ include/linux/compiler.h:533:26: note: in expansion of macro ‘READ_ONCE’ typeof(p) _________p1 = READ_ONCE(p); \ ^ include/linux/rculist.h:250:15: note: in expansion of macro ‘lockless_dereference’ container_of(lockless_dereference(ptr), type, member) ^ fs/fs-writeback.c:782:29: note: in expansion of macro ‘list_entry_rcu’ struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list, ^ include/linux/compiler.h:283:28: error: lvalue required as unary ‘&’ operand __read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \ ^ include/linux/kernel.h:811:49: note: in definition of macro ‘container_of’ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ include/linux/compiler.h:286:22: note: in expansion of macro ‘__READ_ONCE’ #define READ_ONCE(x) __READ_ONCE(x, 1) ^ include/linux/compiler.h:533:26: note: in expansion of macro ‘READ_ONCE’ typeof(p) _________p1 = READ_ONCE(p); \ ^ include/linux/rculist.h:250:15: note: in expansion of macro ‘lockless_dereference’ container_of(lockless_dereference(ptr), type, member) ^ fs/fs-writeback.c:782:29: note: in expansion of macro ‘list_entry_rcu’ struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list, ^
scripts/Makefile.build:258: recipe for target 'fs/fs-writeback.o' failed make[1]: *** [fs/fs-writeback.o] Error 1
Makefile:1526: recipe for target 'fs/fs-writeback.o' failed
make: *** [fs/fs-writeback.o] Error 2
Quoted 8 lines
It's this new usage in
fs/fs-writeback.c:static void bdi_split_work_to_wbs(struct
backing_dev_info*bdi,
structwb_writeback_work*base_work, boolskip_if_busy){ struct bdi_writeback *last_wb = NULL; struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
I believe that the above should instead be:
struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,
After all, RCU read-side list primitives need to fetch pointers in order to traverse those pointers in an RCU-safe manner. The patch below clears this up for me, does it also work for you?
Thanx, Paul
------------------------------------------------------------------------
commit 9221c4e78cc3511cd15b1433617ae2548ad8f631
Author: Paul E. McKenney <[email protected]> Date: Mon Oct 26 07:47:20 2015 -0700
fs: Fix argument to list_entry_rcu()
The list_entry_rcu() macro requires that its first argument be the pointer to the list_head contained in the structure whose pointer is to be returned, but fetched in an RCU-safe manner. This commit therefore fixes the use in bdi_split_work_to_wbs() to follow this convention.
fs/fs-writeback.c +1 -1
@@ -779,7 +779,7 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, bool skip_if_busy) {struct bdi_writeback *last_wb =NULL ; -struct bdi_writeback *wb =list_entry_rcu (&bdi->wb_list, +struct bdi_writeback *wb =list_entry_rcu (bdi->wb_list.next, struct bdi_writeback, bdi_node);might_sleep ();
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference()
Quoted 9 lines · Paul E. McKenney
Quoted 8 lines
It's this new usage in
fs/fs-writeback.c:static void bdi_split_work_to_wbs(struct
backing_dev_info*bdi,
structwb_writeback_work*base_work, boolskip_if_busy){ struct bdi_writeback *last_wb = NULL; struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
Quoted 7 lines
I believe that the above should instead be:
struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,After all, RCU read-side list primitives need to fetch pointers in order to traverse those pointers in an RCU-safe manner. The patch below clears this up for me, does it also work for you?
Are you sure about that?
I considered this solution too, but the code goes like this:
static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
struct wb_writeback_work *base_work, bool skip_if_busy)
{
struct bdi_writeback *last_wb = NULL;
struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
struct bdi_writeback, bdi_node);
might_sleep();
restart:
rcu_read_lock();
list_for_each_entry_continue_rcu(wb, &bdi->wb_list, bdi_node) {and list_for_each_entry_continue_rcu() will start the iteration with the next entry. So if you initialize the head with .next, then we'll start with .next->next, i.e. we skip the first entry.
That seems to change behavior and break the logic.
Another solution I considered is to use bd->wb_list.next->prev, but that, beyond being ugly, causes actual extra runtime overhead - for something that seems academical.
Thanks,
Ingo
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference()
In reply to Paul E. McKenneyQuoted 6 lines · Paul E. McKenney
Quoted 2 lines
struct bdi_writeback *last_wb = NULL; struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,I believe that the above should instead be:
struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,
I don't think you can do that.
You haven't even taken the RCU read lock yet at this point.
What the code seems to try to do is to get the "head pointer" of the list before taking the read lock (since _that_ is stable), and then follow the list under the lock.
You're making it actually follow the first RCU pointer too early.
That said, I'm not sure why it doesn't just do the normal
rcu_read_lock();
list_for_each_entry_rcu(wb, &bdi->wb_list, bdi_node) {
....
}
rcu_read_unlock();like the other places do. It looks like it wants that "list_for_each_entry_continue_rcu()" because it does that odd "pin entry and drop rcu lock and retake it and continue where you left off", but I'm not sure why the continue version would be so different.. It's going to do that "follow next entry" regardless, and the "goto restart" doesn't look like it actually adds anything. If following the next pointer is ok even after having released the RCU read lock, then I'm not seeing why the end of the loop couldn't just do
rcu_read_unlock();
wb_wait_for_completion(bdi, &fallback_work_done);
rcu_read_lock();and just continue the loop (and the pinning of "wb" and releasing the "last_wb" thing in the *next* iteration should make it all work the same).
Adding Tejun to the cc, because this is his code and there's probably something subtle I'm missing. Tejun, can you take a look? It's bdi_split_work_to_wbs() in fs/fs-writeback.c.
Linus
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference()
Hello,
Quoted 3 lines · Linus Torvalds
Quoted 3 lines
I believe that the above should instead be:
struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,
I should have just used list_entry() here. It's just offseting the pointer to set up the initial iteration point.
...
Quoted 22 lines
That said, I'm not sure why it doesn't just do the normal
rcu_read_lock(); list_for_each_entry_rcu(wb, &bdi->wb_list, bdi_node) { .... } rcu_read_unlock();like the other places do. It looks like it wants that "
list_for_each_entry_continue_rcu()" because it does that odd "pin entry and drop rcu lock and retake it and continue where you left off", but I'm not sure why the continue version would be so different.. It's going to do that "follow next entry" regardless, and the "goto restart" doesn't look like it actually adds anything. If following the next pointer is ok even after having released the RCU read lock, then I'm not seeing why the end of the loop couldn't just dorcu_read_unlock(); wb_wait_for_completion(bdi, &fallback_work_done); rcu_read_lock();
Quoted 7 lines
and just continue the loop (and the pinning of "wb" and releasing the "
last_wb" thing in the *next* iteration should make it all work the same).Adding Tejun to the cc, because this is his code and there's probably something subtle I'm missing. Tejun, can you take a look? It's
bdi_split_work_to_wbs()infs/fs-writeback.c.
Yeah, just releasing and regrabbing should work too as the iterator doesn't depend on anything other than the current entry (e.g. as opposed to imaginary list_for_each_entry_safe_rcu()). It's slightly icky to meddle with locking behind the iterator's back tho. Either way should be fine but how about something like the following?
Subject: writeback: don't use list_entry_rcu() for pointer offsetting in bdi_split_work_to_wbs()
bdi_split_work_to_wbs() uses list_for_each_entry_rcu_continue() to walk @bdi->wb_list. To set up the initial iteration condition, it uses list_entry_rcu() to calculate the entry pointer corresponding to the list head; however, this isn't an actual RCU dereference and using list_entry_rcu() for it ended up breaking a proposed list_entry_rcu() change because it was feeding an non-lvalue pointer into the macro.
Don't use the RCU variant for simple pointer offsetting. Use list_entry() instead.
--- fs/fs-writeback.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/fs-writeback.c +2 -2
@@ -779,8 +779,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, bool skip_if_busy) {struct bdi_writeback *last_wb =NULL ; -struct bdi_writeback *wb =list_entry_rcu (&bdi->wb_list, - struct bdi_writeback, bdi_node); +struct bdi_writeback *wb =list_entry (&bdi->wb_list, + struct bdi_writeback, bdi_node);might_sleep (); restart:
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference()
In reply to Linus TorvaldsQuoted 11 lines · Linus Torvalds
Quoted 6 lines · Paul E. McKenney
Quoted 2 lines
struct bdi_writeback *last_wb = NULL; struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,I believe that the above should instead be:
struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,I don't think you can do that.
Quoted 7 lines
You haven't even taken the RCU read lock yet at this point.
What the code seems to try to do is to get the "head pointer" of the list before taking the read lock (since _that_ is stable), and then follow the list under the lock.
You're making it actually follow the first RCU pointer too early.
Good point, color me dazed and confused. :-/
Thanx, Paul
Quoted 32 lines
That said, I'm not sure why it doesn't just do the normal
rcu_read_lock(); list_for_each_entry_rcu(wb, &bdi->wb_list, bdi_node) { .... } rcu_read_unlock();like the other places do. It looks like it wants that "
list_for_each_entry_continue_rcu()" because it does that odd "pin entry and drop rcu lock and retake it and continue where you left off", but I'm not sure why the continue version would be so different.. It's going to do that "follow next entry" regardless, and the "goto restart" doesn't look like it actually adds anything. If following the next pointer is ok even after having released the RCU read lock, then I'm not seeing why the end of the loop couldn't just dorcu_read_unlock(); wb_wait_for_completion(bdi, &fallback_work_done); rcu_read_lock();and just continue the loop (and the pinning of "wb" and releasing the "
last_wb" thing in the *next* iteration should make it all work the same).Adding Tejun to the cc, because this is his code and there's probably something subtle I'm missing. Tejun, can you take a look? It's
bdi_split_work_to_wbs()infs/fs-writeback.c.Linus
Paul E. McKenney
Acked-byRe: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference()
In reply to Tejun HeoQuoted 9 lines · Tejun Heo
Hello,
Quoted 3 lines · Linus Torvalds
Quoted 3 lines
I believe that the above should instead be:
struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,I should have just used
list_entry()here. It's just offseting the pointer to set up the initial iteration point.
OK, that sounds much better!
Quoted 46 lines
...
Quoted 22 lines
That said, I'm not sure why it doesn't just do the normal
rcu_read_lock(); list_for_each_entry_rcu(wb, &bdi->wb_list, bdi_node) { .... } rcu_read_unlock();like the other places do. It looks like it wants that "
list_for_each_entry_continue_rcu()" because it does that odd "pin entry and drop rcu lock and retake it and continue where you left off", but I'm not sure why the continue version would be so different.. It's going to do that "follow next entry" regardless, and the "goto restart" doesn't look like it actually adds anything. If following the next pointer is ok even after having released the RCU read lock, then I'm not seeing why the end of the loop couldn't just dorcu_read_unlock(); wb_wait_for_completion(bdi, &fallback_work_done); rcu_read_lock();Quoted 7 lines
and just continue the loop (and the pinning of "wb" and releasing the "
last_wb" thing in the *next* iteration should make it all work the same).Adding Tejun to the cc, because this is his code and there's probably something subtle I'm missing. Tejun, can you take a look? It's
bdi_split_work_to_wbs()infs/fs-writeback.c.Yeah, just releasing and regrabbing should work too as the iterator doesn't depend on anything other than the current entry (e.g. as opposed to imaginary
list_for_each_entry_safe_rcu()). It's slightly icky to meddle with locking behind the iterator's back tho. Either way should be fine but how about something like the following?Subject: writeback: don't use
list_entry_rcu()for pointer offsetting inbdi_split_work_to_wbs()
bdi_split_work_to_wbs()useslist_for_each_entry_rcu_continue()to walk @bdi->wb_list. To set up the initial iteration condition, it useslist_entry_rcu()to calculate the entry pointer corresponding to the list head; however, this isn't an actual RCU dereference and usinglist_entry_rcu()for it ended up breaking a proposedlist_entry_rcu()change because it was feeding an non-lvalue pointer into the macro.
Quoted 4 lines
Don't use the RCU variant for simple pointer offsetting. Use
list_entry()instead.Signed-off-by Tejun Heo <[email protected]>
Quoted 20 lines
--- fs/fs-writeback.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)fs/fs-writeback.c +2
-2@@ -779,8 +779,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, bool skip_if_busy) {struct bdi_writeback *last_wb =NULL ; -struct bdi_writeback *wb =list_entry_rcu (&bdi->wb_list, - struct bdi_writeback, bdi_node); +struct bdi_writeback *wb =list_entry (&bdi->wb_list, + struct bdi_writeback, bdi_node);might_sleep (); restart:
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference()
In reply to Tejun HeoQuoted 22 lines · Tejun Heo
Subject: writeback: don't use
list_entry_rcu()for pointer offsetting inbdi_split_work_to_wbs()
bdi_split_work_to_wbs()useslist_for_each_entry_rcu_continue()to walk @bdi->wb_list. To set up the initial iteration condition, it useslist_entry_rcu()to calculate the entry pointer corresponding to the list head; however, this isn't an actual RCU dereference and usinglist_entry_rcu()for it ended up breaking a proposedlist_entry_rcu()change because it was feeding an non-lvalue pointer into the macro.Don't use the RCU variant for simple pointer offsetting. Use
list_entry()instead.Signed-off-by Tejun Heo <[email protected]>--- fs/fs-writeback.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)fs/fs-writeback.c +0
-0
fs/fs-writeback.c static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, · line 785
Quoted 9 lines
fs/fs-writeback.c +2
-2@@ -779,8 +779,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, bool skip_if_busy) {struct bdi_writeback *last_wb =NULL ; -struct bdi_writeback *wb =list_entry_rcu (&bdi->wb_list, - struct bdi_writeback, bdi_node); +struct bdi_writeback *wb =list_entry (&bdi->wb_list, + struct bdi_writeback, bdi_node);might_sleep ();
Any objections against me applying this fix to tip:core/rcu so that I can push the recent RCU changes towards linux-next without triggering a build failure?
Thanks,
Ingo
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference()
Quoted 33 lines · Ingo Molnar
Quoted 30 lines · Tejun Heo
Subject: writeback: don't use
list_entry_rcu()for pointer offsetting inbdi_split_work_to_wbs()
bdi_split_work_to_wbs()useslist_for_each_entry_rcu_continue()to walk @bdi->wb_list. To set up the initial iteration condition, it useslist_entry_rcu()to calculate the entry pointer corresponding to the list head; however, this isn't an actual RCU dereference and usinglist_entry_rcu()for it ended up breaking a proposedlist_entry_rcu()change because it was feeding an non-lvalue pointer into the macro.Don't use the RCU variant for simple pointer offsetting. Use
list_entry()instead.Signed-off-by Tejun Heo <[email protected]>--- fs/fs-writeback.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)fs/fs-writeback.c +2
-2@@ -779,8 +779,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, bool skip_if_busy) {struct bdi_writeback *last_wb =NULL ; -struct bdi_writeback *wb =list_entry_rcu (&bdi->wb_list, - struct bdi_writeback, bdi_node); +struct bdi_writeback *wb =list_entry (&bdi->wb_list, + struct bdi_writeback, bdi_node);
Quoted 4 lines
fs/fs-writeback.c static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, · line 785
Quoted 1 line
fs/fs-writeback.c +0
-0might_sleep ();Any objections against me applying this fix to tip:core/rcu so that I can push the recent RCU changes towards linux-next without triggering a build failure?
No objection on my side but probably you are waiting for an ack from somebody else. --
Pat
tip-bot for Tejun Heo
merge bot[tip:core/rcu] fs/writeback, rcu: Don't use list_entry_rcu() for pointer offsetting in bdi_split_work_to_wbs()
In reply to Tejun Heofs/writeback, rcu: Don't use list_entry_rcu() for pointer offsetting in bdi_split_work_to_wbs()
Commit-ID: b33e18f61bd18227a456016a77b1a968f5bc1d65 Gitweb: http://git.kernel.org/tip/b33e18f61bd18227a456016a77b1a968f5bc1d65 Author: Tejun Heo <[email protected]> AuthorDate: Tue, 27 Oct 2015 14:19:39 +0900 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 28 Oct 2015 13:17:30 +0100
fs/writeback, rcu: Don't use list_entry_rcu() for pointer offsetting in bdi_split_work_to_wbs()
bdi_split_work_to_wbs() uses list_for_each_entry_rcu_continue() to walk @bdi->wb_list. To set up the initial iteration condition, it uses list_entry_rcu() to calculate the entry pointer corresponding to the list head; however, this isn't an actual RCU dereference and using list_entry_rcu() for it ended up breaking a proposed list_entry_rcu() change because it was feeding an non-lvalue pointer into the macro.
Don't use the RCU variant for simple pointer offsetting. Use list_entry() instead.
--- fs/fs-writeback.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/fs-writeback.c +2 -2
@@ -779,8 +779,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, bool skip_if_busy) {struct bdi_writeback *last_wb =NULL ; -struct bdi_writeback *wb =list_entry_rcu (&bdi->wb_list, - struct bdi_writeback, bdi_node); +struct bdi_writeback *wb =list_entry (&bdi->wb_list, + struct bdi_writeback, bdi_node);might_sleep (); restart:
Paul E. McKenney
Acked-byRe: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference()
In reply to Patrick MarlierQuoted 36 lines · Patrick Marlier
Quoted 33 lines · Ingo Molnar
Quoted 30 lines · Tejun Heo
Subject: writeback: don't use
list_entry_rcu()for pointer offsetting inbdi_split_work_to_wbs()
bdi_split_work_to_wbs()useslist_for_each_entry_rcu_continue()to walk @bdi->wb_list. To set up the initial iteration condition, it useslist_entry_rcu()to calculate the entry pointer corresponding to the list head; however, this isn't an actual RCU dereference and usinglist_entry_rcu()for it ended up breaking a proposedlist_entry_rcu()change because it was feeding an non-lvalue pointer into the macro.Don't use the RCU variant for simple pointer offsetting. Use
list_entry()instead.Signed-off-by Tejun Heo <[email protected]>--- fs/fs-writeback.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)fs/fs-writeback.c +2
-2@@ -779,8 +779,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, bool skip_if_busy) {struct bdi_writeback *last_wb =NULL ; -struct bdi_writeback *wb =list_entry_rcu (&bdi->wb_list, - struct bdi_writeback, bdi_node); +struct bdi_writeback *wb =list_entry (&bdi->wb_list, + struct bdi_writeback, bdi_node);
Quoted 7 lines
Quoted 4 lines
fs/fs-writeback.c static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, · line 785
Quoted 1 line
fs/fs-writeback.c +0
-0might_sleep ();Any objections against me applying this fix to tip:core/rcu so that I can push the recent RCU changes towards linux-next without triggering a build failure?
No objection on my side but probably you are waiting for an ack from somebody else.
I am guessing that he was asking Tejun, but just for the record, I am OK with it as well:
Thanx, Paul
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference()
Quoted 10 lines · Paul E. McKenney
Quoted 5 lines
Quoted 2 lines
Any objections against me applying this fix to tip:core/rcu so that I can push the recent RCU changes towards linux-next without triggering a build failure?
No objection on my side but probably you are waiting for an ack from somebody else.
I am guessing that he was asking Tejun, but just for the record, I am OK with it as well:
Acked-by Paul E. McKenney <[email protected]>
Oops, sorry, for some reason I thought Ingo was asking someone else. The patch already got applied but yes routing it through -tip sounds good.
Thanks.
Signature · 1 line
tejun