rcu: Clarify memory-ordering properties of grace-period primitives
[deliverable/linux.git] / kernel / rcutree.c
index 4fb2376ddf0660575970a29db0637ac4c70c2020..15a2beec320fe1f959f773a88a65acebb411b716 100644 (file)
@@ -74,6 +74,7 @@ static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS];
        .orphan_nxttail = &sname##_state.orphan_nxtlist, \
        .orphan_donetail = &sname##_state.orphan_donelist, \
        .barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \
+       .onoff_mutex = __MUTEX_INITIALIZER(sname##_state.onoff_mutex), \
        .name = #sname, \
 }
 
@@ -211,13 +212,13 @@ DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {
 #endif
 };
 
-static int blimit = 10;                /* Maximum callbacks per rcu_do_batch. */
-static int qhimark = 10000;    /* If this many pending, ignore blimit. */
-static int qlowmark = 100;     /* Once only this many pending, use blimit. */
+static long blimit = 10;       /* Maximum callbacks per rcu_do_batch. */
+static long qhimark = 10000;   /* If this many pending, ignore blimit. */
+static long qlowmark = 100;    /* Once only this many pending, use blimit. */
 
-module_param(blimit, int, 0444);
-module_param(qhimark, int, 0444);
-module_param(qlowmark, int, 0444);
+module_param(blimit, long, 0444);
+module_param(qhimark, long, 0444);
+module_param(qlowmark, long, 0444);
 
 int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */
 int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT;
@@ -1197,7 +1198,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
        raw_spin_unlock_irq(&rnp->lock);
 
        /* Exclude any concurrent CPU-hotplug operations. */
-       get_online_cpus();
+       mutex_lock(&rsp->onoff_mutex);
 
        /*
         * Set the quiescent-state-needed bits in all the rcu_node
@@ -1234,7 +1235,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
                cond_resched();
        }
 
-       put_online_cpus();
+       mutex_unlock(&rsp->onoff_mutex);
        return 1;
 }
 
@@ -1403,15 +1404,37 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
            !cpu_needs_another_gp(rsp, rdp)) {
                /*
                 * Either we have not yet spawned the grace-period
-                * task or this CPU does not need another grace period.
+                * task, this CPU does not need another grace period,
+                * or a grace period is already in progress.
                 * Either way, don't start a new grace period.
                 */
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
                return;
        }
 
+       /*
+        * Because there is no grace period in progress right now,
+        * any callbacks we have up to this point will be satisfied
+        * by the next grace period.  So promote all callbacks to be
+        * handled after the end of the next grace period.  If the
+        * CPU is not yet aware of the end of the previous grace period,
+        * we need to allow for the callback advancement that will
+        * occur when it does become aware.  Deadlock prevents us from
+        * making it aware at this point: We cannot acquire a leaf
+        * rcu_node ->lock while holding the root rcu_node ->lock.
+        */
+       rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
+       if (rdp->completed == rsp->completed)
+               rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
+
        rsp->gp_flags = RCU_GP_FLAG_INIT;
-       raw_spin_unlock_irqrestore(&rnp->lock, flags);
+       raw_spin_unlock(&rnp->lock); /* Interrupts remain disabled. */
+
+       /* Ensure that CPU is aware of completion of last grace period. */
+       rcu_process_gp_end(rsp, rdp);
+       local_irq_restore(flags);
+
+       /* Wake up rcu_gp_kthread() to start the grace period. */
        wake_up(&rsp->gp_wq);
 }
 
@@ -1700,6 +1723,7 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)
        /* Remove the dead CPU from the bitmasks in the rcu_node hierarchy. */
 
        /* Exclude any attempts to start a new grace period. */
+       mutex_lock(&rsp->onoff_mutex);
        raw_spin_lock_irqsave(&rsp->onofflock, flags);
 
        /* Orphan the dead CPU's callbacks, and adopt them if appropriate. */
@@ -1744,6 +1768,7 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)
        init_callback_list(rdp);
        /* Disallow further callbacks on this CPU. */
        rdp->nxttail[RCU_NEXT_TAIL] = NULL;
+       mutex_unlock(&rsp->onoff_mutex);
 }
 
 #else /* #ifdef CONFIG_HOTPLUG_CPU */
