rcu: Add WARN_ON_ONCE() consistency checks covering state transitions
[deliverable/linux.git] / kernel / rcutree.c
index 6b11b07cfe7f41fb4fae5f8d4adcddaee9aca7d8..e8624ebf23206c1d0d5402890422f423b164c06e 100644 (file)
@@ -107,27 +107,23 @@ static void __cpuinit rcu_init_percpu_data(int cpu, struct rcu_state *rsp,
  */
 void rcu_sched_qs(int cpu)
 {
-       unsigned long flags;
        struct rcu_data *rdp;
 
-       local_irq_save(flags);
        rdp = &per_cpu(rcu_sched_data, cpu);
-       rdp->passed_quiesc = 1;
        rdp->passed_quiesc_completed = rdp->completed;
-       rcu_preempt_qs(cpu);
-       local_irq_restore(flags);
+       barrier();
+       rdp->passed_quiesc = 1;
+       rcu_preempt_note_context_switch(cpu);
 }
 
 void rcu_bh_qs(int cpu)
 {
-       unsigned long flags;
        struct rcu_data *rdp;
 
-       local_irq_save(flags);
        rdp = &per_cpu(rcu_bh_data, cpu);
-       rdp->passed_quiesc = 1;
        rdp->passed_quiesc_completed = rdp->completed;
-       local_irq_restore(flags);
+       barrier();
+       rdp->passed_quiesc = 1;
 }
 
 #ifdef CONFIG_NO_HZ
@@ -615,6 +611,7 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
 
        /* Advance to a new grace period and initialize state. */
        rsp->gpnum++;
+       WARN_ON_ONCE(rsp->signaled == RCU_GP_INIT);
        rsp->signaled = RCU_GP_INIT; /* Hold off force_quiescent_state. */
        rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS;
        record_gp_stall_check_time(rsp);
@@ -631,7 +628,9 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
 
        /* Special-case the common single-level case. */
        if (NUM_RCU_NODES == 1) {
+               rcu_preempt_check_blocked_tasks(rnp);
                rnp->qsmask = rnp->qsmaskinit;
+               rnp->gpnum = rsp->gpnum;
                rsp->signaled = RCU_SIGNAL_INIT; /* force_quiescent_state OK. */
                spin_unlock_irqrestore(&rnp->lock, flags);
                return;
@@ -644,41 +643,28 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
        spin_lock(&rsp->onofflock);  /* irqs already disabled. */
 
        /*
-        * Set the quiescent-state-needed bits in all the non-leaf RCU
-        * nodes for all currently online CPUs.  This operation relies
-        * on the layout of the hierarchy within the rsp->node[] array.
-        * Note that other CPUs will access only the leaves of the
-        * hierarchy, which still indicate that no grace period is in
-        * progress.  In addition, we have excluded CPU-hotplug operations.
-        *
-        * We therefore do not need to hold any locks.  Any required
-        * memory barriers will be supplied by the locks guarding the
-        * leaf rcu_nodes in the hierarchy.
-        */
-
-       rnp_end = rsp->level[NUM_RCU_LVLS - 1];
-       for (rnp_cur = &rsp->node[0]; rnp_cur < rnp_end; rnp_cur++)
-               rnp_cur->qsmask = rnp_cur->qsmaskinit;
-
-       /*
-        * Now set up the leaf nodes.  Here we must be careful.  First,
-        * we need to hold the lock in order to exclude other CPUs, which
-        * might be contending for the leaf nodes' locks.  Second, as
-        * soon as we initialize a given leaf node, its CPUs might run
-        * up the rest of the hierarchy.  We must therefore acquire locks
-        * for each node that we touch during this stage.  (But we still
-        * are excluding CPU-hotplug operations.)
+        * Set the quiescent-state-needed bits in all the rcu_node
+        * structures for all currently online CPUs in breadth-first
+        * order, starting from the root rcu_node structure.  This
+        * operation relies on the layout of the hierarchy within the
+        * rsp->node[] array.  Note that other CPUs will access only
+        * the leaves of the hierarchy, which still indicate that no
+        * grace period is in progress, at least until the corresponding
+        * leaf node has been initialized.  In addition, we have excluded
+        * CPU-hotplug operations.
         *
         * Note that the grace period cannot complete until we finish
         * the initialization process, as there will be at least one
         * qsmask bit set in the root node until that time, namely the
-        * one corresponding to this CPU.
+        * one corresponding to this CPU, due to the fact that we have
+        * irqs disabled.
         */
        rnp_end = &rsp->node[NUM_RCU_NODES];
-       rnp_cur = rsp->level[NUM_RCU_LVLS - 1];
-       for (; rnp_cur < rnp_end; rnp_cur++) {
+       for (rnp_cur = &rsp->node[0]; rnp_cur < rnp_end; rnp_cur++) {
                spin_lock(&rnp_cur->lock);      /* irqs already disabled. */
+               rcu_preempt_check_blocked_tasks(rnp);
                rnp_cur->qsmask = rnp_cur->qsmaskinit;
+               rnp->gpnum = rsp->gpnum;
                spin_unlock(&rnp_cur->lock);    /* irqs already disabled. */
        }
 
@@ -722,6 +708,7 @@ rcu_process_gp_end(struct rcu_state *rsp, struct rcu_data *rdp)
 static void cpu_quiet_msk_finish(struct rcu_state *rsp, unsigned long flags)
        __releases(rnp->lock)
 {
+       WARN_ON_ONCE(rsp->completed == rsp->gpnum);
        rsp->completed = rsp->gpnum;
        rcu_process_gp_end(rsp, rsp->rda[smp_processor_id()]);
        rcu_start_gp(rsp, flags);  /* releases root node's rnp->lock. */
@@ -739,6 +726,8 @@ cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp, struct rcu_node *rnp,
              unsigned long flags)
        __releases(rnp->lock)
 {
+       struct rcu_node *rnp_c;
+
        /* Walk up the rcu_node hierarchy. */
        for (;;) {
                if (!(rnp->qsmask & mask)) {
@@ -762,8 +751,10 @@ cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp, struct rcu_node *rnp,
                        break;
                }
                spin_unlock_irqrestore(&rnp->lock, flags);
+               rnp_c = rnp;
                rnp = rnp->parent;
                spin_lock_irqsave(&rnp->lock, flags);
+               WARN_ON_ONCE(rnp_c->qsmask);
        }
 
        /*
@@ -872,7 +863,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)
        spin_lock_irqsave(&rsp->onofflock, flags);
 
        /* Remove the outgoing CPU from the masks in the rcu_node hierarchy. */
-       rnp = rdp->mynode;
+       rnp = rdp->mynode;      /* this is the outgoing CPU's rnp. */
        mask = rdp->grpmask;    /* rnp->grplo is constant. */
        do {
                spin_lock(&rnp->lock);          /* irqs already disabled. */
@@ -881,7 +872,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)
                        spin_unlock(&rnp->lock); /* irqs remain disabled. */
                        break;
                }
-               rcu_preempt_offline_tasks(rsp, rnp);
+               rcu_preempt_offline_tasks(rsp, rnp, rdp);
                mask = rnp->grpmask;
                spin_unlock(&rnp->lock);        /* irqs remain disabled. */
                rnp = rnp->parent;
This page took 0.04006 seconds and 5 git commands to generate.