rcu: merge TREE_PREEPT_RCU blocked_tasks[] lists
[deliverable/linux.git] / kernel / rcutree.c
index dd4aea806f8ef63ba882af3a47d5981b366d4dc7..0ac1cc03f9353212d34aa8828fa49c11da941f46 100644 (file)
@@ -128,7 +128,7 @@ void rcu_note_context_switch(int cpu)
 #ifdef CONFIG_NO_HZ
 DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {
        .dynticks_nesting = 1,
-       .dynticks = 1,
+       .dynticks = ATOMIC_INIT(1),
 };
 #endif /* #ifdef CONFIG_NO_HZ */
 
@@ -140,10 +140,8 @@ module_param(blimit, int, 0);
 module_param(qhimark, int, 0);
 module_param(qlowmark, int, 0);
 
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
-int rcu_cpu_stall_suppress __read_mostly = RCU_CPU_STALL_SUPPRESS_INIT;
+int rcu_cpu_stall_suppress __read_mostly;
 module_param(rcu_cpu_stall_suppress, int, 0644);
-#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
 
 static void force_quiescent_state(struct rcu_state *rsp, int relaxed);
 static int rcu_pending(int cpu);
@@ -264,13 +262,25 @@ void rcu_enter_nohz(void)
        unsigned long flags;
        struct rcu_dynticks *rdtp;
 
-       smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */
        local_irq_save(flags);
        rdtp = &__get_cpu_var(rcu_dynticks);
-       rdtp->dynticks++;
-       rdtp->dynticks_nesting--;
-       WARN_ON_ONCE(rdtp->dynticks & 0x1);
+       if (--rdtp->dynticks_nesting) {
+               local_irq_restore(flags);
+               return;
+       }
+       /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */
+       smp_mb__before_atomic_inc();  /* See above. */
+       atomic_inc(&rdtp->dynticks);
+       smp_mb__after_atomic_inc();  /* Force ordering with next sojourn. */
+       WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1);
        local_irq_restore(flags);
+
+       /* If the interrupt queued a callback, get out of dyntick mode. */
+       if (in_irq() &&
+           (__get_cpu_var(rcu_sched_data).nxtlist ||
+            __get_cpu_var(rcu_bh_data).nxtlist ||
+            rcu_preempt_needs_cpu(smp_processor_id())))
+               set_need_resched();
 }
 
 /*
@@ -286,11 +296,16 @@ void rcu_exit_nohz(void)
 
        local_irq_save(flags);
        rdtp = &__get_cpu_var(rcu_dynticks);
-       rdtp->dynticks++;
-       rdtp->dynticks_nesting++;
-       WARN_ON_ONCE(!(rdtp->dynticks & 0x1));
+       if (rdtp->dynticks_nesting++) {
+               local_irq_restore(flags);
+               return;
+       }
+       smp_mb__before_atomic_inc();  /* Force ordering w/previous sojourn. */
+       atomic_inc(&rdtp->dynticks);
+       /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */
+       smp_mb__after_atomic_inc();  /* See above. */
+       WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1));
        local_irq_restore(flags);
-       smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
 }
 
 /**
@@ -304,11 +319,15 @@ void rcu_nmi_enter(void)
 {
        struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
 
-       if (rdtp->dynticks & 0x1)
+       if (rdtp->dynticks_nmi_nesting == 0 &&
+           (atomic_read(&rdtp->dynticks) & 0x1))
                return;
-       rdtp->dynticks_nmi++;
-       WARN_ON_ONCE(!(rdtp->dynticks_nmi & 0x1));
-       smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
+       rdtp->dynticks_nmi_nesting++;
+       smp_mb__before_atomic_inc();  /* Force delay from prior write. */
+       atomic_inc(&rdtp->dynticks);
+       /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */
+       smp_mb__after_atomic_inc();  /* See above. */
+       WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1));
 }
 
 /**
@@ -322,11 +341,14 @@ void rcu_nmi_exit(void)
 {
        struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
 
-       if (rdtp->dynticks & 0x1)
+       if (rdtp->dynticks_nmi_nesting == 0 ||
+           --rdtp->dynticks_nmi_nesting != 0)
                return;
-       smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */
-       rdtp->dynticks_nmi++;
-       WARN_ON_ONCE(rdtp->dynticks_nmi & 0x1);
+       /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */
+       smp_mb__before_atomic_inc();  /* See above. */
+       atomic_inc(&rdtp->dynticks);
+       smp_mb__after_atomic_inc();  /* Force delay to next write. */
+       WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1);
 }
 
 /**
@@ -337,13 +359,7 @@ void rcu_nmi_exit(void)
  */
 void rcu_irq_enter(void)
 {
-       struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
-
-       if (rdtp->dynticks_nesting++)
-               return;
-       rdtp->dynticks++;
-       WARN_ON_ONCE(!(rdtp->dynticks & 0x1));
-       smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
+       rcu_exit_nohz();
 }
 
 /**
@@ -355,18 +371,7 @@ void rcu_irq_enter(void)
  */
 void rcu_irq_exit(void)
 {
-       struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
-
-       if (--rdtp->dynticks_nesting)
-               return;
-       smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */
-       rdtp->dynticks++;
-       WARN_ON_ONCE(rdtp->dynticks & 0x1);
-
-       /* If the interrupt queued a callback, get out of dyntick mode. */
-       if (__this_cpu_read(rcu_sched_data.nxtlist) ||
-           __this_cpu_read(rcu_bh_data.nxtlist))
-               set_need_resched();
+       rcu_enter_nohz();
 }
 
 #ifdef CONFIG_SMP