@@ -1766,7 +1791,8 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
 {
        unsigned long flags;
        struct rcu_head *next, *list, **tail;
-       int bl, count, count_lazy, i;
+       long bl, count, count_lazy;
+       int i;
 
        /* If no callbacks are ready, just return.*/
        if (!cpu_has_callbacks_ready_to_invoke(rdp)) {
@@ -2202,10 +2228,28 @@ static inline int rcu_blocking_is_gp(void)
  * rcu_read_lock_sched().
  *
  * This means that all preempt_disable code sequences, including NMI and
- * hardware-interrupt handlers, in progress on entry will have completed
- * before this primitive returns.  However, this does not guarantee that
- * softirq handlers will have completed, since in some kernels, these
- * handlers can run in process context, and can block.
+ * non-threaded hardware-interrupt handlers, in progress on entry will
+ * have completed before this primitive returns.  However, this does not
+ * guarantee that softirq handlers will have completed, since in some
+ * kernels, these handlers can run in process context, and can block.
+ *
+ * Note that this guarantee implies further memory-ordering guarantees.
+ * On systems with more than one CPU, when synchronize_sched() returns,
+ * each CPU is guaranteed to have executed a full memory barrier since the
+ * end of its last RCU-sched read-side critical section whose beginning
+ * preceded the call to synchronize_sched().  In addition, each CPU having
+ * an RCU read-side critical section that extends beyond the return from
+ * synchronize_sched() is guaranteed to have executed a full memory barrier
+ * after the beginning of synchronize_sched() and before the beginning of
+ * that RCU read-side critical section.  Note that these guarantees include
+ * CPUs that are offline, idle, or executing in user mode, as well as CPUs
+ * that are executing in the kernel.
+ *
+ * Furthermore, if CPU A invoked synchronize_sched(), which returned
+ * to its caller on CPU B, then both CPU A and CPU B are guaranteed
+ * to have executed a full memory barrier during the execution of
+ * synchronize_sched() -- even if CPU A and CPU B are the same CPU (but
+ * again only if the system has more than one CPU).
  *
  * This primitive provides the guarantees made by the (now removed)
  * synchronize_kernel() API.  In contrast, synchronize_rcu() only
@@ -2233,6 +2277,9 @@ EXPORT_SYMBOL_GPL(synchronize_sched);
  * read-side critical sections have completed.  RCU read-side critical
  * sections are delimited by rcu_read_lock_bh() and rcu_read_unlock_bh(),
  * and may be nested.
+ *
+ * See the description of synchronize_sched() for more detailed information
+ * on memory ordering guarantees.
  */
 void synchronize_rcu_bh(void)
 {
@@ -2648,6 +2695,9 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
        struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
        struct rcu_node *rnp = rcu_get_root(rsp);
 
+       /* Exclude new grace periods. */
+       mutex_lock(&rsp->onoff_mutex);
+
        /* Set up local state, ensuring consistent view of global state. */
        raw_spin_lock_irqsave(&rnp->lock, flags);
        rdp->beenonline = 1;     /* We have now been online. */
@@ -2662,14 +2712,6 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
        rcu_prepare_for_idle_init(cpu);
        raw_spin_unlock(&rnp->lock);            /* irqs remain disabled. */
 
-       /*
-        * A new grace period might start here.  If so, we won't be part
-        * of it, but that is OK, as we are currently in a quiescent state.
-        */
-
-       /* Exclude any attempts to start a new GP on large systems. */
-       raw_spin_lock(&rsp->onofflock);         /* irqs already disabled. */
-
        /* Add CPU to rcu_node bitmasks. */
        rnp = rdp->mynode;
        mask = rdp->grpmask;
@@ -2693,8 +2735,9 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
                raw_spin_unlock(&rnp->lock); /* irqs already disabled. */
                rnp = rnp->parent;
        } while (rnp != NULL && !(rnp->qsmaskinit & mask));
+       local_irq_restore(flags);
 
-       raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
+       mutex_unlock(&rsp->onoff_mutex);
 }
 
 static void __cpuinit rcu_prepare_cpu(int cpu)
This page took 0.026652 seconds and 5 git commands to generate.