Update /debug/tracing/README
[safe/jmp/linux-2.6] / kernel / rcupreempt.c
index a5aabb1..5d59e85 100644 (file)
  *             to Suparna Bhattacharya for pushing me completely away
  *             from atomic instructions on the read side.
  *
+ *  - Added handling of Dynamic Ticks
+ *      Copyright 2007 - Paul E. Mckenney <paulmck@us.ibm.com>
+ *                     - Steven Rostedt <srostedt@redhat.com>
+ *
  * Papers:  http://www.rdrop.com/users/paulmck/RCU
  *
  * Design Document: http://lwn.net/Articles/253651/
 #include <asm/atomic.h>
 #include <linux/bitops.h>
 #include <linux/module.h>
+#include <linux/kthread.h>
 #include <linux/completion.h>
 #include <linux/moduleparam.h>
 #include <linux/percpu.h>
 #include <linux/notifier.h>
-#include <linux/rcupdate.h>
 #include <linux/cpu.h>
 #include <linux/random.h>
 #include <linux/delay.h>
-#include <linux/byteorder/swabb.h>
 #include <linux/cpumask.h>
 #include <linux/rcupreempt_trace.h>
-
-/*
- * Macro that prevents the compiler from reordering accesses, but does
- * absolutely -nothing- to prevent CPUs from reordering.  This is used
- * only to mediate communication between mainline code and hardware
- * interrupt and NMI handlers.
- */
-#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+#include <asm/byteorder.h>
 
 /*
  * PREEMPT_RCU data structures.
@@ -78,14 +74,18 @@ struct rcu_data {
        spinlock_t      lock;           /* Protect rcu_data fields. */
        long            completed;      /* Number of last completed batch. */
        int             waitlistcount;
-       struct tasklet_struct rcu_tasklet;
        struct rcu_head *nextlist;
        struct rcu_head **nexttail;
        struct rcu_head *waitlist[GP_STAGES];
        struct rcu_head **waittail[GP_STAGES];
-       struct rcu_head *donelist;
+       struct rcu_head *donelist;      /* from waitlist & waitschedlist */
        struct rcu_head **donetail;
        long rcu_flipctr[2];
+       struct rcu_head *nextschedlist;
+       struct rcu_head **nextschedtail;
+       struct rcu_head *waitschedlist;
+       struct rcu_head **waitschedtail;
+       int rcu_sched_sleeping;
 #ifdef CONFIG_RCU_TRACE
        struct rcupreempt_trace trace;
 #endif /* #ifdef CONFIG_RCU_TRACE */
@@ -127,11 +127,24 @@ enum rcu_try_flip_states {
        rcu_try_flip_waitmb_state,
 };
 
+/*
+ * States for rcu_ctrlblk.rcu_sched_sleep.
+ */
+
+enum rcu_sched_sleep_states {
+       rcu_sched_not_sleeping, /* Not sleeping, callbacks need GP.  */
+       rcu_sched_sleep_prep,   /* Thinking of sleeping, rechecking. */
+       rcu_sched_sleeping,     /* Sleeping, awaken if GP needed. */
+};
+
 struct rcu_ctrlblk {
        spinlock_t      fliplock;       /* Protect state-machine transitions. */
        long            completed;      /* Number of last completed batch. */
        enum rcu_try_flip_states rcu_try_flip_state; /* The current state of
                                                        the rcu state machine */
+       spinlock_t      schedlock;      /* Protect rcu_sched sleep state. */
+       enum rcu_sched_sleep_states sched_sleep; /* rcu_sched state. */
+       wait_queue_head_t sched_wq;     /* Place for rcu_sched to sleep. */
 };
 
 static DEFINE_PER_CPU(struct rcu_data, rcu_data);
@@ -139,14 +152,21 @@ static struct rcu_ctrlblk rcu_ctrlblk = {
        .fliplock = __SPIN_LOCK_UNLOCKED(rcu_ctrlblk.fliplock),
        .completed = 0,
        .rcu_try_flip_state = rcu_try_flip_idle_state,
+       .schedlock = __SPIN_LOCK_UNLOCKED(rcu_ctrlblk.schedlock),
+       .sched_sleep = rcu_sched_not_sleeping,
+       .sched_wq = __WAIT_QUEUE_HEAD_INITIALIZER(rcu_ctrlblk.sched_wq),
 };
 
+static struct task_struct *rcu_sched_grace_period_task;
 
 #ifdef CONFIG_RCU_TRACE
 static char *rcu_try_flip_state_names[] =
        { "idle", "waitack", "waitzero", "waitmb" };
 #endif /* #ifdef CONFIG_RCU_TRACE */
 
