Skip to content

Commit

Permalink
rcu: Clean up code based on review feedback from Josh Triplett, part 4
Browse files Browse the repository at this point in the history
These issues identified during an old-fashioned face-to-face code
review extending over many hours.  This group improves an existing
abstraction and introduces two new ones.  It also fixes an RCU
stall-warning bug found while making the other changes.

o	Make RCU_INIT_FLAVOR() declare its own variables, removing
	the need to declare them at each call site.

o	Create an rcu_for_each_leaf() macro that scans the leaf
	nodes of the rcu_node tree.

o	Create an rcu_for_each_node_breadth_first() macro that does
	a breadth-first traversal of the rcu_node tree, AKA
	stepping through the array in index-number order.

o	If all CPUs corresponding to a given leaf rcu_node
	structure go offline, then any tasks queued on that leaf
	will be moved to the root rcu_node structure.  Therefore,
	the stall-warning code must dump out tasks queued on the
	root rcu_node structure as well as those queued on the leaf
	rcu_node structures.

Signed-off-by: Paul E. McKenney <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
LKML-Reference: <12541491934126-git-send-email->
Signed-off-by: Ingo Molnar <[email protected]>
  • Loading branch information
paulmck authored and Ingo Molnar committed Oct 5, 2009
1 parent 3d76c08 commit a0b6c9a
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 29 deletions.
53 changes: 28 additions & 25 deletions kernel/rcutree.c
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,6 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
long delta;
unsigned long flags;
struct rcu_node *rnp = rcu_get_root(rsp);
struct rcu_node *rnp_cur = rsp->level[NUM_RCU_LVLS - 1];
struct rcu_node *rnp_end = &rsp->node[NUM_RCU_NODES];

/* Only let one CPU complain about others per time interval. */

Expand All @@ -474,18 +472,24 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
return;
}
rsp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_RECHECK;

/*
* Now rat on any tasks that got kicked up to the root rcu_node
* due to CPU offlining.
*/
rcu_print_task_stall(rnp);
spin_unlock_irqrestore(&rnp->lock, flags);

/* OK, time to rat on our buddy... */

printk(KERN_ERR "INFO: RCU detected CPU stalls:");
for (; rnp_cur < rnp_end; rnp_cur++) {
rcu_for_each_leaf_node(rsp, rnp) {
rcu_print_task_stall(rnp);
if (rnp_cur->qsmask == 0)
if (rnp->qsmask == 0)
continue;
for (cpu = 0; cpu <= rnp_cur->grphi - rnp_cur->grplo; cpu++)
if (rnp_cur->qsmask & (1UL << cpu))
printk(" %d", rnp_cur->grplo + cpu);
for (cpu = 0; cpu <= rnp->grphi - rnp->grplo; cpu++)
if (rnp->qsmask & (1UL << cpu))
printk(" %d", rnp->grplo + cpu);
}
printk(" (detected by %d, t=%ld jiffies)\n",
smp_processor_id(), (long)(jiffies - rsp->gp_start));
Expand Down Expand Up @@ -649,7 +653,7 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
* one corresponding to this CPU, due to the fact that we have
* irqs disabled.
*/
for (rnp = &rsp->node[0]; rnp < &rsp->node[NUM_RCU_NODES]; rnp++) {
rcu_for_each_node_breadth_first(rsp, rnp) {
spin_lock(&rnp->lock); /* irqs already disabled. */
rcu_preempt_check_blocked_tasks(rnp);
rnp->qsmask = rnp->qsmaskinit;
Expand Down Expand Up @@ -1042,33 +1046,32 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp,
int cpu;
unsigned long flags;
unsigned long mask;
struct rcu_node *rnp_cur = rsp->level[NUM_RCU_LVLS - 1];
struct rcu_node *rnp_end = &rsp->node[NUM_RCU_NODES];
struct rcu_node *rnp;

for (; rnp_cur < rnp_end; rnp_cur++) {
rcu_for_each_leaf_node(rsp, rnp) {
mask = 0;
spin_lock_irqsave(&rnp_cur->lock, flags);
spin_lock_irqsave(&rnp->lock, flags);
if (rsp->completed != lastcomp) {
spin_unlock_irqrestore(&rnp_cur->lock, flags);
spin_unlock_irqrestore(&rnp->lock, flags);
return 1;
}
if (rnp_cur->qsmask == 0) {
spin_unlock_irqrestore(&rnp_cur->lock, flags);
if (rnp->qsmask == 0) {
spin_unlock_irqrestore(&rnp->lock, flags);
continue;
}
cpu = rnp_cur->grplo;
cpu = rnp->grplo;
bit = 1;
for (; cpu <= rnp_cur->grphi; cpu++, bit <<= 1) {
if ((rnp_cur->qsmask & bit) != 0 && f(rsp->rda[cpu]))
for (; cpu <= rnp->grphi; cpu++, bit <<= 1) {
if ((rnp->qsmask & bit) != 0 && f(rsp->rda[cpu]))
mask |= bit;
}
if (mask != 0 && rsp->completed == lastcomp) {

/* cpu_quiet_msk() releases rnp_cur->lock. */
cpu_quiet_msk(mask, rsp, rnp_cur, flags);
/* cpu_quiet_msk() releases rnp->lock. */
cpu_quiet_msk(mask, rsp, rnp, flags);
continue;
}
spin_unlock_irqrestore(&rnp_cur->lock, flags);
spin_unlock_irqrestore(&rnp->lock, flags);
}
return 0;
}
Expand Down Expand Up @@ -1550,6 +1553,10 @@ static void __init rcu_init_one(struct rcu_state *rsp)
*/
#define RCU_INIT_FLAVOR(rsp, rcu_data) \
do { \
int i; \
int j; \
struct rcu_node *rnp; \
\
rcu_init_one(rsp); \
rnp = (rsp)->level[NUM_RCU_LVLS - 1]; \
j = 0; \
Expand All @@ -1564,10 +1571,6 @@ do { \

void __init __rcu_init(void)
{
int i; /* All used by RCU_INIT_FLAVOR(). */
int j;
struct rcu_node *rnp;

rcu_bootup_announce();
#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
printk(KERN_INFO "RCU-based detection of stalled CPUs is enabled.\n");
Expand Down
12 changes: 12 additions & 0 deletions kernel/rcutree.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,18 @@ struct rcu_node {
/* blocked_tasks[] array. */
} ____cacheline_internodealigned_in_smp;

/*
* Do a full breadth-first scan of the rcu_node structures for the
* specified rcu_state structure.
*/
#define rcu_for_each_node_breadth_first(rsp, rnp) \
for ((rnp) = &(rsp)->node[0]; \
(rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++)

#define rcu_for_each_leaf_node(rsp, rnp) \
for ((rnp) = (rsp)->level[NUM_RCU_LVLS - 1]; \
(rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++)

/* Index values for nxttail array in struct rcu_data. */
#define RCU_DONE_TAIL 0 /* Also RCU_WAIT head. */
#define RCU_WAIT_TAIL 1 /* Also RCU_NEXT_READY head. */
Expand Down
4 changes: 0 additions & 4 deletions kernel/rcutree_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,10 +423,6 @@ static void __cpuinit rcu_preempt_init_percpu_data(int cpu)
*/
static void __init __rcu_init_preempt(void)
{
int i; /* All used by RCU_INIT_FLAVOR(). */
int j;
struct rcu_node *rnp;

RCU_INIT_FLAVOR(&rcu_preempt_state, rcu_preempt_data);
}

Expand Down

0 comments on commit a0b6c9a

Please sign in to comment.