Miscellaneous fixes for 4.2
Subsystems (8)
PATCH 3/15 rcu: Eliminate a few RCU_BOOST #ifdefs in favor of IS_ENABLED()
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
This commit removes a few RCU_BOOST #ifdefs, replacing them with IS_ENABLED()-protected return statements. This relies on the optimizer to remove any resulting dead code. There are several other RCU_BOOST #ifdefs, however these rely on some per-CPU variables that are available only under RCU_BOOST. These might be converted later, if the simplification proves to outweigh the increase in memory footprint. One hoped-for advantage is more easily locating compiler errors in obscure combinations of Kconfig parameters.
--- kernel/rcu/tree.h | 2 -- kernel/rcu/tree_plugin.h | 35 ++++++++++++++++++++--------------- 2 files changed, 20 insertions(+), 17 deletions(-)
kernel/rcu/tree.h +0 -2
@@ -170,7 +170,6 @@ struct rcu_node {/* if there is no such task. If there */ /* is no current expedited grace period, */ /* then there can cannot be any such task. */ -#ifdef CONFIG_RCU_BOOST struct list_head *boost_tasks;/* Pointer to first task that needs to be */ /* priority boosted, or NULL if no priority */
@@ -208,7 +207,6 @@ struct rcu_node {unsigned long n_balk_nos;/* Refused to boost: not sure why, though. */ /* This can happen due to race conditions. */ -#endif /* #ifdef CONFIG_RCU_BOOST */ #ifdef CONFIG_RCU_NOCB_CPU wait_queue_head_t nocb_gp_wq[2 ];/* Place for rcu_nocb_kthread() to wait GP. */
kernel/rcu/tree_plugin.h +20 -15
@@ -43,7 +43,17 @@ DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status); DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_loops);DEFINE_PER_CPU (char, rcu_cpu_has_work); -#endif /* #ifdef CONFIG_RCU_BOOST */ +#else /* #ifdef CONFIG_RCU_BOOST */ + +/* +* Some architectures do not define rt_mutexes, but if !CONFIG_RCU_BOOST, +* all uses are in dead code. Provide a definition to keep the compiler +* happy, but add WARN_ON_ONCE() to complain if used in the wrong place. +* This probably needs to be excluded from -rt builds. +*/ +#define rt_mutex_owner (a) ({ WARN_ON_ONCE(1); NULL; }) + +#endif /* #else #ifdef CONFIG_RCU_BOOST */ #ifdef CONFIG_RCU_NOCB_CPU static cpumask_var_t rcu_nocb_mask;/* CPUs to have callbacks offloaded. */
@@ -180,10 +190,9 @@ static void rcu_preempt_note_context_switch(void)if ((rnp->qsmask & rdp->grpmask) && rnp->gp_tasks !=NULL ) {list_add (&t->rcu_node_entry, rnp->gp_tasks->prev); rnp->gp_tasks = &t->rcu_node_entry; -#ifdef CONFIG_RCU_BOOST -if (rnp->boost_tasks !=NULL ) +if (IS_ENABLED (CONFIG_RCU_BOOST ) && + rnp->boost_tasks !=NULL ) rnp->boost_tasks = rnp->gp_tasks; -#endif /* #ifdef CONFIG_RCU_BOOST */ }else {list_add (&t->rcu_node_entry, &rnp->blkd_tasks);if (rnp->qsmask & rdp->grpmask)
@@ -263,9 +272,7 @@ void rcu_read_unlock_special(struct task_struct *t)bool empty_exp_now;unsigned long flags;struct list_head *np; -#ifdef CONFIG_RCU_BOOST bool drop_boost_mutex = false; -#endif /* #ifdef CONFIG_RCU_BOOST */ struct rcu_node *rnp;union rcu_special special;
@@ -331,12 +338,12 @@ void rcu_read_unlock_special(struct task_struct *t) rnp->gp_tasks = np;if (&t->rcu_node_entry == rnp->exp_tasks) rnp->exp_tasks = np; -#ifdef CONFIG_RCU_BOOST -if (&t->rcu_node_entry == rnp->boost_tasks) - rnp->boost_tasks = np; -/* Snapshot ->boost_mtx ownership with rcu_node lock held. */ - drop_boost_mutex =rt_mutex_owner (&rnp->boost_mtx) == t; -#endif /* #ifdef CONFIG_RCU_BOOST */ +if (IS_ENABLED (CONFIG_RCU_BOOST )) { +if (&t->rcu_node_entry == rnp->boost_tasks) + rnp->boost_tasks = np; +/* Snapshot ->boost_mtx ownership w/rnp->lock held. */ + drop_boost_mutex =rt_mutex_owner (&rnp->boost_mtx) == t; + }/* * If this was the last task on the current list, and if
@@ -358,11 +365,9 @@ void rcu_read_unlock_special(struct task_struct *t)raw_spin_unlock_irqrestore (&rnp->lock, flags); } -#ifdef CONFIG_RCU_BOOST /* Unboost if we were boosted. */ -if (drop_boost_mutex) +if (IS_ENABLED (CONFIG_RCU_BOOST ) && drop_boost_mutex)rt_mutex_unlock (&rnp->boost_mtx); -#endif /* #ifdef CONFIG_RCU_BOOST */ /* * If this was the last task on the expedited lists,
Signature · 1 line
1.8.1.5
PATCH 5/15 rcu: Create an immutable rcu_data_p pointer to default rcu_data structure
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
This commit creates an immutable rcu_data_p pointer that references rcu_preempt_data for TREE_PREEMPT_RCU builds and that references rcu_sched_data for TREE_RCU builds. This rcu_data_p pointer will enable more code to move from #ifdef to IS_ENABLED().
--- kernel/rcu/tree.c | 1 + kernel/rcu/tree_plugin.h | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-)
kernel/rcu/tree.c +1 -0
@@ -111,6 +111,7 @@ RCU_STATE_INITIALIZER(rcu_sched, 's', call_rcu_sched);RCU_STATE_INITIALIZER (rcu_bh,'b' , call_rcu_bh);static struct rcu_state *const rcu_state_p; +static struct rcu_data __percpu *const rcu_data_p;LIST_HEAD (rcu_struct_flavors);/* Increase (but not decrease) the CONFIG_RCU_FANOUT_LEAF at boot time. */
kernel/rcu/tree_plugin.h +9 -7
@@ -101,6 +101,7 @@ static void __init rcu_bootup_announce_oddness(void)RCU_STATE_INITIALIZER (rcu_preempt,'p' , call_rcu);static struct rcu_state *const rcu_state_p = &rcu_preempt_state; +static struct rcu_data __percpu *const rcu_data_p = &rcu_preempt_data;static int rcu_preempted_readers_exp (struct rcu_node *rnp); static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp,
@@ -126,11 +127,11 @@ static void __init rcu_bootup_announce(void)*/ static void rcu_preempt_qs (void ) { -if (!__this_cpu_read (rcu_preempt_data.passed_quiesce)) { +if (!__this_cpu_read (rcu_data_p->passed_quiesce)) {trace_rcu_grace_period (TPS ("rcu_preempt" ), -__this_cpu_read (rcu_preempt_data.gpnum), +__this_cpu_read (rcu_data_p->gpnum),TPS ("cpuqs" )); -__this_cpu_write (rcu_preempt_data.passed_quiesce,1 ); +__this_cpu_write (rcu_data_p->passed_quiesce,1 );barrier ();/* Coordinate with rcu_preempt_check_callbacks(). */ current->rcu_read_unlock_special.b.need_qs = false; }
@@ -495,8 +496,8 @@ static void rcu_preempt_check_callbacks(void)return ; }if (t->rcu_read_lock_nesting >0 && -__this_cpu_read (rcu_preempt_data.qs_pending) && - !__this_cpu_read (rcu_preempt_data.passed_quiesce)) +__this_cpu_read (rcu_data_p->qs_pending) && + !__this_cpu_read (rcu_data_p->passed_quiesce)) t->rcu_read_unlock_special.b.need_qs = true; }
@@ -504,7 +505,7 @@ static void rcu_preempt_check_callbacks(void)static void rcu_preempt_do_callbacks (void ) { -rcu_do_batch (rcu_state_p,this_cpu_ptr (&rcu_preempt_data)); +rcu_do_batch (rcu_state_p,this_cpu_ptr (rcu_data_p)); }#endif /* #ifdef CONFIG_RCU_BOOST */
@@ -811,7 +812,7 @@ EXPORT_SYMBOL_GPL(rcu_barrier);*/ static void __init __rcu_init_preempt (void ) { -rcu_init_one (rcu_state_p, &rcu_preempt_data); +rcu_init_one (rcu_state_p, rcu_data_p); }/*
@@ -835,6 +836,7 @@ void exit_rcu(void)#else /* #ifdef CONFIG_PREEMPT_RCU */ static struct rcu_state *const rcu_state_p = &rcu_sched_state; +static struct rcu_data __percpu *const rcu_data_p = &rcu_sched_data;/* * Tell them what RCU they are running.
Signature · 1 line
1.8.1.5
PATCH 2/15 rcu: Convert from rcu_preempt_state to *rcu_state_p
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
It would be good to move more code from #ifdef to IS_ENABLED(), but that does not work if the body of the IS_ENABLED() "if" statement references a variable (such as rcu_preempt_state) that does not exist if the IS_ENABLED() Kconfig variable is not set. This commit therefore substitutes *rcu_state_p for all uses of rcu_preempt_state in kernel/rcu/tree_preempt.h, which should enable elimination of a few #ifdefs.
--- kernel/rcu/tree_plugin.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)
kernel/rcu/tree_plugin.h +9 -10
@@ -150,7 +150,7 @@ static void rcu_preempt_note_context_switch(void) !t->rcu_read_unlock_special.b.blocked) {/* Possibly blocking in an RCU read-side critical section. */ - rdp =this_cpu_ptr (rcu_preempt_state.rda); + rdp =this_cpu_ptr (rcu_state_p->rda); rnp = rdp->mynode;raw_spin_lock_irqsave (&rnp->lock, flags);smp_mb__after_unlock_lock ();
@@ -353,8 +353,7 @@ void rcu_read_unlock_special(struct task_struct *t) rnp->grplo, rnp->grphi, !!rnp->gp_tasks); -rcu_report_unblock_qs_rnp (&rcu_preempt_state, - rnp, flags); +rcu_report_unblock_qs_rnp (rcu_state_p, rnp, flags); }else {raw_spin_unlock_irqrestore (&rnp->lock, flags); }
@@ -370,7 +369,7 @@ void rcu_read_unlock_special(struct task_struct *t)* then we need to report up the rcu_node hierarchy. */ if (!empty_exp && empty_exp_now) -rcu_report_exp_rnp (&rcu_preempt_state, rnp, true); +rcu_report_exp_rnp (rcu_state_p, rnp, true); }else {local_irq_restore (flags); }
@@ -500,7 +499,7 @@ static void rcu_preempt_check_callbacks(void)static void rcu_preempt_do_callbacks (void ) { -rcu_do_batch (&rcu_preempt_state,this_cpu_ptr (&rcu_preempt_data)); +rcu_do_batch (rcu_state_p,this_cpu_ptr (&rcu_preempt_data)); }#endif /* #ifdef CONFIG_RCU_BOOST */
@@ -510,7 +509,7 @@ static void rcu_preempt_do_callbacks(void)*/ void call_rcu (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) { -__call_rcu (head, func, &rcu_preempt_state,-1 ,0 ); +__call_rcu (head, func, rcu_state_p,-1 ,0 ); }EXPORT_SYMBOL_GPL (call_rcu);
@@ -711,7 +710,7 @@ sync_rcu_preempt_exp_init2(struct rcu_state *rsp, struct rcu_node *rnp)void synchronize_rcu_expedited (void ) {struct rcu_node *rnp; -struct rcu_state *rsp = &rcu_preempt_state; +struct rcu_state *rsp = rcu_state_p;unsigned long snap;int trycount =0 ;
@@ -798,7 +797,7 @@ EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);*/ void rcu_barrier (void ) { -_rcu_barrier (&rcu_preempt_state); +_rcu_barrier (rcu_state_p); }EXPORT_SYMBOL_GPL (rcu_barrier);
@@ -807,7 +806,7 @@ EXPORT_SYMBOL_GPL(rcu_barrier);*/ static void __init __rcu_init_preempt (void ) { -rcu_init_one (&rcu_preempt_state, &rcu_preempt_data); +rcu_init_one (rcu_state_p, &rcu_preempt_data); }/*
@@ -1172,7 +1171,7 @@ static int rcu_spawn_one_boost_kthread(struct rcu_state *rsp,struct sched_param sp;struct task_struct *t; -if (&rcu_preempt_state != rsp) +if (rcu_state_p != rsp)return 0 ;if (!rcu_scheduler_fully_active ||rcu_rnp_online_cpus (rnp) ==0 )
Signature · 1 line
1.8.1.5
PATCH 4/15 rcu: Tell the compiler that rcu_state_p is immutable
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
This commit adds a "const" tag to the declarations of rcu_state_p, which should allow the compiler to generate better code and also to catch erroneous assignments to this variable.
--- kernel/rcu/tree.c | 2 +- kernel/rcu/tree_plugin.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-)
kernel/rcu/tree.c +1 -1
@@ -110,7 +110,7 @@ struct rcu_state sname##_state = { \RCU_STATE_INITIALIZER (rcu_sched,'s' , call_rcu_sched);RCU_STATE_INITIALIZER (rcu_bh,'b' , call_rcu_bh); -static struct rcu_state *rcu_state_p; +static struct rcu_state *const rcu_state_p;LIST_HEAD (rcu_struct_flavors);/* Increase (but not decrease) the CONFIG_RCU_FANOUT_LEAF at boot time. */
kernel/rcu/tree_plugin.h +2 -2
@@ -100,7 +100,7 @@ static void __init rcu_bootup_announce_oddness(void)#ifdef CONFIG_PREEMPT_RCU RCU_STATE_INITIALIZER (rcu_preempt,'p' , call_rcu); -static struct rcu_state *rcu_state_p = &rcu_preempt_state; +static struct rcu_state *const rcu_state_p = &rcu_preempt_state;static int rcu_preempted_readers_exp (struct rcu_node *rnp); static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp,
@@ -834,7 +834,7 @@ void exit_rcu(void)#else /* #ifdef CONFIG_PREEMPT_RCU */ -static struct rcu_state *rcu_state_p = &rcu_sched_state; +static struct rcu_state *const rcu_state_p = &rcu_sched_state;/* * Tell them what RCU they are running.
Signature · 1 line
1.8.1.5
PATCH 1/15 rcu: Convert ACCESS_ONCE() to READ_ONCE() and WRITE_ONCE()
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
This commit moves from the old ACCESS_ONCE() API to the new READ_ONCE() and WRITE_ONCE() APIs.
--- include/linux/rculist.h | 6 +- include/linux/rcupdate.h | 16 ++--- kernel/rcu/rcutorture.c | 2 +- kernel/rcu/srcu.c | 10 +-- kernel/rcu/tiny_plugin.h | 12 ++-- kernel/rcu/tree.c | 184 +++++++++++++++++++++++------------------------ kernel/rcu/tree_plugin.h | 93 ++++++++++++------------ kernel/rcu/tree_trace.c | 6 +- kernel/rcu/update.c | 30 ++++---- kernel/torture.c | 26 +++---- 10 files changed, 193 insertions(+), 192 deletions(-)
include/linux/rculist.h +3 -3
@@ -29,8 +29,8 @@*/ static inline void INIT_LIST_HEAD_RCU (struct list_head *list) { -ACCESS_ONCE (list->next) = list; -ACCESS_ONCE (list->prev) = list; +WRITE_ONCE (list->next, list); +WRITE_ONCE (list->prev, list); }/*
@@ -288,7 +288,7 @@ static inline void list_splice_init_rcu(struct list_head *list,#define list_first_or_null_rcu (ptr, type, member) \ ({ \ struct list_head *__ptr = (ptr); \ - struct list_head *__next = ACCESS_ONCE(__ptr->next); \ + struct list_head *__next = READ_ONCE(__ptr->next); \ likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \ })
include/linux/rcupdate.h +8 -8
@@ -364,8 +364,8 @@ extern struct srcu_struct tasks_rcu_exit_srcu;#define rcu_note_voluntary_context_switch (t) \ do { \ rcu_all_qs(); \ - if (ACCESS_ONCE((t)->rcu_tasks_holdout)) \ - ACCESS_ONCE((t)->rcu_tasks_holdout) = false; \ + if (READ_ONCE((t)->rcu_tasks_holdout)) \ + WRITE_ONCE((t)->rcu_tasks_holdout, false); \ } while (0)#else /* #ifdef CONFIG_TASKS_RCU */ #define TASKS_RCU (x) do { } while (0)
@@ -609,7 +609,7 @@ static inline void rcu_preempt_sleep_check(void)#define __rcu_access_pointer (p, space) \ ({ \ - typeof(*p) *_________p1 = (typeof(*p) *__force)ACCESS_ONCE(p); \ + typeof(*p) *_________p1 = (typeof(*p) *__force)READ_ONCE(p); \ rcu_dereference_sparse(p, space); \ ((typeof(*p) __force __kernel *)(_________p1)); \ })
@@ -630,7 +630,7 @@ static inline void rcu_preempt_sleep_check(void)#define __rcu_access_index (p, space) \ ({ \ - typeof(p) _________p1 = ACCESS_ONCE(p); \ + typeof(p) _________p1 = READ_ONCE(p); \ rcu_dereference_sparse(p, space); \ (_________p1); \ })
@@ -659,7 +659,7 @@ static inline void rcu_preempt_sleep_check(void)*/ #define lockless_dereference (p) \ ({ \ - typeof(p) _________p1 = ACCESS_ONCE(p); \ + typeof(p) _________p1 = READ_ONCE(p); \ smp_read_barrier_depends();/* Dependency order vs. p above. */ \ (_________p1); \ })
@@ -702,7 +702,7 @@ static inline void rcu_preempt_sleep_check(void)* @p: The pointer to read * * Return the value of the specified RCU-protected pointer, but omit the -* smp_read_barrier_depends() and keep the ACCESS_ONCE(). This is useful +* smp_read_barrier_depends() and keep the READ_ONCE(). This is useful * when the value of this pointer is accessed, but the pointer is not * dereferenced, for example, when testing an RCU-protected pointer against * NULL. Although rcu_access_pointer() may also be used in cases where
@@ -791,7 +791,7 @@ static inline void rcu_preempt_sleep_check(void)* @p: The index to read * * Return the value of the specified RCU-protected index, but omit the -* smp_read_barrier_depends() and keep the ACCESS_ONCE(). This is useful +* smp_read_barrier_depends() and keep the READ_ONCE(). This is useful * when the value of this index is accessed, but the index is not * dereferenced, for example, when testing an RCU-protected index against * -1. Although rcu_access_index() may also be used in cases where
@@ -827,7 +827,7 @@ static inline void rcu_preempt_sleep_check(void)* @c: The conditions under which the dereference will take place * * Return the value of the specified RCU-protected pointer, but omit -* both the smp_read_barrier_depends() and the ACCESS_ONCE(). This +* both the smp_read_barrier_depends() and the READ_ONCE(). This * is useful in cases where update-side locks prevent the value of the * pointer from changing. Please note that this primitive does -not- * prevent the compiler from repeating this reference or combining it
kernel/rcu/rcutorture.c +1 -1
@@ -1413,7 +1413,7 @@ static int rcu_torture_barrier_cbs(void *arg) do { wait_event(barrier_cbs_wq[myid], (newphase = - ACCESS_ONCE(barrier_phase)) != lastphase || + READ_ONCE(barrier_phase)) != lastphase || torture_must_stop()); lastphase = newphase; smp_mb(); /* ensure barrier_phase load before ->call(). */
kernel/rcu/srcu.c +5 -5
@@ -151,7 +151,7 @@ static unsigned long srcu_readers_seq_idx(struct srcu_struct *sp, int idx)unsigned long t;for_each_possible_cpu (cpu) { - t =ACCESS_ONCE (per_cpu_ptr (sp->per_cpu_ref, cpu)->seq[idx]); + t =READ_ONCE (per_cpu_ptr (sp->per_cpu_ref, cpu)->seq[idx]); sum += t; }return sum;
@@ -168,7 +168,7 @@ static unsigned long srcu_readers_active_idx(struct srcu_struct *sp, int idx)unsigned long t;for_each_possible_cpu (cpu) { - t =ACCESS_ONCE (per_cpu_ptr (sp->per_cpu_ref, cpu)->c[idx]); + t =READ_ONCE (per_cpu_ptr (sp->per_cpu_ref, cpu)->c[idx]); sum += t; }return sum;
@@ -265,8 +265,8 @@ static int srcu_readers_active(struct srcu_struct *sp)unsigned long sum =0 ;for_each_possible_cpu (cpu) { - sum +=ACCESS_ONCE (per_cpu_ptr (sp->per_cpu_ref, cpu)->c[0 ]); - sum +=ACCESS_ONCE (per_cpu_ptr (sp->per_cpu_ref, cpu)->c[1 ]); + sum +=READ_ONCE (per_cpu_ptr (sp->per_cpu_ref, cpu)->c[0 ]); + sum +=READ_ONCE (per_cpu_ptr (sp->per_cpu_ref, cpu)->c[1 ]); }return sum; }
@@ -296,7 +296,7 @@ int __srcu_read_lock(struct srcu_struct *sp) {int idx; - idx =ACCESS_ONCE (sp->completed) &0x1 ; + 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. */
kernel/rcu/tiny_plugin.h +7 -5
@@ -144,16 +144,17 @@ static void check_cpu_stall(struct rcu_ctrlblk *rcp)return ; rcp->ticks_this_gp++; j = jiffies; - js =ACCESS_ONCE (rcp->jiffies_stall); + js =READ_ONCE (rcp->jiffies_stall);if (rcp->rcucblist &&ULONG_CMP_GE (j, js)) {pr_err ("INFO: %s stall on CPU (%lu ticks this GP) idle=%llx (t=%lu jiffies q=%ld)\n" , rcp->name, rcp->ticks_this_gp,DYNTICK_TASK_EXIT_IDLE , jiffies - rcp->gp_start, rcp->qlen);dump_stack (); -ACCESS_ONCE (rcp->jiffies_stall) = jiffies + -3 *rcu_jiffies_till_stall_check () +3 ; +WRITE_ONCE (rcp->jiffies_stall, + jiffies +3 *rcu_jiffies_till_stall_check () +3 ); }else if (ULONG_CMP_GE (j, js)) { -ACCESS_ONCE (rcp->jiffies_stall) = jiffies +rcu_jiffies_till_stall_check (); +WRITE_ONCE (rcp->jiffies_stall, + jiffies +rcu_jiffies_till_stall_check ()); } }
@@ -161,7 +162,8 @@ static void reset_cpu_stall_ticks(struct rcu_ctrlblk *rcp) { rcp->ticks_this_gp =0 ; rcp->gp_start = jiffies; -ACCESS_ONCE (rcp->jiffies_stall) = jiffies +rcu_jiffies_till_stall_check (); +WRITE_ONCE (rcp->jiffies_stall, + jiffies +rcu_jiffies_till_stall_check ()); }static void check_cpu_stalls (void )
kernel/rcu/tree.c +92 -92
544 lines not on this page · raw message
kernel/rcu/tree_plugin.h +46 -47
315 lines not on this page · raw message
kernel/rcu/tree_trace.c +3 -3
@@ -277,7 +277,7 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)seq_printf (m,"nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld/%ld\n" , rsp->n_force_qs, rsp->n_force_qs_ngp, rsp->n_force_qs - rsp->n_force_qs_ngp, -ACCESS_ONCE (rsp->n_force_qs_lh), rsp->qlen_lazy, rsp->qlen); +READ_ONCE (rsp->n_force_qs_lh), rsp->qlen_lazy, rsp->qlen);for (rnp = &rsp->node[0 ]; rnp - &rsp->node[0 ] < rcu_num_nodes; rnp++) {if (rnp->level != level) {seq_puts (m,"\n" );
@@ -323,8 +323,8 @@ static void show_one_rcugp(struct seq_file *m, struct rcu_state *rsp)struct rcu_node *rnp = &rsp->node[0 ];raw_spin_lock_irqsave (&rnp->lock, flags); - completed =ACCESS_ONCE (rsp->completed); - gpnum =ACCESS_ONCE (rsp->gpnum); + completed =READ_ONCE (rsp->completed); + gpnum =READ_ONCE (rsp->gpnum);if (completed == gpnum) gpage =0 ;else
kernel/rcu/update.c +15 -15
@@ -150,14 +150,14 @@ void __rcu_read_unlock(void)barrier ();/* critical section before exit code. */ t->rcu_read_lock_nesting =INT_MIN ;barrier ();/* assign before ->rcu_read_unlock_special load */ -if (unlikely (ACCESS_ONCE (t->rcu_read_unlock_special.s))) +if (unlikely (READ_ONCE (t->rcu_read_unlock_special.s)))rcu_read_unlock_special (t);barrier ();/* ->rcu_read_unlock_special load before assign */ t->rcu_read_lock_nesting =0 ; }#ifdef CONFIG_PROVE_LOCKING { -int rrln =ACCESS_ONCE (t->rcu_read_lock_nesting); +int rrln =READ_ONCE (t->rcu_read_lock_nesting);WARN_ON_ONCE (rrln <0 && rrln >INT_MIN /2 ); }
@@ -389,17 +389,17 @@ module_param(rcu_cpu_stall_timeout, int, 0644);int rcu_jiffies_till_stall_check (void ) { -int till_stall_check =ACCESS_ONCE (rcu_cpu_stall_timeout); +int till_stall_check =READ_ONCE (rcu_cpu_stall_timeout);/* * Limit check must be consistent with the Kconfig limits * for CONFIG_RCU_CPU_STALL_TIMEOUT. */ if (till_stall_check <3 ) { -ACCESS_ONCE (rcu_cpu_stall_timeout) =3 ; +WRITE_ONCE (rcu_cpu_stall_timeout,3 ); till_stall_check =3 ; }else if (till_stall_check >300 ) { -ACCESS_ONCE (rcu_cpu_stall_timeout) =300 ; +WRITE_ONCE (rcu_cpu_stall_timeout,300 ); till_stall_check =300 ; }return till_stall_check *HZ +RCU_STALL_DELAY_DELTA ;
@@ -550,12 +550,12 @@ static void check_holdout_task(struct task_struct *t, {int cpu; -if (!ACCESS_ONCE (t->rcu_tasks_holdout) || - t->rcu_tasks_nvcsw !=ACCESS_ONCE (t->nvcsw) || - !ACCESS_ONCE (t->on_rq) || +if (!READ_ONCE (t->rcu_tasks_holdout) || + t->rcu_tasks_nvcsw !=READ_ONCE (t->nvcsw) || + !READ_ONCE (t->on_rq) || (IS_ENABLED (CONFIG_NO_HZ_FULL ) && !is_idle_task (t) && t->rcu_tasks_idle_cpu >=0 )) { -ACCESS_ONCE (t->rcu_tasks_holdout) = false; +WRITE_ONCE (t->rcu_tasks_holdout, false);list_del_init (&t->rcu_tasks_holdout_list);put_task_struct (t);return ;
@@ -639,11 +639,11 @@ static int __noreturn rcu_tasks_kthread(void *arg)*/ rcu_read_lock ();for_each_process_thread (g, t) { -if (t != current &&ACCESS_ONCE (t->on_rq) && +if (t != current &&READ_ONCE (t->on_rq) && !is_idle_task (t)) {get_task_struct (t); - t->rcu_tasks_nvcsw =ACCESS_ONCE (t->nvcsw); -ACCESS_ONCE (t->rcu_tasks_holdout) = true; + t->rcu_tasks_nvcsw =READ_ONCE (t->nvcsw); +WRITE_ONCE (t->rcu_tasks_holdout, true);list_add (&t->rcu_tasks_holdout_list, &rcu_tasks_holdouts); }
@@ -672,7 +672,7 @@ static int __noreturn rcu_tasks_kthread(void *arg)struct task_struct *t1;schedule_timeout_interruptible (HZ ); - rtst =ACCESS_ONCE (rcu_task_stall_timeout); + rtst =READ_ONCE (rcu_task_stall_timeout); needreport = rtst >0 &&time_after (jiffies, lastreport + rtst);if (needreport)
@@ -728,7 +728,7 @@ static void rcu_spawn_tasks_kthread(void)static struct task_struct *rcu_tasks_kthread_ptr;struct task_struct *t; -if (ACCESS_ONCE (rcu_tasks_kthread_ptr)) { +if (READ_ONCE (rcu_tasks_kthread_ptr)) {smp_mb ();/* Ensure caller sees full kthread. */ return ; }
@@ -740,7 +740,7 @@ static void rcu_spawn_tasks_kthread(void) t =kthread_run (rcu_tasks_kthread,NULL ,"rcu_tasks_kthread" );BUG_ON (IS_ERR (t));smp_mb ();/* Ensure others see full kthread. */ -ACCESS_ONCE (rcu_tasks_kthread_ptr) = t; +WRITE_ONCE (rcu_tasks_kthread_ptr, t);mutex_unlock (&rcu_tasks_kthread_mutex); }
kernel/torture.c +13 -13
@@ -409,7 +409,7 @@ static void (*torture_shutdown_hook)(void);*/ void torture_shutdown_absorb (const char *title) { -while (ACCESS_ONCE (fullstop) ==FULLSTOP_SHUTDOWN ) { +while (READ_ONCE (fullstop) ==FULLSTOP_SHUTDOWN ) {pr_notice ("torture thread %s parking due to system shutdown\n" , title);schedule_timeout_uninterruptible (MAX_SCHEDULE_TIMEOUT );
@@ -480,9 +480,9 @@ static int torture_shutdown_notify(struct notifier_block *unused1, unsigned long unused2, void *unused3) { mutex_lock(&fullstop_mutex); -if (ACCESS_ONCE (fullstop) ==FULLSTOP_DONTSTOP ) { +if (READ_ONCE (fullstop) ==FULLSTOP_DONTSTOP ) {VERBOSE_TOROUT_STRING ("Unscheduled system shutdown detected" ); -ACCESS_ONCE (fullstop) =FULLSTOP_SHUTDOWN ; +WRITE_ONCE (fullstop,FULLSTOP_SHUTDOWN ); }else {pr_warn ("Concurrent rmmod and shutdown illegal!\n" ); }
@@ -523,13 +523,13 @@ static int stutter;*/ void stutter_wait (const char *title) { -while (ACCESS_ONCE (stutter_pause_test) || - (torture_runnable && !ACCESS_ONCE (*torture_runnable))) { +while (READ_ONCE (stutter_pause_test) || + (torture_runnable && !READ_ONCE (*torture_runnable))) {if (stutter_pause_test) -if (ACCESS_ONCE (stutter_pause_test) ==1 ) +if (READ_ONCE (stutter_pause_test) ==1 )schedule_timeout_interruptible (1 );else -while (ACCESS_ONCE (stutter_pause_test)) +while (READ_ONCE (stutter_pause_test))cond_resched ();else schedule_timeout_interruptible (round_jiffies_relative (HZ ));
@@ -549,14 +549,14 @@ static int torture_stutter(void *arg)if (!torture_must_stop ()) {if (stutter >1 ) {schedule_timeout_interruptible (stutter -1 ); -ACCESS_ONCE (stutter_pause_test) =2 ; +WRITE_ONCE (stutter_pause_test,2 ); }schedule_timeout_interruptible (1 ); -ACCESS_ONCE (stutter_pause_test) =1 ; +WRITE_ONCE (stutter_pause_test,1 ); }if (!torture_must_stop ())schedule_timeout_interruptible (stutter); -ACCESS_ONCE (stutter_pause_test) =0 ; +WRITE_ONCE (stutter_pause_test,0 );torture_shutdown_absorb ("torture_stutter" ); }while (!torture_must_stop ());torture_kthread_stopping ("torture_stutter" );
@@ -642,13 +642,13 @@ EXPORT_SYMBOL_GPL(torture_init_end);bool torture_cleanup_begin (void ) {mutex_lock (&fullstop_mutex); -if (ACCESS_ONCE (fullstop) ==FULLSTOP_SHUTDOWN ) { +if (READ_ONCE (fullstop) ==FULLSTOP_SHUTDOWN ) {pr_warn ("Concurrent rmmod and shutdown illegal!\n" );mutex_unlock (&fullstop_mutex);schedule_timeout_uninterruptible (10 );return true; } -ACCESS_ONCE (fullstop) =FULLSTOP_RMMOD ; +WRITE_ONCE (fullstop,FULLSTOP_RMMOD );mutex_unlock (&fullstop_mutex);torture_shutdown_cleanup ();torture_shuffle_cleanup ();
@@ -681,7 +681,7 @@ EXPORT_SYMBOL_GPL(torture_must_stop);*/ bool torture_must_stop_irq (void ) { -return ACCESS_ONCE (fullstop) !=FULLSTOP_DONTSTOP ; +return READ_ONCE (fullstop) !=FULLSTOP_DONTSTOP ; }EXPORT_SYMBOL_GPL (torture_must_stop_irq);
Signature · 1 line
1.8.1.5
PATCH 11/15 rcu: Add more debug info on "kthread starved" RCU CPU stall warnings
From: "Paul E. McKenney" <[email protected]>
This commit adds grace number and command-flags information to the "kthread starved" message that is sometimes printed out as part of RCU CPU stall warnings. This message is caused by the corresponding RCU grace-period kthread not having run for at least two seconds, and this added information can be helpful when debugging.
--- kernel/rcu/tree.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
kernel/rcu/tree.c +3 -2
@@ -1133,8 +1133,9 @@ static void rcu_check_gp_kthread_starvation(struct rcu_state *rsp) j = jiffies; gpa =READ_ONCE (rsp->gp_activity);if (j - gpa >2 *HZ ) -pr_err ("%s kthread starved for %ld jiffies!\n" , - rsp->name, j - gpa); +pr_err ("%s kthread starved for %ld jiffies! g%lu c%lu f%#x\n" , + rsp->name, j - gpa, + rsp->gpnum, rsp->completed, rsp->gp_flags); }/*
Signature · 1 line
1.8.1.5
PATCH 9/15 powerpc: Fix smp_mb__before_spinlock()
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
Currently, smp_mb__before_spinlock() is defined to be smp_wmb() in core code, but this is not sufficient on PowerPC. This patch therefore supplies an override for the generic definition to strengthen smp_mb__before_spinlock() to smp_mb(), as is needed on PowerPC.
--- arch/powerpc/include/asm/barrier.h | 1 + 1 file changed, 1 insertion(+)
arch/powerpc/include/asm/barrier.h +1 -0
@@ -89,5 +89,6 @@ do { \#define smp_mb__before_atomic () smp_mb()#define smp_mb__after_atomic () smp_mb() +#define smp_mb__before_spinlock () smp_mb()#endif /* _ASM_POWERPC_BARRIER_H */
Signature · 1 line
1.8.1.5
PATCH 14/15 rcu: Make rcu_*_data variables static
In reply to Paul E. McKenneyFrom: Nicolas Iooss <[email protected]>
rcu_bh_data, rcu_sched_data and rcu_preempt_data are never used outside kernel/rcu/tree.c and thus can be made static.
Doing so fixes a section mismatch warning reported by clang when building LLVMLinux with -Wsection, because these variables were declared in .data..percpu and defined in .data..percpu..shared_aligned since commit 11bbb235c26f ("rcu: Use DEFINE_PER_CPU_SHARED_ALIGNED for rcu_data").
--- kernel/rcu/tree.c | 2 +- kernel/rcu/tree.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-)
kernel/rcu/tree.c +1 -1
@@ -91,7 +91,7 @@ static const char *tp_##sname##_varname __used __tracepoint_string = sname##_var#define RCU_STATE_INITIALIZER (sname, sabbr, cr) \ DEFINE_RCU_TPS(sname) \ -DEFINE_PER_CPU_SHARED_ALIGNED(struct rcu_data, sname##_data); \ +static DEFINE_PER_CPU_SHARED_ALIGNED(struct rcu_data, sname##_data); \ struct rcu_state sname##_state = { \ .level = { &sname##_state.node[0] }, \ .rda = &sname##_data, \
kernel/rcu/tree.h +0 -3
@@ -517,14 +517,11 @@ extern struct list_head rcu_struct_flavors;* RCU implementation internal declarations: */ extern struct rcu_state rcu_sched_state; -DECLARE_PER_CPU(struct rcu_data, rcu_sched_data);extern struct rcu_state rcu_bh_state; -DECLARE_PER_CPU(struct rcu_data, rcu_bh_data);#ifdef CONFIG_PREEMPT_RCU extern struct rcu_state rcu_preempt_state; -DECLARE_PER_CPU(struct rcu_data, rcu_preempt_data);#endif /* #ifdef CONFIG_PREEMPT_RCU */ #ifdef CONFIG_RCU_BOOST
Signature · 1 line
1.8.1.5
PATCH 13/15 rcu: Make synchronize_sched_expedited() call wait_rcu_gp()
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
Currently, synchronize_sched_expedited() will call synchronize_sched() if there is danger of counter wrap. But if configuration says to always do expedited grace periods, synchronize_sched() will just call synchronize_sched_expedited() right back again. In theory, the old expedited operations will complete, the counters will get back in synch, and the recursion will end. But we could easily run out of stack long before that time. This commit therefore makes synchronize_sched_expedited() invoke the underlying wait_rcu_gp(call_rcu_sched) instead of synchronize_sched(), the same as all the other calls out from synchronize_sched_expedited().
This bug was introduced by commit 1924bcb02597 (Avoid counter wrap in synchronize_sched_expedited()).
--- kernel/rcu/tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/rcu/tree.c +1 -1
@@ -3288,7 +3288,7 @@ void synchronize_sched_expedited(void)if (ULONG_CMP_GE ((ulong )atomic_long_read (&rsp->expedited_start), (ulong )atomic_long_read (&rsp->expedited_done) +ULONG_MAX /8 )) { -synchronize_sched (); +wait_rcu_gp (call_rcu_sched);atomic_long_inc (&rsp->expedited_wrap);return ; }
Signature · 1 line
1.8.1.5
PATCH 10/15 rcu: Fix missing task information during rcu-preempt stall
In reply to Paul E. McKenneyFrom: Patrick Daly <[email protected]>
The first item list_for_each_entry_continue(alist) iterates over is alist->next, rather than alist itself. Consequently, rcu_print_detail_task_stall_rnp() skips the task referenced by gp_tasks.
Use gp_tasks->prev as the argument to list_for_each_entry_continue() instead.
--- kernel/rcu/tree_plugin.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/rcu/tree_plugin.h +2 -2
@@ -395,7 +395,7 @@ static void rcu_print_detail_task_stall_rnp(struct rcu_node *rnp)raw_spin_unlock_irqrestore (&rnp->lock, flags);return ; } - t =list_entry (rnp->gp_tasks, + t =list_entry (rnp->gp_tasks->prev, struct task_struct, rcu_node_entry);list_for_each_entry_continue (t, &rnp->blkd_tasks, rcu_node_entry)sched_show_task (t);
@@ -452,7 +452,7 @@ static int rcu_print_task_stall(struct rcu_node *rnp)if (!rcu_preempt_blocked_readers_cgp (rnp))return 0 ;rcu_print_task_stall_begin (rnp); - t =list_entry (rnp->gp_tasks, + t =list_entry (rnp->gp_tasks->prev, struct task_struct, rcu_node_entry);list_for_each_entry_continue (t, &rnp->blkd_tasks, rcu_node_entry) {pr_cont (" P%d" , t->pid);
Signature · 1 line
1.8.1.5
PATCH 7/15 rcu: Force wakeup of rcu_gp_kthread at grace-period end
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
The rcu_gp_kthread_wake() refuses to do a wakeup unless at least one of the ->gp_flags bits are set, which normally will not be the case when the last quiescent state is reported. This results in up to a 3-jiffy delay given default Kconfig settings. This commit therefore has rcu_report_qs_rsp() set RCU_GP_FLAG_FQS before invoking rcu_gp_kthread_wake() in order to force a more immediate wakeup at grace-period end, thus reducing grace-period latencies.
--- kernel/rcu/tree.c | 1 + 1 file changed, 1 insertion(+)
kernel/rcu/tree.c +1 -0
@@ -2137,6 +2137,7 @@ static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags) __releases(rcu_get_root(rsp)->lock) {WARN_ON_ONCE (!rcu_gp_in_progress (rsp)); +WRITE_ONCE (rsp->gp_flags,READ_ONCE (rsp->gp_flags) |RCU_GP_FLAG_FQS );raw_spin_unlock_irqrestore (&rcu_get_root (rsp)->lock, flags);rcu_gp_kthread_wake (rsp); }
Signature · 1 line
1.8.1.5
PATCH 8/15 rcu: tree_plugin: Use bool function return values of true/false not 1/0
In reply to Paul E. McKenneyFrom: Joe Perches <[email protected]>
Use the normal return values for bool functions
--- kernel/rcu/tree_plugin.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/rcu/tree_plugin.h +2 -2
@@ -3056,9 +3056,9 @@ static bool rcu_nohz_full_cpu(struct rcu_state *rsp)if (tick_nohz_full_cpu (smp_processor_id ()) && (!rcu_gp_in_progress (rsp) ||ULONG_CMP_LT (jiffies,READ_ONCE (rsp->gp_start) +HZ ))) -return 1 ; +return true;#endif /* #ifdef CONFIG_NO_HZ_FULL */ -return 0 ; +return false; }/*
Signature · 1 line
1.8.1.5
PATCH 12/15 smp: Make control dependencies work on Alpha, improve documentation
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
The current formulation of control dependencies fails on DEC Alpha, which does not respect dependencies of any kind unless an explicit memory barrier is provided. This means that the current fomulation of control dependencies fails on Alpha. This commit therefore creates a READ_ONCE_CTRL() that has the same overhead on non-Alpha systems, but causes Alpha to produce the needed ordering. This commit also applies READ_ONCE_CTRL() to the one known use of control dependencies.
Use of READ_ONCE_CTRL() also has the beneficial effect of adding a bit of self-documentation to control dependencies.
--- Documentation/memory-barriers.txt | 55 +++++++++++++++++++++++---------------- include/linux/compiler.h | 16 ++++++++++++ kernel/events/ring_buffer.c | 2 +- 3 files changed, 50 insertions(+), 23 deletions(-)
Documentation/memory-barriers.txt +33 -22
@@ -617,16 +617,16 @@ case what's actually required is: However, stores are not speculated. This means that ordering -is- provided for load-store control dependencies, as in the following example: - q = ACCESS_ONCE(a); + q = READ_ONCE_CTRL(a); if (q) { ACCESS_ONCE(b) = p; } -Control dependencies pair normally with other types of barriers. -That said, please note that ACCESS_ONCE() is not optional! Without the -ACCESS_ONCE(), might combine the load from 'a' with other loads from -'a', and the store to 'b' with other stores to 'b', with possible highly -counterintuitive effects on ordering. +Control dependencies pair normally with other types of barriers. That +said, please note that READ_ONCE_CTRL() is not optional! Without the +READ_ONCE_CTRL(), the compiler might combine the load from 'a' with +other loads from 'a', and the store to 'b' with other stores to 'b', +with possible highly counterintuitive effects on ordering. Worse yet, if the compiler is able to prove (say) that the value of variable 'a' is always non-zero, it would be well within its rights
@@ -636,12 +636,15 @@ as follows: q = a; b = p; /* BUG: Compiler and CPU can both reorder!!! */ -So don't leave out the ACCESS_ONCE(). +Finally, the READ_ONCE_CTRL() includes an smp_read_barrier_depends() +that DEC Alpha needs in order to respect control depedencies. + +So don't leave out the READ_ONCE_CTRL(). It is tempting to try to enforce ordering on identical stores on both branches of the "if" statement as follows: - q = ACCESS_ONCE(a); + q = READ_ONCE_CTRL(a); if (q) { barrier(); ACCESS_ONCE(b) = p;
@@ -655,7 +658,7 @@ branches of the "if" statement as follows: Unfortunately, current compilers will transform this as follows at high optimization levels: - q = ACCESS_ONCE(a); + q = READ_ONCE_CTRL(a); barrier(); ACCESS_ONCE(b) = p; /* BUG: No ordering vs. load from a!!! */ if (q) {
@@ -685,7 +688,7 @@ memory barriers, for example, smp_store_release(): In contrast, without explicit memory barriers, two-legged-if control ordering is guaranteed only when the stores differ, for example: - q = ACCESS_ONCE(a); + q = READ_ONCE_CTRL(a); if (q) { ACCESS_ONCE(b) = p; do_something();
@@ -694,14 +697,14 @@ ordering is guaranteed only when the stores differ, for example: do_something_else(); } -The initial ACCESS_ONCE() is still required to prevent the compiler from -proving the value of 'a'. +The initial READ_ONCE_CTRL() is still required to prevent the compiler +from proving the value of 'a'. In addition, you need to be careful what you do with the local variable 'q', otherwise the compiler might be able to guess the value and again remove the needed conditional. For example: - q = ACCESS_ONCE(a); + q = READ_ONCE_CTRL(a); if (q % MAX) { ACCESS_ONCE(b) = p; do_something();
@@ -714,7 +717,7 @@ If MAX is defined to be 1, then the compiler knows that (q % MAX) is equal to zero, in which case the compiler is within its rights to transform the above code into the following: - q = ACCESS_ONCE(a); + q = READ_ONCE_CTRL(a); ACCESS_ONCE(b) = p; do_something_else();
@@ -725,7 +728,7 @@ is gone, and the barrier won't bring it back. Therefore, if you are relying on this ordering, you should make sure that MAX is greater than one, perhaps as follows: - q = ACCESS_ONCE(a); + q = READ_ONCE_CTRL(a); BUILD_BUG_ON(MAX <= 1); /* Order load from a with store to b. */ if (q % MAX) { ACCESS_ONCE(b) = p;
@@ -742,14 +745,15 @@ of the 'if' statement. You must also be careful not to rely too much on boolean short-circuit evaluation. Consider this example: - q = ACCESS_ONCE(a); + q = READ_ONCE_CTRL(a); if (a || 1 > 0) ACCESS_ONCE(b) = 1; -Because the second condition is always true, the compiler can transform -this example as following, defeating control dependency: +Because the first condition cannot fault and the second condition is +always true, the compiler can transform this example as following, +defeating control dependency: - q = ACCESS_ONCE(a); + q = READ_ONCE_CTRL(a); ACCESS_ONCE(b) = 1; This example underscores the need to ensure that the compiler cannot
@@ -762,8 +766,8 @@ demonstrated by two related examples, with the initial values of x and y both being zero: CPU 0 CPU 1 - ===================== ===================== - r1 = ACCESS_ONCE(x); r2 = ACCESS_ONCE(y); + ======================= ======================= + r1 = READ_ONCE_CTRL(x); r2 = READ_ONCE_CTRL(y); if (r1 > 0) if (r2 > 0) ACCESS_ONCE(y) = 1; ACCESS_ONCE(x) = 1;
@@ -783,7 +787,8 @@ But because control dependencies do -not- provide transitivity, the above assertion can fail after the combined three-CPU example completes. If you need the three-CPU example to provide ordering, you will need smp_mb() between the loads and stores in the CPU 0 and CPU 1 code fragments, -that is, just before or just after the "if" statements. +that is, just before or just after the "if" statements. Furthermore, +the original two-CPU example is very fragile and should be avoided. These two examples are the LB and WWC litmus tests from this paper: http://www.cl.cam.ac.uk/users/pes20/ppc-supplemental/test6.pdf and this
@@ -791,6 +796,12 @@ site: https://www.cl.cam.ac.uk/~pes20/ppcmem/index.html. In summary: + (*) Control dependencies must be headed by READ_ONCE_CTRL(). + Or, as a much less preferable alternative, interpose + be headed by READ_ONCE() or an ACCESS_ONCE() read and must + have smp_read_barrier_depends() between this read and the + control-dependent write. + (*) Control dependencies can order prior loads against later stores. However, they do -not- guarantee any other sort of ordering: Not prior loads against later loads, nor prior stores against
include/linux/compiler.h +16 -0
@@ -248,6 +248,22 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s#define WRITE_ONCE (x, val) \ ({ typeof(x) __val = (val); __write_once_size(&(x), &__val, sizeof(__val)); __val; }) +/** +* READ_ONCE_CTRL - Read a value heading a control dependency +* @x: The value to be read, heading the control dependency +* +* Control dependencies are tricky. See Documentation/memory-barriers.txt +* for important information on how to use them. Note that in many cases, +* use of smp_load_acquire() will be much simpler. Control dependencies +* should be avoided except on the hottest of hotpaths. +*/ +#define READ_ONCE_CTRL(x) \ +({ \ + typeof(x) __val = READ_ONCE(x); \ + smp_read_barrier_depends(); /* Enforce control dependency. */ \ + __val; \ +}) +#endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */
kernel/events/ring_buffer.c +1 -1
@@ -141,7 +141,7 @@ int perf_output_begin(struct perf_output_handle *handle,perf_output_get_handle (handle); do { - tail = ACCESS_ONCE(rb->user_page->data_tail); + tail = READ_ONCE_CTRL(rb->user_page->data_tail); offset = head = local_read(&rb->head); if (!rb->overwrite && unlikely(CIRC_SPACE(head, tail, perf_data_size(rb)) < size))
Signature · 1 line
1.8.1.5
cover Miscellaneous fixes for 4.2
Hello!
This series contains miscellaneous fixes.
1. Move RCU from the old ACCESS_ONCE() API to READ_ONCE() and
WRITE_ONCE().
2. Change uses of rcu_preempt_state to *rcu_state_p, which allows
easier elimination of a few #ifdefs.
3. Eliminate a few CONFIG_RCU_BOOST #ifdefs.
4. Use the "const" tag to tell the compiler that rcu_state_p is
immutable.
5. Create an immutable rcu_data_p to the default rcu_data per-CPU
structures.
6. Eliminate a few CONFIG_RCU_NOCB_CPU_ALL #ifdefs.
7. Force wakeup of rcu_gp_kthread at grace-period end in order to
cause end-of-grace-period processing to happen in a timely fashion, thus reducing grace-period latencies.
8. Use true/false for bool-function return values, courtesy of
Joe Perches.
9. Fix PowerPC's smp_mb__before_spinlock().
10. Prevent RCU CPU stall warnings from ignoring tasks blocking the
current grace period, courtesy of Patrick Daly.
11. Add more debugging information when an RCU CPU stall warning is
caused by stalling of the grace-period kthread.
12. Make control dependencies work on DEC Alpha and fix documentation.
13. Avoid deadlocks by having synchronize_sched_expedited() invoke
wait_rcu_gp() instead of synchronize_sched().
14. Make the rcu_*_data variables static.
15. Change rcu_cpu_has_callbacks()'s return type to bool, courtesy
of Nicholas Mc Guire.
Thanx, Paul
------------------------------------------------------------------------
b/Documentation/memory-barriers.txt | 55 +++++---- b/arch/powerpc/include/asm/barrier.h | 1 b/include/linux/compiler.h | 16 ++ b/include/linux/rculist.h | 6 - b/include/linux/rcupdate.h | 20 +-- b/include/linux/rcutree.h | 2 b/kernel/events/ring_buffer.c | 2 b/kernel/rcu/rcutorture.c | 2 b/kernel/rcu/srcu.c | 10 - b/kernel/rcu/tiny_plugin.h | 12 +- b/kernel/rcu/tree.c | 199 +++++++++++++++++------------------ b/kernel/rcu/tree.h | 5 b/kernel/rcu/tree_plugin.h | 197 +++++++++++++++++----------------- b/kernel/rcu/tree_trace.c | 6 - b/kernel/rcu/update.c | 30 ++--- b/kernel/torture.c | 26 ++-- 16 files changed, 311 insertions(+), 278 deletions(-)
PATCH 15/15 rcu: Change function declaration to bool
In reply to Paul E. McKenneyFrom: Nicholas Mc Guire <[email protected]>
rcu_cpu_has_callbacks() is declared int. The current declaration was introduced in commit c0f4dfd4f90f (rcu: Make RCU_FAST_NO_HZ take advantage of numbered callbacks). But it is actually returning bool and as the function description states " * Return true if the specified CPU has any callback....", this probably should be a bool as all (3) call-sites currently treat it as bool.
Type-checking coccinelle spatches are being used to locate type mismatches between function signatures and return values in this case this produced:./kernel/rcu/tree.c:3538 WARNING: return of wrong type
int != bool,
Patch was compile tested with x86_64_defconfig (implies CONFIG_TREE_RCU=y)
Patch is against 4.1-rc3 (localversion-next is -next-20150511) and fixes
--- kernel/rcu/tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/rcu/tree.c +1 -1
@@ -3494,7 +3494,7 @@ static int rcu_pending(void)* non-NULL, store an indication of whether all callbacks are lazy. * (If there are no callbacks, all of them are deemed to be lazy.) */ -static int __maybe_unused rcu_cpu_has_callbacks (bool *all_lazy) +static bool __maybe_unused rcu_cpu_has_callbacks (bool *all_lazy) {bool al = true;bool hc = false;
Signature · 1 line
1.8.1.5
PATCH 6/15 rcu: Eliminate a few CONFIG_RCU_NOCB_CPU_ALL #ifdefs
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
This commit converts several CONFIG_RCU_NOCB_CPU_ALL #ifdefs to instead use IS_ENABLED(). This change should help avoid hiding code from compiler diagnostics.
--- include/linux/rcupdate.h | 4 ++-- include/linux/rcutree.h | 2 -- kernel/rcu/tree_plugin.h | 22 ++++++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-)
include/linux/rcupdate.h +2 -2
@@ -1153,13 +1153,13 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)#define kfree_rcu (ptr, rcu_head) \ __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head)) -#if defined(CONFIG_TINY_RCU ) || defined(CONFIG_RCU_NOCB_CPU_ALL ) +#ifdef CONFIG_TINY_RCU static inline int rcu_needs_cpu (unsigned long *delta_jiffies) { *delta_jiffies =ULONG_MAX ;return 0 ; } -#endif /* #if defined(CONFIG_TINY_RCU) || defined(CONFIG_RCU_NOCB_CPU_ALL) */ +#endif /* #ifdef CONFIG_TINY_RCU */ #if defined(CONFIG_RCU_NOCB_CPU_ALL )static inline bool rcu_is_nocb_cpu (int cpu) {return true; }
include/linux/rcutree.h +0 -2
@@ -31,9 +31,7 @@#define __LINUX_RCUTREE_Hvoid rcu_note_context_switch (void ); -#ifndef CONFIG_RCU_NOCB_CPU_ALL int rcu_needs_cpu (unsigned long *delta_jiffies); -#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */ void rcu_cpu_stall_reset (void );/*
kernel/rcu/tree_plugin.h +12 -10
@@ -1372,13 +1372,12 @@ static void rcu_prepare_kthreads(int cpu)* Because we not have RCU_FAST_NO_HZ, just check whether this CPU needs * any flavor of RCU. */ -#ifndef CONFIG_RCU_NOCB_CPU_ALL int rcu_needs_cpu (unsigned long *delta_jiffies) { *delta_jiffies =ULONG_MAX ; -return rcu_cpu_has_callbacks (NULL ); +return IS_ENABLED (CONFIG_RCU_NOCB_CPU_ALL ) + ?0 :rcu_cpu_has_callbacks (NULL ); } -#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */ /* * Because we do not have RCU_FAST_NO_HZ, don't bother cleaning up
@@ -1485,11 +1484,15 @@ static bool __maybe_unused rcu_try_advance_all_cbs(void)* * The caller must have disabled interrupts. */ -#ifndef CONFIG_RCU_NOCB_CPU_ALL int rcu_needs_cpu (unsigned long *dj) {struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks); +if (IS_ENABLED (CONFIG_RCU_NOCB_CPU_ALL )) { + *dj =ULONG_MAX ; +return 0 ; + } +/* Snapshot to detect later posting of non-lazy callback. */ rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted;
@@ -1516,7 +1519,6 @@ int rcu_needs_cpu(unsigned long *dj) }return 0 ; } -#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */ /* * Prepare a CPU for idle from an RCU perspective. The first major task
@@ -1530,7 +1532,6 @@ int rcu_needs_cpu(unsigned long *dj)*/ static void rcu_prepare_for_idle (void ) { -#ifndef CONFIG_RCU_NOCB_CPU_ALL bool needwake;struct rcu_data *rdp;struct rcu_dynticks *rdtp =this_cpu_ptr (&rcu_dynticks);
@@ -1538,6 +1539,9 @@ static void rcu_prepare_for_idle(void)struct rcu_state *rsp;int tne; +if (IS_ENABLED (CONFIG_RCU_NOCB_CPU_ALL )) +return ; +/* Handle nohz enablement switches conservatively. */ tne =READ_ONCE (tick_nohz_active);if (tne != rdtp->tick_nohz_enabled_snap) {
@@ -1585,7 +1589,6 @@ static void rcu_prepare_for_idle(void)if (needwake)rcu_gp_kthread_wake (rsp); } -#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */ }/*
@@ -1595,12 +1598,11 @@ static void rcu_prepare_for_idle(void)*/ static void rcu_cleanup_after_idle (void ) { -#ifndef CONFIG_RCU_NOCB_CPU_ALL -if (rcu_is_nocb_cpu (smp_processor_id ())) +if (IS_ENABLED (CONFIG_RCU_NOCB_CPU_ALL ) || +rcu_is_nocb_cpu (smp_processor_id ()))return ;if (rcu_try_advance_all_cbs ())invoke_rcu_core (); -#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */ }/*
Signature · 1 line
1.8.1.5