+static DECLARE_BITMAP(rcu_cpu_online_map, NR_CPUS) __read_mostly
+       = CPU_BITS_NONE;
+
 /*
  * Enum and per-CPU flag to determine when each CPU has seen
  * the most recent counter flip.
@@ -201,6 +221,8 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(enum rcu_mb_flag_values, rcu_mb_flag)
  */
 #define RCU_TRACE_RDP(f, rdp) RCU_TRACE(f, &((rdp)->trace));
 
+#define RCU_SCHED_BATCH_TIME (HZ / 50)
+
 /*
  * Return the number of RCU batches processed thus far.  Useful
  * for debug and statistics.
@@ -211,8 +233,6 @@ long rcu_batches_completed(void)
 }
 EXPORT_SYMBOL_GPL(rcu_batches_completed);
 
-EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
-
 void __rcu_read_lock(void)
 {
        int idx;
@@ -407,6 +427,300 @@ static void __rcu_advance_callbacks(struct rcu_data *rdp)
        }
 }
 
+DEFINE_PER_CPU_SHARED_ALIGNED(struct rcu_dyntick_sched, rcu_dyntick_sched) = {
+       .dynticks = 1,
+};
+
+#ifdef CONFIG_NO_HZ
+static DEFINE_PER_CPU(int, rcu_update_flag);
+
+/**
+ * rcu_irq_enter - Called from Hard irq handlers and NMI/SMI.
+ *
+ * If the CPU was idle with dynamic ticks active, this updates the
+ * rcu_dyntick_sched.dynticks to let the RCU handling know that the
+ * CPU is active.
+ */
+void rcu_irq_enter(void)
+{
+       int cpu = smp_processor_id();
+       struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu);
+
+       if (per_cpu(rcu_update_flag, cpu))
+               per_cpu(rcu_update_flag, cpu)++;
+
+       /*
+        * Only update if we are coming from a stopped ticks mode
+        * (rcu_dyntick_sched.dynticks is even).
+        */
+       if (!in_interrupt() &&
+           (rdssp->dynticks & 0x1) == 0) {
+               /*
+                * The following might seem like we could have a race
+                * with NMI/SMIs. But this really isn't a problem.
+                * Here we do a read/modify/write, and the race happens
+                * when an NMI/SMI comes in after the read and before
+                * the write. But NMI/SMIs will increment this counter
+                * twice before returning, so the zero bit will not
+                * be corrupted by the NMI/SMI which is the most important
+                * part.
+                *
+                * The only thing is that we would bring back the counter
+                * to a postion that it was in during the NMI/SMI.
+                * But the zero bit would be set, so the rest of the
+                * counter would again be ignored.
+                *
+                * On return from the IRQ, the counter may have the zero
+                * bit be 0 and the counter the same as the return from
+                * the NMI/SMI. If the state machine was so unlucky to
+                * see that, it still doesn't matter, since all
+                * RCU read-side critical sections on this CPU would
+                * have already completed.
+                */
+               rdssp->dynticks++;
+               /*
+                * The following memory barrier ensures that any
+                * rcu_read_lock() primitives in the irq handler
+                * are seen by other CPUs to follow the above
+                * increment to rcu_dyntick_sched.dynticks. This is
+                * required in order for other CPUs to correctly
+                * determine when it is safe to advance the RCU
+                * grace-period state machine.
+                */
+               smp_mb(); /* see above block comment. */
+               /*
+                * Since we can't determine the dynamic tick mode from
+                * the rcu_dyntick_sched.dynticks after this routine,
+                * we use a second flag to acknowledge that we came
+                * from an idle state with ticks stopped.
+                */
+               per_cpu(rcu_update_flag, cpu)++;
+               /*
+                * If we take an NMI/SMI now, they will also increment
+                * the rcu_update_flag, and will not update the
+                * rcu_dyntick_sched.dynticks on exit. That is for
+                * this IRQ to do.
+                */
+       }
+}
+
+/**
+ * rcu_irq_exit - Called from exiting Hard irq context.
+ *
+ * If the CPU was idle with dynamic ticks active, update the
+ * rcu_dyntick_sched.dynticks to put let the RCU handling be
+ * aware that the CPU is going back to idle with no ticks.
+ */
+void rcu_irq_exit(void)
+{
+       int cpu = smp_processor_id();
+       struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu);
+
+       /*
+        * rcu_update_flag is set if we interrupted the CPU
+        * when it was idle with ticks stopped.
+        * Once this occurs, we keep track of interrupt nesting
+        * because a NMI/SMI could also come in, and we still
+        * only want the IRQ that started the increment of the
+        * rcu_dyntick_sched.dynticks to be the one that modifies
+        * it on exit.
+        */
+       if (per_cpu(rcu_update_flag, cpu)) {
+               if (--per_cpu(rcu_update_flag, cpu))
+                       return;
+
+               /* This must match the interrupt nesting */
+               WARN_ON(in_interrupt());
+
+               /*
+                * If an NMI/SMI happens now we are still
+                * protected by the rcu_dyntick_sched.dynticks being odd.
+                */
+
+               /*
+                * The following memory barrier ensures that any
+                * rcu_read_unlock() primitives in the irq handler
+                * are seen by other CPUs to preceed the following
+                * increment to rcu_dyntick_sched.dynticks. This
+                * is required in order for other CPUs to determine
+                * when it is safe to advance the RCU grace-period
+                * state machine.
+                */
+               smp_mb(); /* see above block comment. */
+               rdssp->dynticks++;
+               WARN_ON(rdssp->dynticks & 0x1);
+       }
+}
+
+void rcu_nmi_enter(void)
+{
+       rcu_irq_enter();
+}
+
+void rcu_nmi_exit(void)
+{
+       rcu_irq_exit();
+}
+
+static void dyntick_save_progress_counter(int cpu)
+{
+       struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu);
+
+       rdssp->dynticks_snap = rdssp->dynticks;
+}
+
+static inline int
+rcu_try_flip_waitack_needed(int cpu)
+{
+       long curr;
+       long snap;
+       struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu);
+
+       curr = rdssp->dynticks;
+       snap = rdssp->dynticks_snap;
+       smp_mb(); /* force ordering with cpu entering/leaving dynticks. */
+
+       /*
+        * If the CPU remained in dynticks mode for the entire time
+        * and didn't take any interrupts, NMIs, SMIs, or whatever,
+        * then it cannot be in the middle of an rcu_read_lock(), so
+        * the next rcu_read_lock() it executes must use the new value
+        * of the counter.  So we can safely pretend that this CPU
+        * already acknowledged the counter.
+        */
+
+       if ((curr == snap) && ((curr & 0x1) == 0))
+               return 0;
+
+       /*
+        * If the CPU passed through or entered a dynticks idle phase with
+        * no active irq handlers, then, as above, we can safely pretend
+        * that this CPU already acknowledged the counter.
+        */
+
+       if ((curr - snap) > 2 || (curr & 0x1) == 0)
+               return 0;
+
+       /* We need this CPU to explicitly acknowledge the counter flip. */
+
+       return 1;
+}
+
+static inline int
+rcu_try_flip_waitmb_needed(int cpu)
+{
+       long curr;
+       long snap;
+       struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu);
+
+       curr = rdssp->dynticks;
+       snap = rdssp->dynticks_snap;
+       smp_mb(); /* force ordering with cpu entering/leaving dynticks. */
+
+       /*
+        * If the CPU remained in dynticks mode for the entire time
+        * and didn't take any interrupts, NMIs, SMIs, or whatever,
+        * then it cannot have executed an RCU read-side critical section
+        * during that time, so there is no need for it to execute a
+        * memory barrier.
+        */
+
+       if ((curr == snap) && ((curr & 0x1) == 0))
+               return 0;
+
+       /*
+        * If the CPU either entered or exited an outermost interrupt,
+        * SMI, NMI, or whatever handler, then we know that it executed
+        * a memory barrier when doing so.  So we don't need another one.
+        */
+       if (curr != snap)
+               return 0;
+
+       /* We need the CPU to execute a memory barrier. */
+
+       return 1;
+}
+
+static void dyntick_save_progress_counter_sched(int cpu)
+{
+       struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu);
+
+       rdssp->sched_dynticks_snap = rdssp->dynticks;
+}
+
+static int rcu_qsctr_inc_needed_dyntick(int cpu)
+{
+       long curr;
+       long snap;
+       struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu);
+
+       curr = rdssp->dynticks;
+       snap = rdssp->sched_dynticks_snap;
+       smp_mb(); /* force ordering with cpu entering/leaving dynticks. */
+
+       /*
+        * If the CPU remained in dynticks mode for the entire time
+        * and didn't take any interrupts, NMIs, SMIs, or whatever,
+        * then it cannot be in the middle of an rcu_read_lock(), so
+        * the next rcu_read_lock() it executes must use the new value
+        * of the counter.  Therefore, this CPU has been in a quiescent
+        * state the entire time, and we don't need to wait for it.
+        */
+
+       if ((curr == snap) && ((curr & 0x1) == 0))
+               return 0;
+
+       /*
+        * If the CPU passed through or entered a dynticks idle phase with
+        * no active irq handlers, then, as above, this CPU has already
+        * passed through a quiescent state.
+        */
+
+       if ((curr - snap) > 2 || (snap & 0x1) == 0)
+               return 0;
+
+       /* We need this CPU to go through a quiescent state. */
+
+       return 1;
+}
+
+#else /* !CONFIG_NO_HZ */
+
+# define dyntick_save_progress_counter(cpu)            do { } while (0)
+# define rcu_try_flip_waitack_needed(cpu)              (1)
+# define rcu_try_flip_waitmb_needed(cpu)               (1)
+
+# define dyntick_save_progress_counter_sched(cpu)      do { } while (0)
+# define rcu_qsctr_inc_needed_dyntick(cpu)             (1)
+
+#endif /* CONFIG_NO_HZ */
+
+static void save_qsctr_sched(int cpu)
+{
+       struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu);
+
+       rdssp->sched_qs_snap = rdssp->sched_qs;
+}
+
+static inline int rcu_qsctr_inc_needed(int cpu)
+{
+       struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu);
+
+       /*
+        * If there has been a quiescent state, no more need to wait
+        * on this CPU.
+        */
+
+       if (rdssp->sched_qs != rdssp->sched_qs_snap) {
+               smp_mb(); /* force ordering with cpu entering schedule(). */
+               return 0;
+       }
+
+       /* We need this CPU to go through a quiescent state. */
+
+       return 1;
+}
+
 /*
  * Get here when RCU is idle.  Decide whether we need to
  * move out of idle state, and return non-zero if so.
@@ -445,8 +759,10 @@ rcu_try_flip_idle(void)
 
        /* Now ask each CPU for acknowledgement of the flip. */
 
