diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-04 18:55:08 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-04 18:55:08 -0400 |
| commit | 5bda4f638f36ef4c4e3b1397b02affc3db94356e (patch) | |
| tree | d1bde148cde9981c31941382b2076084c7f5796c /kernel/rcu | |
| parent | a45c657f28f82b056173d1afc2e7ed1f1f68829f (diff) | |
| parent | 01c9db827146ce321562a992a5dbc1a49b1a99ce (diff) | |
Merge branch 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull RCU changes from Ingo Molar:
"The main changes:
- torture-test updates
- callback-offloading changes
- maintainership changes
- update RCU documentation
- miscellaneous fixes"
* 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (32 commits)
rcu: Allow for NULL tick_nohz_full_mask when nohz_full= missing
rcu: Fix a sparse warning in rcu_report_unblock_qs_rnp()
rcu: Fix a sparse warning in rcu_initiate_boost()
rcu: Fix __rcu_reclaim() to use true/false for bool
rcu: Remove CONFIG_PROVE_RCU_DELAY
rcu: Use __this_cpu_read() instead of per_cpu_ptr()
rcu: Don't use NMIs to dump other CPUs' stacks
rcu: Bind grace-period kthreads to non-NO_HZ_FULL CPUs
rcu: Simplify priority boosting by putting rt_mutex in rcu_node
rcu: Check both root and current rcu_node when setting up future grace period
rcu: Allow post-unlock reference for rt_mutex
rcu: Loosen __call_rcu()'s rcu_head alignment constraint
rcu: Eliminate read-modify-write ACCESS_ONCE() calls
rcu: Remove redundant ACCESS_ONCE() from tick_do_timer_cpu
rcu: Make rcu node arrays static const char * const
signal: Explain local_irq_save() call
rcu: Handle obsolete references to TINY_PREEMPT_RCU
rcu: Document deadlock-avoidance information for rcu_read_unlock()
scripts: Teach get_maintainer.pl about the new "R:" tag
rcu: Update rcu torture maintainership filename patterns
...
Diffstat (limited to 'kernel/rcu')
| -rw-r--r-- | kernel/rcu/rcu.h | 8 | ||||
| -rw-r--r-- | kernel/rcu/srcu.c | 4 | ||||
| -rw-r--r-- | kernel/rcu/tree.c | 59 | ||||
| -rw-r--r-- | kernel/rcu/tree.h | 36 | ||||
| -rw-r--r-- | kernel/rcu/tree_plugin.h | 302 | ||||
| -rw-r--r-- | kernel/rcu/update.c | 3 |
6 files changed, 314 insertions, 98 deletions
diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h index bfda2726ca45..ff1a6de62f17 100644 --- a/kernel/rcu/rcu.h +++ b/kernel/rcu/rcu.h | |||
| @@ -99,6 +99,10 @@ static inline void debug_rcu_head_unqueue(struct rcu_head *head) | |||
| 99 | 99 | ||
| 100 | void kfree(const void *); | 100 | void kfree(const void *); |
| 101 | 101 | ||
| 102 | /* | ||
| 103 | * Reclaim the specified callback, either by invoking it (non-lazy case) | ||
| 104 | * or freeing it directly (lazy case). Return true if lazy, false otherwise. | ||
| 105 | */ | ||
| 102 | static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head) | 106 | static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head) |
| 103 | { | 107 | { |
| 104 | unsigned long offset = (unsigned long)head->func; | 108 | unsigned long offset = (unsigned long)head->func; |
| @@ -108,12 +112,12 @@ static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head) | |||
| 108 | RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset)); | 112 | RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset)); |
| 109 | kfree((void *)head - offset); | 113 | kfree((void *)head - offset); |
| 110 | rcu_lock_release(&rcu_callback_map); | 114 | rcu_lock_release(&rcu_callback_map); |
| 111 | return 1; | 115 | return true; |
| 112 | } else { | 116 | } else { |
| 113 | RCU_TRACE(trace_rcu_invoke_callback(rn, head)); | 117 | RCU_TRACE(trace_rcu_invoke_callback(rn, head)); |
| 114 | head->func(head); | 118 | head->func(head); |
| 115 | rcu_lock_release(&rcu_callback_map); | 119 | rcu_lock_release(&rcu_callback_map); |
| 116 | return 0; | 120 | return false; |
| 117 | } | 121 | } |
| 118 | } | 122 | } |
| 119 | 123 | ||
diff --git a/kernel/rcu/srcu.c b/kernel/rcu/srcu.c index c639556f3fa0..e037f3eb2f7b 100644 --- a/kernel/rcu/srcu.c +++ b/kernel/rcu/srcu.c | |||
| @@ -298,9 +298,9 @@ int __srcu_read_lock(struct srcu_struct *sp) | |||
| 298 | 298 | ||
| 299 | idx = ACCESS_ONCE(sp->completed) & 0x1; | 299 | idx = ACCESS_ONCE(sp->completed) & 0x1; |
| 300 | preempt_disable(); | 300 | preempt_disable(); |
| 301 | ACCESS_ONCE(this_cpu_ptr(sp->per_cpu_ref)->c[idx]) += 1; | 301 | __this_cpu_inc(sp->per_cpu_ref->c[idx]); |
| 302 | smp_mb(); /* B */ /* Avoid leaking the critical section. */ | 302 | smp_mb(); /* B */ /* Avoid leaking the critical section. */ |
| 303 | ACCESS_ONCE(this_cpu_ptr(sp->per_cpu_ref)->seq[idx]) += 1; | 303 | __this_cpu_inc(sp->per_cpu_ref->seq[idx]); |
| 304 | preempt_enable(); | 304 | preempt_enable(); |
| 305 | return idx; | 305 | return idx; |
| 306 | } | 306 | } |
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 625d0b0cd75a..1b70cb6fbe3c 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c | |||
| @@ -1013,10 +1013,7 @@ static void record_gp_stall_check_time(struct rcu_state *rsp) | |||
| 1013 | } | 1013 | } |
| 1014 | 1014 | ||
| 1015 | /* | 1015 | /* |
| 1016 | * Dump stacks of all tasks running on stalled CPUs. This is a fallback | 1016 | * Dump stacks of all tasks running on stalled CPUs. |
| 1017 | * for architectures that do not implement trigger_all_cpu_backtrace(). | ||
| 1018 | * The NMI-triggered stack traces are more accurate because they are | ||
| 1019 | * printed by the target CPU. | ||
| 1020 | */ | 1017 | */ |
| 1021 | static void rcu_dump_cpu_stacks(struct rcu_state *rsp) | 1018 | static void rcu_dump_cpu_stacks(struct rcu_state *rsp) |
| 1022 | { | 1019 | { |
| @@ -1094,7 +1091,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp) | |||
| 1094 | (long)rsp->gpnum, (long)rsp->completed, totqlen); | 1091 | (long)rsp->gpnum, (long)rsp->completed, totqlen); |
| 1095 | if (ndetected == 0) | 1092 | if (ndetected == 0) |
| 1096 | pr_err("INFO: Stall ended before state dump start\n"); | 1093 | pr_err("INFO: Stall ended before state dump start\n"); |
| 1097 | else if (!trigger_all_cpu_backtrace()) | 1094 | else |
| 1098 | rcu_dump_cpu_stacks(rsp); | 1095 | rcu_dump_cpu_stacks(rsp); |
| 1099 | 1096 | ||
| 1100 | /* Complain about tasks blocking the grace period. */ | 1097 | /* Complain about tasks blocking the grace period. */ |
| @@ -1125,8 +1122,7 @@ static void print_cpu_stall(struct rcu_state *rsp) | |||
| 1125 | pr_cont(" (t=%lu jiffies g=%ld c=%ld q=%lu)\n", | 1122 | pr_cont(" (t=%lu jiffies g=%ld c=%ld q=%lu)\n", |
| 1126 | jiffies - rsp->gp_start, | 1123 | jiffies - rsp->gp_start, |
| 1127 | (long)rsp->gpnum, (long)rsp->completed, totqlen); | 1124 | (long)rsp->gpnum, (long)rsp->completed, totqlen); |
| 1128 | if (!trigger_all_cpu_backtrace()) | 1125 | rcu_dump_cpu_stacks(rsp); |
| 1129 | dump_stack(); | ||
| 1130 | 1126 | ||
| 1131 | raw_spin_lock_irqsave(&rnp->lock, flags); | 1127 | raw_spin_lock_irqsave(&rnp->lock, flags); |
| 1132 | if (ULONG_CMP_GE(jiffies, ACCESS_ONCE(rsp->jiffies_stall))) | 1128 | if (ULONG_CMP_GE(jiffies, ACCESS_ONCE(rsp->jiffies_stall))) |
| @@ -1305,10 +1301,16 @@ rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp, | |||
| 1305 | * believe that a grace period is in progress, then we must wait | 1301 | * believe that a grace period is in progress, then we must wait |
| 1306 | * for the one following, which is in "c". Because our request | 1302 | * for the one following, which is in "c". Because our request |
| 1307 | * will be noticed at the end of the current grace period, we don't | 1303 | * will be noticed at the end of the current grace period, we don't |
| 1308 | * need to explicitly start one. | 1304 | * need to explicitly start one. We only do the lockless check |
| 1305 | * of rnp_root's fields if the current rcu_node structure thinks | ||
| 1306 | * there is no grace period in flight, and because we hold rnp->lock, | ||
| 1307 | * the only possible change is when rnp_root's two fields are | ||
| 1308 | * equal, in which case rnp_root->gpnum might be concurrently | ||
| 1309 | * incremented. But that is OK, as it will just result in our | ||
| 1310 | * doing some extra useless work. | ||
| 1309 | */ | 1311 | */ |
| 1310 | if (rnp->gpnum != rnp->completed || | 1312 | if (rnp->gpnum != rnp->completed || |
| 1311 | ACCESS_ONCE(rnp->gpnum) != ACCESS_ONCE(rnp->completed)) { | 1313 | ACCESS_ONCE(rnp_root->gpnum) != ACCESS_ONCE(rnp_root->completed)) { |
| 1312 | rnp->need_future_gp[c & 0x1]++; | 1314 | rnp->need_future_gp[c & 0x1]++; |
| 1313 | trace_rcu_future_gp(rnp, rdp, c, TPS("Startedleaf")); | 1315 | trace_rcu_future_gp(rnp, rdp, c, TPS("Startedleaf")); |
| 1314 | goto out; | 1316 | goto out; |
| @@ -1645,11 +1647,6 @@ static int rcu_gp_init(struct rcu_state *rsp) | |||
| 1645 | rnp->level, rnp->grplo, | 1647 | rnp->level, rnp->grplo, |
| 1646 | rnp->grphi, rnp->qsmask); | 1648 | rnp->grphi, rnp->qsmask); |
| 1647 | raw_spin_unlock_irq(&rnp->lock); | 1649 | raw_spin_unlock_irq(&rnp->lock); |
| 1648 | #ifdef CONFIG_PROVE_RCU_DELAY | ||
| 1649 | if ((prandom_u32() % (rcu_num_nodes + 1)) == 0 && | ||
| 1650 | system_state == SYSTEM_RUNNING) | ||
| 1651 | udelay(200); | ||
| 1652 | #endif /* #ifdef CONFIG_PROVE_RCU_DELAY */ | ||
| 1653 | cond_resched(); | 1650 | cond_resched(); |
| 1654 | } | 1651 | } |
| 1655 | 1652 | ||
| @@ -2347,7 +2344,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) | |||
| 2347 | } | 2344 | } |
| 2348 | smp_mb(); /* List handling before counting for rcu_barrier(). */ | 2345 | smp_mb(); /* List handling before counting for rcu_barrier(). */ |
| 2349 | rdp->qlen_lazy -= count_lazy; | 2346 | rdp->qlen_lazy -= count_lazy; |
| 2350 | ACCESS_ONCE(rdp->qlen) -= count; | 2347 | ACCESS_ONCE(rdp->qlen) = rdp->qlen - count; |
| 2351 | rdp->n_cbs_invoked += count; | 2348 | rdp->n_cbs_invoked += count; |
| 2352 | 2349 | ||
| 2353 | /* Reinstate batch limit if we have worked down the excess. */ | 2350 | /* Reinstate batch limit if we have worked down the excess. */ |
| @@ -2485,14 +2482,14 @@ static void force_quiescent_state(struct rcu_state *rsp) | |||
| 2485 | struct rcu_node *rnp_old = NULL; | 2482 | struct rcu_node *rnp_old = NULL; |
| 2486 | 2483 | ||
| 2487 | /* Funnel through hierarchy to reduce memory contention. */ | 2484 | /* Funnel through hierarchy to reduce memory contention. */ |
| 2488 | rnp = per_cpu_ptr(rsp->rda, raw_smp_processor_id())->mynode; | 2485 | rnp = __this_cpu_read(rsp->rda->mynode); |
| 2489 | for (; rnp != NULL; rnp = rnp->parent) { | 2486 | for (; rnp != NULL; rnp = rnp->parent) { |
| 2490 | ret = (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) || | 2487 | ret = (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) || |
| 2491 | !raw_spin_trylock(&rnp->fqslock); | 2488 | !raw_spin_trylock(&rnp->fqslock); |
| 2492 | if (rnp_old != NULL) | 2489 | if (rnp_old != NULL) |
| 2493 | raw_spin_unlock(&rnp_old->fqslock); | 2490 | raw_spin_unlock(&rnp_old->fqslock); |
| 2494 | if (ret) { | 2491 | if (ret) { |
| 2495 | ACCESS_ONCE(rsp->n_force_qs_lh)++; | 2492 | rsp->n_force_qs_lh++; |
| 2496 | return; | 2493 | return; |
| 2497 | } | 2494 | } |
| 2498 | rnp_old = rnp; | 2495 | rnp_old = rnp; |
| @@ -2504,7 +2501,7 @@ static void force_quiescent_state(struct rcu_state *rsp) | |||
| 2504 | smp_mb__after_unlock_lock(); | 2501 | smp_mb__after_unlock_lock(); |
| 2505 | raw_spin_unlock(&rnp_old->fqslock); | 2502 | raw_spin_unlock(&rnp_old->fqslock); |
| 2506 | if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) { | 2503 | if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) { |
| 2507 | ACCESS_ONCE(rsp->n_force_qs_lh)++; | 2504 | rsp->n_force_qs_lh++; |
| 2508 | raw_spin_unlock_irqrestore(&rnp_old->lock, flags); | 2505 | raw_spin_unlock_irqrestore(&rnp_old->lock, flags); |
| 2509 | return; /* Someone beat us to it. */ | 2506 | return; /* Someone beat us to it. */ |
| 2510 | } | 2507 | } |
| @@ -2662,7 +2659,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), | |||
| 2662 | unsigned long flags; | 2659 | unsigned long flags; |
| 2663 | struct rcu_data *rdp; | 2660 | struct rcu_data *rdp; |
