diff options
Diffstat (limited to 'kernel/rcu/tree.c')
-rw-r--r-- | kernel/rcu/tree.c | 80 |
1 files changed, 66 insertions, 14 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index b3d116cd072d..0c47e300210a 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c | |||
@@ -12,8 +12,8 @@ | |||
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, you can access it online at |
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 16 | * http://www.gnu.org/licenses/gpl-2.0.html. |
17 | * | 17 | * |
18 | * Copyright IBM Corporation, 2008 | 18 | * Copyright IBM Corporation, 2008 |
19 | * | 19 | * |
@@ -58,8 +58,6 @@ | |||
58 | #include <linux/suspend.h> | 58 | #include <linux/suspend.h> |
59 | 59 | ||
60 | #include "tree.h" | 60 | #include "tree.h" |
61 | #include <trace/events/rcu.h> | ||
62 | |||
63 | #include "rcu.h" | 61 | #include "rcu.h" |
64 | 62 | ||
65 | MODULE_ALIAS("rcutree"); | 63 | MODULE_ALIAS("rcutree"); |
@@ -837,7 +835,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp, | |||
837 | * to the next. Only do this for the primary flavor of RCU. | 835 | * to the next. Only do this for the primary flavor of RCU. |
838 | */ | 836 | */ |
839 | if (rdp->rsp == rcu_state && | 837 | if (rdp->rsp == rcu_state && |
840 | ULONG_CMP_GE(ACCESS_ONCE(jiffies), rdp->rsp->jiffies_resched)) { | 838 | ULONG_CMP_GE(jiffies, rdp->rsp->jiffies_resched)) { |
841 | rdp->rsp->jiffies_resched += 5; | 839 | rdp->rsp->jiffies_resched += 5; |
842 | resched_cpu(rdp->cpu); | 840 | resched_cpu(rdp->cpu); |
843 | } | 841 | } |
@@ -847,7 +845,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp, | |||
847 | 845 | ||
848 | static void record_gp_stall_check_time(struct rcu_state *rsp) | 846 | static void record_gp_stall_check_time(struct rcu_state *rsp) |
849 | { | 847 | { |
850 | unsigned long j = ACCESS_ONCE(jiffies); | 848 | unsigned long j = jiffies; |
851 | unsigned long j1; | 849 | unsigned long j1; |
852 | 850 | ||
853 | rsp->gp_start = j; | 851 | rsp->gp_start = j; |
@@ -1005,7 +1003,7 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1005 | 1003 | ||
1006 | if (rcu_cpu_stall_suppress || !rcu_gp_in_progress(rsp)) | 1004 | if (rcu_cpu_stall_suppress || !rcu_gp_in_progress(rsp)) |
1007 | return; | 1005 | return; |
1008 | j = ACCESS_ONCE(jiffies); | 1006 | j = jiffies; |
1009 | 1007 | ||
1010 | /* | 1008 | /* |
1011 | * Lots of memory barriers to reject false positives. | 1009 | * Lots of memory barriers to reject false positives. |
@@ -1423,13 +1421,14 @@ static int rcu_gp_init(struct rcu_state *rsp) | |||
1423 | 1421 | ||
1424 | /* Advance to a new grace period and initialize state. */ | 1422 | /* Advance to a new grace period and initialize state. */ |
1425 | record_gp_stall_check_time(rsp); | 1423 | record_gp_stall_check_time(rsp); |
1426 | smp_wmb(); /* Record GP times before starting GP. */ | 1424 | /* Record GP times before starting GP, hence smp_store_release(). */ |
1427 | rsp->gpnum++; | 1425 | smp_store_release(&rsp->gpnum, rsp->gpnum + 1); |
1428 | trace_rcu_grace_period(rsp->name, rsp->gpnum, TPS("start")); | 1426 | trace_rcu_grace_period(rsp->name, rsp->gpnum, TPS("start")); |
1429 | raw_spin_unlock_irq(&rnp->lock); | 1427 | raw_spin_unlock_irq(&rnp->lock); |
1430 | 1428 | ||
1431 | /* Exclude any concurrent CPU-hotplug operations. */ | 1429 | /* Exclude any concurrent CPU-hotplug operations. */ |
1432 | mutex_lock(&rsp->onoff_mutex); | 1430 | mutex_lock(&rsp->onoff_mutex); |
1431 | smp_mb__after_unlock_lock(); /* ->gpnum increment before GP! */ | ||
1433 | 1432 | ||
1434 | /* | 1433 | /* |
1435 | * Set the quiescent-state-needed bits in all the rcu_node | 1434 | * Set the quiescent-state-needed bits in all the rcu_node |
@@ -1557,10 +1556,11 @@ static void rcu_gp_cleanup(struct rcu_state *rsp) | |||
1557 | } | 1556 | } |
1558 | rnp = rcu_get_root(rsp); | 1557 | rnp = rcu_get_root(rsp); |
1559 | raw_spin_lock_irq(&rnp->lock); | 1558 | raw_spin_lock_irq(&rnp->lock); |
1560 | smp_mb__after_unlock_lock(); | 1559 | smp_mb__after_unlock_lock(); /* Order GP before ->completed update. */ |
1561 | rcu_nocb_gp_set(rnp, nocb); | 1560 | rcu_nocb_gp_set(rnp, nocb); |
1562 | 1561 | ||
1563 | rsp->completed = rsp->gpnum; /* Declare grace period done. */ | 1562 | /* Declare grace period done. */ |
1563 | ACCESS_ONCE(rsp->completed) = rsp->gpnum; | ||
1564 | trace_rcu_grace_period(rsp->name, rsp->completed, TPS("end")); | 1564 | trace_rcu_grace_period(rsp->name, rsp->completed, TPS("end")); |
1565 | rsp->fqs_state = RCU_GP_IDLE; | 1565 | rsp->fqs_state = RCU_GP_IDLE; |
1566 | rdp = this_cpu_ptr(rsp->rda); | 1566 | rdp = this_cpu_ptr(rsp->rda); |
@@ -2304,7 +2304,7 @@ static void force_quiescent_state(struct rcu_state *rsp) | |||
2304 | if (rnp_old != NULL) | 2304 | if (rnp_old != NULL) |
2305 | raw_spin_unlock(&rnp_old->fqslock); | 2305 | raw_spin_unlock(&rnp_old->fqslock); |
2306 | if (ret) { | 2306 | if (ret) { |
2307 | rsp->n_force_qs_lh++; | 2307 | ACCESS_ONCE(rsp->n_force_qs_lh)++; |
2308 | return; | 2308 | return; |
2309 | } | 2309 | } |
2310 | rnp_old = rnp; | 2310 | rnp_old = rnp; |
@@ -2316,7 +2316,7 @@ static void force_quiescent_state(struct rcu_state *rsp) | |||
2316 | smp_mb__after_unlock_lock(); | 2316 | smp_mb__after_unlock_lock(); |
2317 | raw_spin_unlock(&rnp_old->fqslock); | 2317 | raw_spin_unlock(&rnp_old->fqslock); |
2318 | if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) { | 2318 | if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) { |
2319 | rsp->n_force_qs_lh++; | 2319 | ACCESS_ONCE(rsp->n_force_qs_lh)++; |
2320 | raw_spin_unlock_irqrestore(&rnp_old->lock, flags); | 2320 | raw_spin_unlock_irqrestore(&rnp_old->lock, flags); |
2321 | return; /* Someone beat us to it. */ | 2321 | return; /* Someone beat us to it. */ |
2322 | } | 2322 | } |
@@ -2639,6 +2639,58 @@ void synchronize_rcu_bh(void) | |||
2639 | } | 2639 | } |
2640 | EXPORT_SYMBOL_GPL(synchronize_rcu_bh); | 2640 | EXPORT_SYMBOL_GPL(synchronize_rcu_bh); |
2641 | 2641 | ||
2642 | /** | ||
2643 | * get_state_synchronize_rcu - Snapshot current RCU state | ||
2644 | * | ||
2645 | * Returns a cookie that is used by a later call to cond_synchronize_rcu() | ||
2646 | * to determine whether or not a full grace period has elapsed in the | ||
2647 | * meantime. | ||
2648 | */ | ||
2649 | unsigned long get_state_synchronize_rcu(void) | ||
2650 | { | ||
2651 | /* | ||
2652 | * Any prior manipulation of RCU-protected data must happen | ||
2653 | * before the load from ->gpnum. | ||
2654 | */ | ||
2655 | smp_mb(); /* ^^^ */ | ||
2656 | |||
2657 | /* | ||
2658 | * Make sure this load happens before the purportedly | ||
2659 | * time-consuming work between get_state_synchronize_rcu() | ||
2660 | * and cond_synchronize_rcu(). | ||
2661 | */ | ||
2662 | return smp_load_acquire(&rcu_state->gpnum); | ||
2663 | } | ||
2664 | EXPORT_SYMBOL_GPL(get_state_synchronize_rcu); | ||
2665 | |||
2666 | /** | ||
2667 | * cond_synchronize_rcu - Conditionally wait for an RCU grace period | ||
2668 | * | ||
2669 | * @oldstate: return value from earlier call to get_state_synchronize_rcu() | ||
2670 | * | ||
2671 | * If a full RCU grace period has elapsed since the earlier call to | ||
2672 | * get_state_synchronize_rcu(), just return. Otherwise, invoke | ||
2673 | * synchronize_rcu() to wait for a full grace period. | ||
2674 | * | ||
2675 | * Yes, this function does not take counter wrap into account. But | ||
2676 | * counter wrap is harmless. If the counter wraps, we have waited for | ||
2677 | * more than 2 billion grace periods (and way more on a 64-bit system!), | ||
2678 | * so waiting for one additional grace period should be just fine. | ||
2679 | */ | ||
2680 | void cond_synchronize_rcu(unsigned long oldstate) | ||
2681 | { | ||
2682 | unsigned long newstate; | ||
2683 | |||
2684 | /* | ||
2685 | * Ensure that this load happens before any RCU-destructive | ||
2686 | * actions the caller might carry out after we return. | ||
2687 | */ | ||
2688 | newstate = smp_load_acquire(&rcu_state->completed); | ||
2689 | if (ULONG_CMP_GE(oldstate, newstate)) | ||
2690 | synchronize_rcu(); | ||
2691 | } | ||
2692 | EXPORT_SYMBOL_GPL(cond_synchronize_rcu); | ||
2693 | |||
2642 | static int synchronize_sched_expedited_cpu_stop(void *data) | 2694 | static int synchronize_sched_expedited_cpu_stop(void *data) |
2643 | { | 2695 | { |
2644 | /* | 2696 | /* |
@@ -2880,7 +2932,7 @@ static int rcu_pending(int cpu) | |||
2880 | * non-NULL, store an indication of whether all callbacks are lazy. | 2932 | * non-NULL, store an indication of whether all callbacks are lazy. |
2881 | * (If there are no callbacks, all of them are deemed to be lazy.) | 2933 | * (If there are no callbacks, all of them are deemed to be lazy.) |
2882 | */ | 2934 | */ |
2883 | static int rcu_cpu_has_callbacks(int cpu, bool *all_lazy) | 2935 | static int __maybe_unused rcu_cpu_has_callbacks(int cpu, bool *all_lazy) |
2884 | { | 2936 | { |
2885 | bool al = true; | 2937 | bool al = true; |
2886 | bool hc = false; | 2938 | bool hc = false; |