-       for_each_possible_cpu(cpu)
+       for_each_cpu(cpu, to_cpumask(rcu_cpu_online_map)) {
                per_cpu(rcu_flip_flag, cpu) = rcu_flipped;
+               dyntick_save_progress_counter(cpu);
+       }
 
        return 1;
 }
@@ -461,8 +777,9 @@ rcu_try_flip_waitack(void)
        int cpu;
 
        RCU_TRACE_ME(rcupreempt_trace_try_flip_a1);
-       for_each_possible_cpu(cpu)
-               if (per_cpu(rcu_flip_flag, cpu) != rcu_flip_seen) {
+       for_each_cpu(cpu, to_cpumask(rcu_cpu_online_map))
+               if (rcu_try_flip_waitack_needed(cpu) &&
+                   per_cpu(rcu_flip_flag, cpu) != rcu_flip_seen) {
                        RCU_TRACE_ME(rcupreempt_trace_try_flip_ae1);
                        return 0;
                }
@@ -492,7 +809,7 @@ rcu_try_flip_waitzero(void)
        /* Check to see if the sum of the "last" counters is zero. */
 
        RCU_TRACE_ME(rcupreempt_trace_try_flip_z1);
-       for_each_possible_cpu(cpu)
+       for_each_cpu(cpu, to_cpumask(rcu_cpu_online_map))
                sum += RCU_DATA_CPU(cpu)->rcu_flipctr[lastidx];
        if (sum != 0) {
                RCU_TRACE_ME(rcupreempt_trace_try_flip_ze1);
@@ -507,8 +824,10 @@ rcu_try_flip_waitzero(void)
        smp_mb();  /*  ^^^^^^^^^^^^ */
 
        /* Call for a memory barrier from each CPU. */
-       for_each_possible_cpu(cpu)
+       for_each_cpu(cpu, to_cpumask(rcu_cpu_online_map)) {
                per_cpu(rcu_mb_flag, cpu) = rcu_mb_needed;
+               dyntick_save_progress_counter(cpu);
+       }
 
        RCU_TRACE_ME(rcupreempt_trace_try_flip_z2);
        return 1;
@@ -525,8 +844,9 @@ rcu_try_flip_waitmb(void)
        int cpu;
 
        RCU_TRACE_ME(rcupreempt_trace_try_flip_m1);
-       for_each_possible_cpu(cpu)
-               if (per_cpu(rcu_mb_flag, cpu) != rcu_mb_done) {
+       for_each_cpu(cpu, to_cpumask(rcu_cpu_online_map))
+               if (rcu_try_flip_waitmb_needed(cpu) &&
+                   per_cpu(rcu_mb_flag, cpu) != rcu_mb_done) {
                        RCU_TRACE_ME(rcupreempt_trace_try_flip_me1);
                        return 0;
                }
@@ -603,6 +923,26 @@ void rcu_check_callbacks(int cpu, int user)
        unsigned long flags;
        struct rcu_data *rdp = RCU_DATA_CPU(cpu);
 
+       /*
+        * If this CPU took its interrupt from user mode or from the
+        * idle loop, and this is not a nested interrupt, then
+        * this CPU has to have exited all prior preept-disable
+        * sections of code.  So increment the counter to note this.
+        *
+        * The memory barrier is needed to handle the case where
+        * writes from a preempt-disable section of code get reordered
+        * into schedule() by this CPU's write buffer.  So the memory
+        * barrier makes sure that the rcu_qsctr_inc() is seen by other
+        * CPUs to happen after any such write.
+        */
+
+       if (user ||
+           (idle_cpu(cpu) && !in_softirq() &&
+            hardirq_count() <= (1 << HARDIRQ_SHIFT))) {
+               smp_mb();       /* Guard against aggressive schedule(). */
+               rcu_qsctr_inc(cpu);
+       }
+
        rcu_check_mb(cpu);
        if (rcu_ctrlblk.completed == rdp->completed)
                rcu_try_flip();
@@ -637,13 +977,129 @@ void rcu_advance_callbacks(int cpu, int user)
        spin_unlock_irqrestore(&rdp->lock, flags);
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+#define rcu_offline_cpu_enqueue(srclist, srctail, dstlist, dsttail) do { \
+               *dsttail = srclist; \
+               if (srclist != NULL) { \
+                       dsttail = srctail; \
+                       srclist = NULL; \
+                       srctail = &srclist;\
+               } \
+       } while (0)
+
+void rcu_offline_cpu(int cpu)
+{
+       int i;
+       struct rcu_head *list = NULL;
+       unsigned long flags;
+       struct rcu_data *rdp = RCU_DATA_CPU(cpu);
+       struct rcu_head *schedlist = NULL;
+       struct rcu_head **schedtail = &schedlist;
+       struct rcu_head **tail = &list;
+
+       /*
+        * Remove all callbacks from the newly dead CPU, retaining order.
+        * Otherwise rcu_barrier() will fail
+        */
+
+       spin_lock_irqsave(&rdp->lock, flags);
+       rcu_offline_cpu_enqueue(rdp->donelist, rdp->donetail, list, tail);
+       for (i = GP_STAGES - 1; i >= 0; i--)
+               rcu_offline_cpu_enqueue(rdp->waitlist[i], rdp->waittail[i],
+                                               list, tail);
+       rcu_offline_cpu_enqueue(rdp->nextlist, rdp->nexttail, list, tail);
+       rcu_offline_cpu_enqueue(rdp->waitschedlist, rdp->waitschedtail,
+                               schedlist, schedtail);
+       rcu_offline_cpu_enqueue(rdp->nextschedlist, rdp->nextschedtail,
+                               schedlist, schedtail);
+       rdp->rcu_sched_sleeping = 0;
+       spin_unlock_irqrestore(&rdp->lock, flags);
+       rdp->waitlistcount = 0;
+
+       /* Disengage the newly dead CPU from the grace-period computation. */
+
+       spin_lock_irqsave(&rcu_ctrlblk.fliplock, flags);
+       rcu_check_mb(cpu);
+       if (per_cpu(rcu_flip_flag, cpu) == rcu_flipped) {
+               smp_mb();  /* Subsequent counter accesses must see new value */
+               per_cpu(rcu_flip_flag, cpu) = rcu_flip_seen;
+               smp_mb();  /* Subsequent RCU read-side critical sections */
+                          /*  seen -after- acknowledgement. */
+       }
+
+       RCU_DATA_ME()->rcu_flipctr[0] += RCU_DATA_CPU(cpu)->rcu_flipctr[0];
+       RCU_DATA_ME()->rcu_flipctr[1] += RCU_DATA_CPU(cpu)->rcu_flipctr[1];
+
+       RCU_DATA_CPU(cpu)->rcu_flipctr[0] = 0;
+       RCU_DATA_CPU(cpu)->rcu_flipctr[1] = 0;
+
+       cpumask_clear_cpu(cpu, to_cpumask(rcu_cpu_online_map));
+
+       spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags);
+
+       /*
+        * Place the removed callbacks on the current CPU's queue.
+        * Make them all start a new grace period: simple approach,
+        * in theory could starve a given set of callbacks, but
+        * you would need to be doing some serious CPU hotplugging
+        * to make this happen.  If this becomes a problem, adding
+        * a synchronize_rcu() to the hotplug path would be a simple
+        * fix.
+        */
+
+       local_irq_save(flags);  /* disable preempt till we know what lock. */
+       rdp = RCU_DATA_ME();
+       spin_lock(&rdp->lock);
+       *rdp->nexttail = list;
+       if (list)
+               rdp->nexttail = tail;
+       *rdp->nextschedtail = schedlist;
+       if (schedlist)
+               rdp->nextschedtail = schedtail;
+       spin_unlock_irqrestore(&rdp->lock, flags);
+}
+
+#else /* #ifdef CONFIG_HOTPLUG_CPU */
+
+void rcu_offline_cpu(int cpu)
+{
+}
+
+#endif /* #else #ifdef CONFIG_HOTPLUG_CPU */
+
+void __cpuinit rcu_online_cpu(int cpu)
+{
+       unsigned long flags;
+       struct rcu_data *rdp;
+
+       spin_lock_irqsave(&rcu_ctrlblk.fliplock, flags);
+       cpumask_set_cpu(cpu, to_cpumask(rcu_cpu_online_map));
+       spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags);
+
+       /*
+        * The rcu_sched grace-period processing might have bypassed
+        * this CPU, given that it was not in the rcu_cpu_online_map
+        * when the grace-period scan started.  This means that the
+        * grace-period task might sleep.  So make sure that if this
+        * should happen, the first callback posted to this CPU will
+        * wake up the grace-period task if need be.
+        */
+
+       rdp = RCU_DATA_CPU(cpu);
+       spin_lock_irqsave(&rdp->lock, flags);
+       rdp->rcu_sched_sleeping = 1;
+       spin_unlock_irqrestore(&rdp->lock, flags);
+}
+
 static void rcu_process_callbacks(struct softirq_action *unused)
 {
        unsigned long flags;
        struct rcu_head *next, *list;
-       struct rcu_data *rdp = RCU_DATA_ME();
+       struct rcu_data *rdp;
 
-       spin_lock_irqsave(&rdp->lock, flags);
+       local_irq_save(flags);
+       rdp = RCU_DATA_ME();
+       spin_lock(&rdp->lock);
        list = rdp->donelist;
        if (list == NULL) {
                spin_unlock_irqrestore(&rdp->lock, flags);
@@ -675,11 +1131,46 @@ void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
        *rdp->nexttail = head;
        rdp->nexttail = &head->next;
        RCU_TRACE_RDP(rcupreempt_trace_next_add, rdp);
-       spin_unlock(&rdp->lock);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&rdp->lock, flags);
 }
 EXPORT_SYMBOL_GPL(call_rcu);
 