@@ -378,19 +383,8 @@ void rcu_irq_exit(void)
  */
 static int dyntick_save_progress_counter(struct rcu_data *rdp)
 {
-       int ret;
-       int snap;
-       int snap_nmi;
-
-       snap = rdp->dynticks->dynticks;
-       snap_nmi = rdp->dynticks->dynticks_nmi;
-       smp_mb();       /* Order sampling of snap with end of grace period. */
-       rdp->dynticks_snap = snap;
-       rdp->dynticks_nmi_snap = snap_nmi;
-       ret = ((snap & 0x1) == 0) && ((snap_nmi & 0x1) == 0);
-       if (ret)
-               rdp->dynticks_fqs++;
-       return ret;
+       rdp->dynticks_snap = atomic_add_return(0, &rdp->dynticks->dynticks);
+       return 0;
 }
 
 /*
@@ -401,16 +395,11 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp)
  */
 static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
 {
-       long curr;
-       long curr_nmi;
-       long snap;
-       long snap_nmi;
+       unsigned long curr;
+       unsigned long snap;
 
-       curr = rdp->dynticks->dynticks;
-       snap = rdp->dynticks_snap;
-       curr_nmi = rdp->dynticks->dynticks_nmi;
-       snap_nmi = rdp->dynticks_nmi_snap;
-       smp_mb(); /* force ordering with cpu entering/leaving dynticks. */
+       curr = (unsigned long)atomic_add_return(0, &rdp->dynticks->dynticks);
+       snap = (unsigned long)rdp->dynticks_snap;
 
        /*
         * If the CPU passed through or entered a dynticks idle phase with
@@ -420,8 +409,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
         * read-side critical section that started before the beginning
         * of the current RCU grace period.
         */
-       if ((curr != snap || (curr & 0x1) == 0) &&
-           (curr_nmi != snap_nmi || (curr_nmi & 0x1) == 0)) {
+       if ((curr & 0x1) == 0 || ULONG_CMP_GE(curr, snap + 2)) {
                rdp->dynticks_fqs++;
                return 1;
        }
@@ -450,8 +438,6 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
 
 #endif /* #else #ifdef CONFIG_NO_HZ */
 
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
-
 int rcu_cpu_stall_suppress __read_mostly;
 
 static void record_gp_stall_check_time(struct rcu_state *rsp)
@@ -587,26 +573,6 @@ static void __init check_cpu_stall_init(void)
        atomic_notifier_chain_register(&panic_notifier_list, &rcu_panic_block);
 }
 
-#else /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
-
-static void record_gp_stall_check_time(struct rcu_state *rsp)
-{
-}
-
-static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
-{
-}
-
-void rcu_cpu_stall_reset(void)
-{
-}
-
-static void __init check_cpu_stall_init(void)
-{
-}
-
-#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
-
 /*
  * Update CPU-local rcu_data state to record the newly noticed grace period.
  * This is used both when we started the grace period and when we notice
@@ -865,6 +831,12 @@ 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));
+
+       /*
+        * Ensure that all grace-period and pre-grace-period activity
+        * is seen before the assignment to rsp->completed.
+        */
+       smp_mb(); /* See above block comment. */
        rsp->completed = rsp->gpnum;
        rsp->signaled = RCU_GP_IDLE;
        rcu_start_gp(rsp, flags);  /* releases root node's rnp->lock. */
@@ -1391,25 +1363,11 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp)
  */
 static void rcu_process_callbacks(struct softirq_action *unused)
 {
-       /*
-        * Memory references from any prior RCU read-side critical sections
-        * executed by the interrupted code must be seen before any RCU
-        * grace-period manipulations below.
-        */
-       smp_mb(); /* See above block comment. */
-
        __rcu_process_callbacks(&rcu_sched_state,
                                &__get_cpu_var(rcu_sched_data));
        __rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data));
        rcu_preempt_process_callbacks();
 
-       /*
-        * Memory references from any later RCU read-side critical sections
-        * executed by the interrupted code must be seen after any RCU
-        * grace-period manipulations above.
-        */
-       smp_mb(); /* See above block comment. */
-
        /* If we are last CPU on way to dyntick-idle mode, accelerate it. */
        rcu_needs_cpu_flush();
 }
@@ -1943,10 +1901,7 @@ static void __init rcu_init_one(struct rcu_state *rsp,
                                              j / rsp->levelspread[i - 1];
                        }
                        rnp->level = i;
-                       INIT_LIST_HEAD(&rnp->blocked_tasks[0]);
-                       INIT_LIST_HEAD(&rnp->blocked_tasks[1]);
-                       INIT_LIST_HEAD(&rnp->blocked_tasks[2]);
-                       INIT_LIST_HEAD(&rnp->blocked_tasks[3]);
+                       INIT_LIST_HEAD(&rnp->blkd_tasks);
                }
        }
 
This page took 0.028592 seconds and 5 git commands to generate.