diff options
Diffstat (limited to 'kernel/rcu/tree_plugin.h')
-rw-r--r-- | kernel/rcu/tree_plugin.h | 102 |
1 files changed, 89 insertions, 13 deletions
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 08a765232432..6e2ef4b2b920 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h | |||
@@ -204,6 +204,7 @@ static void rcu_preempt_note_context_switch(int cpu) | |||
204 | rdp = per_cpu_ptr(rcu_preempt_state.rda, cpu); | 204 | rdp = per_cpu_ptr(rcu_preempt_state.rda, cpu); |
205 | rnp = rdp->mynode; | 205 | rnp = rdp->mynode; |
206 | raw_spin_lock_irqsave(&rnp->lock, flags); | 206 | raw_spin_lock_irqsave(&rnp->lock, flags); |
207 | smp_mb__after_unlock_lock(); | ||
207 | t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED; | 208 | t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED; |
208 | t->rcu_blocked_node = rnp; | 209 | t->rcu_blocked_node = rnp; |
209 | 210 | ||
@@ -312,6 +313,7 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags) | |||
312 | mask = rnp->grpmask; | 313 | mask = rnp->grpmask; |
313 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ | 314 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ |
314 | raw_spin_lock(&rnp_p->lock); /* irqs already disabled. */ | 315 | raw_spin_lock(&rnp_p->lock); /* irqs already disabled. */ |
316 | smp_mb__after_unlock_lock(); | ||
315 | rcu_report_qs_rnp(mask, &rcu_preempt_state, rnp_p, flags); | 317 | rcu_report_qs_rnp(mask, &rcu_preempt_state, rnp_p, flags); |
316 | } | 318 | } |
317 | 319 | ||
@@ -361,10 +363,14 @@ void rcu_read_unlock_special(struct task_struct *t) | |||
361 | special = t->rcu_read_unlock_special; | 363 | special = t->rcu_read_unlock_special; |
362 | if (special & RCU_READ_UNLOCK_NEED_QS) { | 364 | if (special & RCU_READ_UNLOCK_NEED_QS) { |
363 | rcu_preempt_qs(smp_processor_id()); | 365 | rcu_preempt_qs(smp_processor_id()); |
366 | if (!t->rcu_read_unlock_special) { | ||
367 | local_irq_restore(flags); | ||
368 | return; | ||
369 | } | ||
364 | } | 370 | } |
365 | 371 | ||
366 | /* Hardware IRQ handlers cannot block. */ | 372 | /* Hardware IRQ handlers cannot block, complain if they get here. */ |
367 | if (in_irq() || in_serving_softirq()) { | 373 | if (WARN_ON_ONCE(in_irq() || in_serving_softirq())) { |
368 | local_irq_restore(flags); | 374 | local_irq_restore(flags); |
369 | return; | 375 | return; |
370 | } | 376 | } |
@@ -381,6 +387,7 @@ void rcu_read_unlock_special(struct task_struct *t) | |||
381 | for (;;) { | 387 | for (;;) { |
382 | rnp = t->rcu_blocked_node; | 388 | rnp = t->rcu_blocked_node; |
383 | raw_spin_lock(&rnp->lock); /* irqs already disabled. */ | 389 | raw_spin_lock(&rnp->lock); /* irqs already disabled. */ |
390 | smp_mb__after_unlock_lock(); | ||
384 | if (rnp == t->rcu_blocked_node) | 391 | if (rnp == t->rcu_blocked_node) |
385 | break; | 392 | break; |
386 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ | 393 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ |
@@ -605,6 +612,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, | |||
605 | while (!list_empty(lp)) { | 612 | while (!list_empty(lp)) { |
606 | t = list_entry(lp->next, typeof(*t), rcu_node_entry); | 613 | t = list_entry(lp->next, typeof(*t), rcu_node_entry); |
607 | raw_spin_lock(&rnp_root->lock); /* irqs already disabled */ | 614 | raw_spin_lock(&rnp_root->lock); /* irqs already disabled */ |
615 | smp_mb__after_unlock_lock(); | ||
608 | list_del(&t->rcu_node_entry); | 616 | list_del(&t->rcu_node_entry); |
609 | t->rcu_blocked_node = rnp_root; | 617 | t->rcu_blocked_node = rnp_root; |
610 | list_add(&t->rcu_node_entry, lp_root); | 618 | list_add(&t->rcu_node_entry, lp_root); |
@@ -629,6 +637,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, | |||
629 | * in this case. | 637 | * in this case. |
630 | */ | 638 | */ |
631 | raw_spin_lock(&rnp_root->lock); /* irqs already disabled */ | 639 | raw_spin_lock(&rnp_root->lock); /* irqs already disabled */ |
640 | smp_mb__after_unlock_lock(); | ||
632 | if (rnp_root->boost_tasks != NULL && | 641 | if (rnp_root->boost_tasks != NULL && |
633 | rnp_root->boost_tasks != rnp_root->gp_tasks && | 642 | rnp_root->boost_tasks != rnp_root->gp_tasks && |
634 | rnp_root->boost_tasks != rnp_root->exp_tasks) | 643 | rnp_root->boost_tasks != rnp_root->exp_tasks) |
@@ -772,6 +781,7 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp, | |||
772 | unsigned long mask; | 781 | unsigned long mask; |
773 | 782 | ||
774 | raw_spin_lock_irqsave(&rnp->lock, flags); | 783 | raw_spin_lock_irqsave(&rnp->lock, flags); |
784 | smp_mb__after_unlock_lock(); | ||
775 | for (;;) { | 785 | for (;;) { |
776 | if (!sync_rcu_preempt_exp_done(rnp)) { | 786 | if (!sync_rcu_preempt_exp_done(rnp)) { |
777 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 787 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
@@ -779,14 +789,17 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp, | |||
779 | } | 789 | } |
780 | if (rnp->parent == NULL) { | 790 | if (rnp->parent == NULL) { |
781 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 791 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
782 | if (wake) | 792 | if (wake) { |
793 | smp_mb(); /* EGP done before wake_up(). */ | ||
783 | wake_up(&sync_rcu_preempt_exp_wq); | 794 | wake_up(&sync_rcu_preempt_exp_wq); |
795 | } | ||
784 | break; | 796 | break; |
785 | } | 797 | } |
786 | mask = rnp->grpmask; | 798 | mask = rnp->grpmask; |
787 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled */ | 799 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled */ |
788 | rnp = rnp->parent; | 800 | rnp = rnp->parent; |
789 | raw_spin_lock(&rnp->lock); /* irqs already disabled */ | 801 | raw_spin_lock(&rnp->lock); /* irqs already disabled */ |
802 | smp_mb__after_unlock_lock(); | ||
790 | rnp->expmask &= ~mask; | 803 | rnp->expmask &= ~mask; |
791 | } | 804 | } |
792 | } | 805 | } |
@@ -806,6 +819,7 @@ sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp) | |||
806 | int must_wait = 0; | 819 | int must_wait = 0; |
807 | 820 | ||
808 | raw_spin_lock_irqsave(&rnp->lock, flags); | 821 | raw_spin_lock_irqsave(&rnp->lock, flags); |
822 | smp_mb__after_unlock_lock(); | ||
809 | if (list_empty(&rnp->blkd_tasks)) { | 823 | if (list_empty(&rnp->blkd_tasks)) { |
810 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 824 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
811 | } else { | 825 | } else { |
@@ -886,6 +900,7 @@ void synchronize_rcu_expedited(void) | |||
886 | /* Initialize ->expmask for all non-leaf rcu_node structures. */ | 900 | /* Initialize ->expmask for all non-leaf rcu_node structures. */ |
887 | rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) { | 901 | rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) { |
888 | raw_spin_lock_irqsave(&rnp->lock, flags); | 902 | raw_spin_lock_irqsave(&rnp->lock, flags); |
903 | smp_mb__after_unlock_lock(); | ||
889 | rnp->expmask = rnp->qsmaskinit; | 904 | rnp->expmask = rnp->qsmaskinit; |
890 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 905 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
891 | } | 906 | } |
@@ -1191,6 +1206,7 @@ static int rcu_boost(struct rcu_node *rnp) | |||
1191 | return 0; /* Nothing left to boost. */ | 1206 | return 0; /* Nothing left to boost. */ |
1192 | 1207 | ||
1193 | raw_spin_lock_irqsave(&rnp->lock, flags); | 1208 | raw_spin_lock_irqsave(&rnp->lock, flags); |
1209 | smp_mb__after_unlock_lock(); | ||
1194 | 1210 | ||
1195 | /* | 1211 | /* |
1196 | * Recheck under the lock: all tasks in need of boosting | 1212 | * Recheck under the lock: all tasks in need of boosting |
@@ -1377,6 +1393,7 @@ static int rcu_spawn_one_boost_kthread(struct rcu_state *rsp, | |||
1377 | if (IS_ERR(t)) | 1393 | if (IS_ERR(t)) |
1378 | return PTR_ERR(t); | 1394 | return PTR_ERR(t); |
1379 | raw_spin_lock_irqsave(&rnp->lock, flags); | 1395 | raw_spin_lock_irqsave(&rnp->lock, flags); |
1396 | smp_mb__after_unlock_lock(); | ||
1380 | rnp->boost_kthread_task = t; | 1397 | rnp->boost_kthread_task = t; |
1381 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 1398 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
1382 | sp.sched_priority = RCU_BOOST_PRIO; | 1399 | sp.sched_priority = RCU_BOOST_PRIO; |
@@ -1769,6 +1786,7 @@ static void rcu_prepare_for_idle(int cpu) | |||
1769 | continue; | 1786 | continue; |
1770 | rnp = rdp->mynode; | 1787 | rnp = rdp->mynode; |
1771 | raw_spin_lock(&rnp->lock); /* irqs already disabled. */ | 1788 | raw_spin_lock(&rnp->lock); /* irqs already disabled. */ |
1789 | smp_mb__after_unlock_lock(); | ||
1772 | rcu_accelerate_cbs(rsp, rnp, rdp); | 1790 | rcu_accelerate_cbs(rsp, rnp, rdp); |
1773 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ | 1791 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ |
1774 | } | 1792 | } |
@@ -1852,6 +1870,7 @@ static int rcu_oom_notify(struct notifier_block *self, | |||
1852 | 1870 | ||
1853 | /* Wait for callbacks from earlier instance to complete. */ | 1871 | /* Wait for callbacks from earlier instance to complete. */ |
1854 | wait_event(oom_callback_wq, atomic_read(&oom_callback_count) == 0); | 1872 | wait_event(oom_callback_wq, atomic_read(&oom_callback_count) == 0); |
1873 | smp_mb(); /* Ensure callback reuse happens after callback invocation. */ | ||
1855 | 1874 | ||
1856 | /* | 1875 | /* |
1857 | * Prevent premature wakeup: ensure that all increments happen | 1876 | * Prevent premature wakeup: ensure that all increments happen |
@@ -2101,7 +2120,8 @@ bool rcu_is_nocb_cpu(int cpu) | |||
2101 | static void __call_rcu_nocb_enqueue(struct rcu_data *rdp, | 2120 | static void __call_rcu_nocb_enqueue(struct rcu_data *rdp, |
2102 | struct rcu_head *rhp, | 2121 | struct rcu_head *rhp, |
2103 | struct rcu_head **rhtp, | 2122 | struct rcu_head **rhtp, |
2104 | int rhcount, int rhcount_lazy) | 2123 | int rhcount, int rhcount_lazy, |
2124 | unsigned long flags) | ||
2105 | { | 2125 | { |
2106 | int len; | 2126 | int len; |
2107 | struct rcu_head **old_rhpp; | 2127 | struct rcu_head **old_rhpp; |
@@ -2122,9 +2142,16 @@ static void __call_rcu_nocb_enqueue(struct rcu_data *rdp, | |||
2122 | } | 2142 | } |
2123 | len = atomic_long_read(&rdp->nocb_q_count); | 2143 | len = atomic_long_read(&rdp->nocb_q_count); |
2124 | if (old_rhpp == &rdp->nocb_head) { | 2144 | if (old_rhpp == &rdp->nocb_head) { |
2125 | wake_up(&rdp->nocb_wq); /* ... only if queue was empty ... */ | 2145 | if (!irqs_disabled_flags(flags)) { |
2146 | wake_up(&rdp->nocb_wq); /* ... if queue was empty ... */ | ||
2147 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, | ||
2148 | TPS("WakeEmpty")); | ||
2149 | } else { | ||
2150 | rdp->nocb_defer_wakeup = true; | ||
2151 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, | ||
2152 | TPS("WakeEmptyIsDeferred")); | ||
2153 | } | ||
2126 | rdp->qlen_last_fqs_check = 0; | 2154 | rdp->qlen_last_fqs_check = 0; |
2127 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeEmpty")); | ||
2128 | } else if (len > rdp->qlen_last_fqs_check + qhimark) { | 2155 | } else if (len > rdp->qlen_last_fqs_check + qhimark) { |
2129 | wake_up_process(t); /* ... or if many callbacks queued. */ | 2156 | wake_up_process(t); /* ... or if many callbacks queued. */ |
2130 | rdp->qlen_last_fqs_check = LONG_MAX / 2; | 2157 | rdp->qlen_last_fqs_check = LONG_MAX / 2; |
@@ -2145,12 +2172,12 @@ static void __call_rcu_nocb_enqueue(struct rcu_data *rdp, | |||
2145 | * "rcuo" kthread can find it. | 2172 | * "rcuo" kthread can find it. |
2146 | */ | 2173 | */ |
2147 | static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, | 2174 | static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, |
2148 | bool lazy) | 2175 | bool lazy, unsigned long flags) |
2149 | { | 2176 | { |
2150 | 2177 | ||
2151 | if (!rcu_is_nocb_cpu(rdp->cpu)) | 2178 | if (!rcu_is_nocb_cpu(rdp->cpu)) |
2152 | return 0; | 2179 | return 0; |
2153 | __call_rcu_nocb_enqueue(rdp, rhp, &rhp->next, 1, lazy); | 2180 | __call_rcu_nocb_enqueue(rdp, rhp, &rhp->next, 1, lazy, flags); |
2154 | if (__is_kfree_rcu_offset((unsigned long)rhp->func)) | 2181 | if (__is_kfree_rcu_offset((unsigned long)rhp->func)) |
2155 | trace_rcu_kfree_callback(rdp->rsp->name, rhp, | 2182 | trace_rcu_kfree_callback(rdp->rsp->name, rhp, |
2156 | (unsigned long)rhp->func, | 2183 | (unsigned long)rhp->func, |
@@ -2168,7 +2195,8 @@ static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, | |||
2168 | * not a no-CBs CPU. | 2195 | * not a no-CBs CPU. |
2169 | */ | 2196 | */ |
2170 | static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp, | 2197 | static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp, |
2171 | struct rcu_data *rdp) | 2198 | struct rcu_data *rdp, |
2199 | unsigned long flags) | ||
2172 | { | 2200 | { |
2173 | long ql = rsp->qlen; | 2201 | long ql = rsp->qlen; |
2174 | long qll = rsp->qlen_lazy; | 2202 | long qll = rsp->qlen_lazy; |
@@ -2182,14 +2210,14 @@ static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp, | |||
2182 | /* First, enqueue the donelist, if any. This preserves CB ordering. */ | 2210 | /* First, enqueue the donelist, if any. This preserves CB ordering. */ |
2183 | if (rsp->orphan_donelist != NULL) { | 2211 | if (rsp->orphan_donelist != NULL) { |
2184 | __call_rcu_nocb_enqueue(rdp, rsp->orphan_donelist, | 2212 | __call_rcu_nocb_enqueue(rdp, rsp->orphan_donelist, |
2185 | rsp->orphan_donetail, ql, qll); | 2213 | rsp->orphan_donetail, ql, qll, flags); |
2186 | ql = qll = 0; | 2214 | ql = qll = 0; |
2187 | rsp->orphan_donelist = NULL; | 2215 | rsp->orphan_donelist = NULL; |
2188 | rsp->orphan_donetail = &rsp->orphan_donelist; | 2216 | rsp->orphan_donetail = &rsp->orphan_donelist; |
2189 | } | 2217 | } |
2190 | if (rsp->orphan_nxtlist != NULL) { | 2218 | if (rsp->orphan_nxtlist != NULL) { |
2191 | __call_rcu_nocb_enqueue(rdp, rsp->orphan_nxtlist, | 2219 | __call_rcu_nocb_enqueue(rdp, rsp->orphan_nxtlist, |
2192 | rsp->orphan_nxttail, ql, qll); | 2220 | rsp->orphan_nxttail, ql, qll, flags); |
2193 | ql = qll = 0; | 2221 | ql = qll = 0; |
2194 | rsp->orphan_nxtlist = NULL; | 2222 | rsp->orphan_nxtlist = NULL; |
2195 | rsp->orphan_nxttail = &rsp->orphan_nxtlist; | 2223 | rsp->orphan_nxttail = &rsp->orphan_nxtlist; |
@@ -2209,6 +2237,7 @@ static void rcu_nocb_wait_gp(struct rcu_data *rdp) | |||
2209 | struct rcu_node *rnp = rdp->mynode; | 2237 | struct rcu_node *rnp = rdp->mynode; |
2210 | 2238 | ||
2211 | raw_spin_lock_irqsave(&rnp->lock, flags); | 2239 | raw_spin_lock_irqsave(&rnp->lock, flags); |
2240 | smp_mb__after_unlock_lock(); | ||
2212 | c = rcu_start_future_gp(rnp, rdp); | 2241 | c = rcu_start_future_gp(rnp, rdp); |
2213 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 2242 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
2214 | 2243 | ||
@@ -2250,6 +2279,7 @@ static int rcu_nocb_kthread(void *arg) | |||
2250 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, | 2279 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, |
2251 | TPS("Sleep")); | 2280 | TPS("Sleep")); |
2252 | wait_event_interruptible(rdp->nocb_wq, rdp->nocb_head); | 2281 | wait_event_interruptible(rdp->nocb_wq, rdp->nocb_head); |
2282 | /* Memory barrier provide by xchg() below. */ | ||
2253 | } else if (firsttime) { | 2283 | } else if (firsttime) { |
2254 | firsttime = 0; | 2284 | firsttime = 0; |
2255 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, | 2285 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, |
@@ -2310,6 +2340,22 @@ static int rcu_nocb_kthread(void *arg) | |||
2310 | return 0; | 2340 | return 0; |
2311 | } | 2341 | } |
2312 | 2342 | ||
2343 | /* Is a deferred wakeup of rcu_nocb_kthread() required? */ | ||
2344 | static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp) | ||
2345 | { | ||
2346 | return ACCESS_ONCE(rdp->nocb_defer_wakeup); | ||
2347 | } | ||
2348 | |||
2349 | /* Do a deferred wakeup of rcu_nocb_kthread(). */ | ||
2350 | static void do_nocb_deferred_wakeup(struct rcu_data *rdp) | ||
2351 | { | ||
2352 | if (!rcu_nocb_need_deferred_wakeup(rdp)) | ||
2353 | return; | ||
2354 | ACCESS_ONCE(rdp->nocb_defer_wakeup) = false; | ||
2355 | wake_up(&rdp->nocb_wq); | ||
2356 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("DeferredWakeEmpty")); | ||
2357 | } | ||
2358 | |||
2313 | /* Initialize per-rcu_data variables for no-CBs CPUs. */ | 2359 | /* Initialize per-rcu_data variables for no-CBs CPUs. */ |
2314 | static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp) | 2360 | static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp) |
2315 | { | 2361 | { |
@@ -2365,13 +2411,14 @@ static void rcu_init_one_nocb(struct rcu_node *rnp) | |||
2365 | } | 2411 | } |
2366 | 2412 | ||
2367 | static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, | 2413 | static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, |
2368 | bool lazy) | 2414 | bool lazy, unsigned long flags) |
2369 | { | 2415 | { |
2370 | return 0; | 2416 | return 0; |
2371 | } | 2417 | } |
2372 | 2418 | ||
2373 | static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp, | 2419 | static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp, |
2374 | struct rcu_data *rdp) | 2420 | struct rcu_data *rdp, |
2421 | unsigned long flags) | ||
2375 | { | 2422 | { |
2376 | return 0; | 2423 | return 0; |
2377 | } | 2424 | } |
@@ -2380,6 +2427,15 @@ static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp) | |||
2380 | { | 2427 | { |
2381 | } | 2428 | } |
2382 | 2429 | ||
2430 | static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp) | ||
2431 | { | ||
2432 | return false; | ||
2433 | } | ||
2434 | |||
2435 | static void do_nocb_deferred_wakeup(struct rcu_data *rdp) | ||
2436 | { | ||
2437 | } | ||
2438 | |||
2383 | static void __init rcu_spawn_nocb_kthreads(struct rcu_state *rsp) | 2439 | static void __init rcu_spawn_nocb_kthreads(struct rcu_state *rsp) |
2384 | { | 2440 | { |
2385 | } | 2441 | } |
@@ -2829,3 +2885,23 @@ static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp) | |||
2829 | } | 2885 | } |
2830 | 2886 | ||
2831 | #endif /* #else #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */ | 2887 | #endif /* #else #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */ |
2888 | |||
2889 | /* | ||
2890 | * Is this CPU a NO_HZ_FULL CPU that should ignore RCU so that the | ||
2891 | * grace-period kthread will do force_quiescent_state() processing? | ||
2892 | * The idea is to avoid waking up RCU core processing on such a | ||
2893 | * CPU unless the grace period has extended for too long. | ||
2894 | * | ||
2895 | * This code relies on the fact that all NO_HZ_FULL CPUs are also | ||
2896 | * CONFIG_RCU_NOCB_CPUs. | ||
2897 | */ | ||
2898 | static bool rcu_nohz_full_cpu(struct rcu_state *rsp) | ||
2899 | { | ||
2900 | #ifdef CONFIG_NO_HZ_FULL | ||
2901 | if (tick_nohz_full_cpu(smp_processor_id()) && | ||
2902 | (!rcu_gp_in_progress(rsp) || | ||
2903 | ULONG_CMP_LT(jiffies, ACCESS_ONCE(rsp->gp_start) + HZ))) | ||
2904 | return 1; | ||
2905 | #endif /* #ifdef CONFIG_NO_HZ_FULL */ | ||
2906 | return 0; | ||
2907 | } | ||