+void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
+{
+       unsigned long flags;
+       struct rcu_data *rdp;
+       int wake_gp = 0;
+
+       head->func = func;
+       head->next = NULL;
+       local_irq_save(flags);
+       rdp = RCU_DATA_ME();
+       spin_lock(&rdp->lock);
+       *rdp->nextschedtail = head;
+       rdp->nextschedtail = &head->next;
+       if (rdp->rcu_sched_sleeping) {
+
+               /* Grace-period processing might be sleeping... */
+
+               rdp->rcu_sched_sleeping = 0;
+               wake_gp = 1;
+       }
+       spin_unlock_irqrestore(&rdp->lock, flags);
+       if (wake_gp) {
+
+               /* Wake up grace-period processing, unless someone beat us. */
+
+               spin_lock_irqsave(&rcu_ctrlblk.schedlock, flags);
+               if (rcu_ctrlblk.sched_sleep != rcu_sched_sleeping)
+                       wake_gp = 0;
+               rcu_ctrlblk.sched_sleep = rcu_sched_not_sleeping;
+               spin_unlock_irqrestore(&rcu_ctrlblk.schedlock, flags);
+               if (wake_gp)
+                       wake_up_interruptible(&rcu_ctrlblk.sched_wq);
+       }
+}
+EXPORT_SYMBOL_GPL(call_rcu_sched);
+
 /*
  * Wait until all currently running preempt_disable() code segments
  * (including hardware-irq-disable segments) complete.  Note that
@@ -688,20 +1179,162 @@ EXPORT_SYMBOL_GPL(call_rcu);
  */
 void __synchronize_sched(void)
 {
-       cpumask_t oldmask;
-       int cpu;
+       struct rcu_synchronize rcu;
 
-       if (sched_getaffinity(0, &oldmask) < 0)
-               oldmask = cpu_possible_map;
-       for_each_online_cpu(cpu) {
-               sched_setaffinity(0, cpumask_of_cpu(cpu));
-               schedule();
-       }
-       sched_setaffinity(0, oldmask);
+       if (num_online_cpus() == 1)
+               return;  /* blocking is gp if only one CPU! */
+
+       init_completion(&rcu.completion);
+       /* Will wake me after RCU finished. */
+       call_rcu_sched(&rcu.head, wakeme_after_rcu);
+       /* Wait for it. */
+       wait_for_completion(&rcu.completion);
 }
 EXPORT_SYMBOL_GPL(__synchronize_sched);
 
 /*
+ * kthread function that manages call_rcu_sched grace periods.
+ */
+static int rcu_sched_grace_period(void *arg)
+{
+       int couldsleep;         /* might sleep after current pass. */
+       int couldsleepnext = 0; /* might sleep after next pass. */
+       int cpu;
+       unsigned long flags;
+       struct rcu_data *rdp;
+       int ret;
+
+       /*
+        * Each pass through the following loop handles one
+        * rcu_sched grace period cycle.
+        */
+       do {
+               /* Save each CPU's current state. */
+
+               for_each_online_cpu(cpu) {
+                       dyntick_save_progress_counter_sched(cpu);
+                       save_qsctr_sched(cpu);
+               }
+
+               /*
+                * Sleep for about an RCU grace-period's worth to
+                * allow better batching and to consume less CPU.
+                */
+               schedule_timeout_interruptible(RCU_SCHED_BATCH_TIME);
+
+               /*
+                * If there was nothing to do last time, prepare to
+                * sleep at the end of the current grace period cycle.
+                */
+               couldsleep = couldsleepnext;
+               couldsleepnext = 1;
+               if (couldsleep) {
+                       spin_lock_irqsave(&rcu_ctrlblk.schedlock, flags);
+                       rcu_ctrlblk.sched_sleep = rcu_sched_sleep_prep;
+                       spin_unlock_irqrestore(&rcu_ctrlblk.schedlock, flags);
+               }
+
+               /*
+                * Wait on each CPU in turn to have either visited
+                * a quiescent state or been in dynticks-idle mode.
+                */
+               for_each_online_cpu(cpu) {
+                       while (rcu_qsctr_inc_needed(cpu) &&
+                              rcu_qsctr_inc_needed_dyntick(cpu)) {
+                               /* resched_cpu(cpu); @@@ */
+                               schedule_timeout_interruptible(1);
+                       }
+               }
+
+               /* Advance callbacks for each CPU.  */
+
+               for_each_online_cpu(cpu) {
+
+                       rdp = RCU_DATA_CPU(cpu);
+                       spin_lock_irqsave(&rdp->lock, flags);
+
+                       /*
+                        * We are running on this CPU irq-disabled, so no
+                        * CPU can go offline until we re-enable irqs.
+                        * The current CPU might have already gone
+                        * offline (between the for_each_offline_cpu and
+                        * the spin_lock_irqsave), but in that case all its
+                        * callback lists will be empty, so no harm done.
+                        *
+                        * Advance the callbacks!  We share normal RCU's
+                        * donelist, since callbacks are invoked the
+                        * same way in either case.
+                        */
+                       if (rdp->waitschedlist != NULL) {
+                               *rdp->donetail = rdp->waitschedlist;
+                               rdp->donetail = rdp->waitschedtail;
+
+                               /*
+                                * Next rcu_check_callbacks() will
+                                * do the required raise_softirq().
+                                */
+                       }
+                       if (rdp->nextschedlist != NULL) {
+                               rdp->waitschedlist = rdp->nextschedlist;
+                               rdp->waitschedtail = rdp->nextschedtail;
+                               couldsleep = 0;
+                               couldsleepnext = 0;
+                       } else {
+                               rdp->waitschedlist = NULL;
+                               rdp->waitschedtail = &rdp->waitschedlist;
+                       }
+                       rdp->nextschedlist = NULL;
+                       rdp->nextschedtail = &rdp->nextschedlist;
+
+                       /* Mark sleep intention. */
+
+                       rdp->rcu_sched_sleeping = couldsleep;
+
+                       spin_unlock_irqrestore(&rdp->lock, flags);
+               }
+
+               /* If we saw callbacks on the last scan, go deal with them. */
+
+               if (!couldsleep)
+                       continue;
+
+               /* Attempt to block... */
+
+               spin_lock_irqsave(&rcu_ctrlblk.schedlock, flags);
+               if (rcu_ctrlblk.sched_sleep != rcu_sched_sleep_prep) {
+
+                       /*
+                        * Someone posted a callback after we scanned.
+                        * Go take care of it.
+                        */
+                       spin_unlock_irqrestore(&rcu_ctrlblk.schedlock, flags);
+                       couldsleepnext = 0;
+                       continue;
+               }
+
+               /* Block until the next person posts a callback. */
+
+               rcu_ctrlblk.sched_sleep = rcu_sched_sleeping;
+               spin_unlock_irqrestore(&rcu_ctrlblk.schedlock, flags);
+               ret = 0;
+               __wait_event_interruptible(rcu_ctrlblk.sched_wq,
+                       rcu_ctrlblk.sched_sleep != rcu_sched_sleeping,
+                       ret);
+
+               /*
+                * Signals would prevent us from sleeping, and we cannot
+                * do much with them in any case.  So flush them.
+                */
+               if (ret)
+                       flush_signals(current);
+               couldsleepnext = 0;
+
+       } while (!kthread_should_stop());
+
+       return (0);
+}
+
+/*
  * Check to see if any future RCU-related work will need to be done
  * by the current CPU, even if none need be done immediately, returning
  * 1 if so.  Assumes that notifiers would take care of handling any
@@ -716,7 +1349,9 @@ int rcu_needs_cpu(int cpu)
 
        return (rdp->donelist != NULL ||
                !!rdp->waitlistcount ||
-               rdp->nextlist != NULL);
+               rdp->nextlist != NULL ||
+               rdp->nextschedlist != NULL ||
+               rdp->waitschedlist != NULL);
 }
 
 int rcu_pending(int cpu)
@@ -727,7 +1362,9 @@ int rcu_pending(int cpu)
 
        if (rdp->donelist != NULL ||
            !!rdp->waitlistcount ||
-           rdp->nextlist != NULL)
+           rdp->nextlist != NULL ||
+           rdp->nextschedlist != NULL ||
+           rdp->waitschedlist != NULL)
                return 1;
 
        /* The RCU core needs an acknowledgement from this CPU. */
