diff options
-rw-r--r-- | include/trace/events/rcu.h | 18 | ||||
-rw-r--r-- | kernel/rcu/tree.c | 15 | ||||
-rw-r--r-- | kernel/rcu/tree.h | 1 | ||||
-rw-r--r-- | kernel/rcu/tree_plugin.h | 33 |
4 files changed, 53 insertions, 14 deletions
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h index 9b56f37148cf..e335e7d8c6c2 100644 --- a/include/trace/events/rcu.h +++ b/include/trace/events/rcu.h | |||
@@ -660,18 +660,18 @@ TRACE_EVENT(rcu_torture_read, | |||
660 | /* | 660 | /* |
661 | * Tracepoint for _rcu_barrier() execution. The string "s" describes | 661 | * Tracepoint for _rcu_barrier() execution. The string "s" describes |
662 | * the _rcu_barrier phase: | 662 | * the _rcu_barrier phase: |
663 | * "Begin": rcu_barrier_callback() started. | 663 | * "Begin": _rcu_barrier() started. |
664 | * "Check": rcu_barrier_callback() checking for piggybacking. | 664 | * "Check": _rcu_barrier() checking for piggybacking. |
665 | * "EarlyExit": rcu_barrier_callback() piggybacked, thus early exit. | 665 | * "EarlyExit": _rcu_barrier() piggybacked, thus early exit. |
666 | * "Inc1": rcu_barrier_callback() piggyback check counter incremented. | 666 | * "Inc1": _rcu_barrier() piggyback check counter incremented. |
667 | * "Offline": rcu_barrier_callback() found offline CPU | 667 | * "OfflineNoCB": _rcu_barrier() found callback on never-online CPU |
668 | * "OnlineNoCB": rcu_barrier_callback() found online no-CBs CPU. | 668 | * "OnlineNoCB": _rcu_barrier() found online no-CBs CPU. |
669 | * "OnlineQ": rcu_barrier_callback() found online CPU with callbacks. | 669 | * "OnlineQ": _rcu_barrier() found online CPU with callbacks. |
670 | * "OnlineNQ": rcu_barrier_callback() found online CPU, no callbacks. | 670 | * "OnlineNQ": _rcu_barrier() found online CPU, no callbacks. |
671 | * "IRQ": An rcu_barrier_callback() callback posted on remote CPU. | 671 | * "IRQ": An rcu_barrier_callback() callback posted on remote CPU. |
672 | * "CB": An rcu_barrier_callback() invoked a callback, not the last. | 672 | * "CB": An rcu_barrier_callback() invoked a callback, not the last. |
673 | * "LastCB": An rcu_barrier_callback() invoked the last callback. | 673 | * "LastCB": An rcu_barrier_callback() invoked the last callback. |
674 | * "Inc2": rcu_barrier_callback() piggyback check counter incremented. | 674 | * "Inc2": _rcu_barrier() piggyback check counter incremented. |
675 | * The "cpu" argument is the CPU or -1 if meaningless, the "cnt" argument | 675 | * The "cpu" argument is the CPU or -1 if meaningless, the "cnt" argument |
676 | * is the count of remaining callbacks, and "done" is the piggybacking count. | 676 | * is the count of remaining callbacks, and "done" is the piggybacking count. |
677 | */ | 677 | */ |
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 133e47223095..9815447d22e0 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c | |||
@@ -3299,11 +3299,16 @@ static void _rcu_barrier(struct rcu_state *rsp) | |||
3299 | continue; | 3299 | continue; |
3300 | rdp = per_cpu_ptr(rsp->rda, cpu); | 3300 | rdp = per_cpu_ptr(rsp->rda, cpu); |
3301 | if (rcu_is_nocb_cpu(cpu)) { | 3301 | if (rcu_is_nocb_cpu(cpu)) { |
3302 | _rcu_barrier_trace(rsp, "OnlineNoCB", cpu, | 3302 | if (!rcu_nocb_cpu_needs_barrier(rsp, cpu)) { |
3303 | rsp->n_barrier_done); | 3303 | _rcu_barrier_trace(rsp, "OfflineNoCB", cpu, |
3304 | atomic_inc(&rsp->barrier_cpu_count); | 3304 | rsp->n_barrier_done); |
3305 | __call_rcu(&rdp->barrier_head, rcu_barrier_callback, | 3305 | } else { |
3306 | rsp, cpu, 0); | 3306 | _rcu_barrier_trace(rsp, "OnlineNoCB", cpu, |
3307 | rsp->n_barrier_done); | ||
3308 | atomic_inc(&rsp->barrier_cpu_count); | ||
3309 | __call_rcu(&rdp->barrier_head, | ||
3310 | rcu_barrier_callback, rsp, cpu, 0); | ||
3311 | } | ||
3307 | } else if (ACCESS_ONCE(rdp->qlen)) { | 3312 | } else if (ACCESS_ONCE(rdp->qlen)) { |
3308 | _rcu_barrier_trace(rsp, "OnlineQ", cpu, | 3313 | _rcu_barrier_trace(rsp, "OnlineQ", cpu, |
3309 | rsp->n_barrier_done); | 3314 | rsp->n_barrier_done); |
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index d03764652d91..bbdc45d8d74f 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h | |||
@@ -587,6 +587,7 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu); | |||
587 | static void print_cpu_stall_info_end(void); | 587 | static void print_cpu_stall_info_end(void); |
588 | static void zero_cpu_stall_ticks(struct rcu_data *rdp); | 588 | static void zero_cpu_stall_ticks(struct rcu_data *rdp); |
589 | static void increment_cpu_stall_ticks(void); | 589 | static void increment_cpu_stall_ticks(void); |
590 | static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu); | ||
590 | static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq); | 591 | static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq); |
591 | static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp); | 592 | static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp); |
592 | static void rcu_init_one_nocb(struct rcu_node *rnp); | 593 | static void rcu_init_one_nocb(struct rcu_node *rnp); |
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 387dd4599344..c1d7f27bd38f 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h | |||
@@ -2050,6 +2050,33 @@ static void wake_nocb_leader(struct rcu_data *rdp, bool force) | |||
2050 | } | 2050 | } |
2051 | 2051 | ||
2052 | /* | 2052 | /* |
2053 | * Does the specified CPU need an RCU callback for the specified flavor | ||
2054 | * of rcu_barrier()? | ||
2055 | */ | ||
2056 | static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu) | ||
2057 | { | ||
2058 | struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); | ||
2059 | struct rcu_head *rhp; | ||
2060 | |||
2061 | /* No-CBs CPUs might have callbacks on any of three lists. */ | ||
2062 | rhp = ACCESS_ONCE(rdp->nocb_head); | ||
2063 | if (!rhp) | ||
2064 | rhp = ACCESS_ONCE(rdp->nocb_gp_head); | ||
2065 | if (!rhp) | ||
2066 | rhp = ACCESS_ONCE(rdp->nocb_follower_head); | ||
2067 | |||
2068 | /* Having no rcuo kthread but CBs after scheduler starts is bad! */ | ||
2069 | if (!ACCESS_ONCE(rdp->nocb_kthread) && rhp) { | ||
2070 | /* RCU callback enqueued before CPU first came online??? */ | ||
2071 | pr_err("RCU: Never-onlined no-CBs CPU %d has CB %p\n", | ||
2072 | cpu, rhp->func); | ||
2073 | WARN_ON_ONCE(1); | ||
2074 | } | ||
2075 | |||
2076 | return !!rhp; | ||
2077 | } | ||
2078 | |||
2079 | /* | ||
2053 | * Enqueue the specified string of rcu_head structures onto the specified | 2080 | * Enqueue the specified string of rcu_head structures onto the specified |
2054 | * CPU's no-CBs lists. The CPU is specified by rdp, the head of the | 2081 | * CPU's no-CBs lists. The CPU is specified by rdp, the head of the |
2055 | * string by rhp, and the tail of the string by rhtp. The non-lazy/lazy | 2082 | * string by rhp, and the tail of the string by rhtp. The non-lazy/lazy |
@@ -2642,6 +2669,12 @@ static bool init_nocb_callback_list(struct rcu_data *rdp) | |||
2642 | 2669 | ||
2643 | #else /* #ifdef CONFIG_RCU_NOCB_CPU */ | 2670 | #else /* #ifdef CONFIG_RCU_NOCB_CPU */ |
2644 | 2671 | ||
2672 | static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu) | ||
2673 | { | ||
2674 | WARN_ON_ONCE(1); /* Should be dead code. */ | ||
2675 | return false; | ||
2676 | } | ||
2677 | |||
2645 | static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) | 2678 | static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) |
2646 | { | 2679 | { |
2647 | } | 2680 | } |