@@ -746,6 +1383,32 @@ int rcu_pending(int cpu)
        return 0;
 }
 
+static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
+                               unsigned long action, void *hcpu)
+{
+       long cpu = (long)hcpu;
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
+               rcu_online_cpu(cpu);
+               break;
+       case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
+       case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
+               rcu_offline_cpu(cpu);
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata rcu_nb = {
+       .notifier_call = rcu_cpu_notify,
+};
+
 void __init __rcu_init(void)
 {
        int cpu;
@@ -768,16 +1431,42 @@ void __init __rcu_init(void)
                rdp->donetail = &rdp->donelist;
                rdp->rcu_flipctr[0] = 0;
                rdp->rcu_flipctr[1] = 0;
+               rdp->nextschedlist = NULL;
+               rdp->nextschedtail = &rdp->nextschedlist;
+               rdp->waitschedlist = NULL;
+               rdp->waitschedtail = &rdp->waitschedlist;
+               rdp->rcu_sched_sleeping = 0;
        }
-       open_softirq(RCU_SOFTIRQ, rcu_process_callbacks, NULL);
+       register_cpu_notifier(&rcu_nb);
+
+       /*
+        * We don't need protection against CPU-Hotplug here
+        * since
+        * a) If a CPU comes online while we are iterating over the
+        *    cpu_online_mask below, we would only end up making a
+        *    duplicate call to rcu_online_cpu() which sets the corresponding
+        *    CPU's mask in the rcu_cpu_online_map.
+        *
+        * b) A CPU cannot go offline at this point in time since the user
+        *    does not have access to the sysfs interface, nor do we
+        *    suspend the system.
+        */
+       for_each_online_cpu(cpu)
+               rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, (void *)(long) cpu);
+
+       open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
 }
 
 /*
- * Deprecated, use synchronize_rcu() or synchronize_sched() instead.
+ * Late-boot-time RCU initialization that must wait until after scheduler
+ * has been initialized.
  */
-void synchronize_kernel(void)
+void __init rcu_init_sched(void)
 {
-       synchronize_rcu();
+       rcu_sched_grace_period_task = kthread_run(rcu_sched_grace_period,
+                                                 NULL,
+                                                 "rcu_sched_grace_period");
+       WARN_ON(IS_ERR(rcu_sched_grace_period_task));
 }
 
 #ifdef CONFIG_RCU_TRACE