diff options
Diffstat (limited to 'kernel/rcu/update.c')
| -rw-r--r-- | kernel/rcu/update.c | 72 |
1 files changed, 63 insertions, 9 deletions
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index e0d31a345ee6..1f133350da01 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c | |||
| @@ -62,6 +62,63 @@ MODULE_ALIAS("rcupdate"); | |||
| 62 | 62 | ||
| 63 | module_param(rcu_expedited, int, 0); | 63 | module_param(rcu_expedited, int, 0); |
| 64 | 64 | ||
| 65 | #ifndef CONFIG_TINY_RCU | ||
| 66 | |||
| 67 | static atomic_t rcu_expedited_nesting = | ||
| 68 | ATOMIC_INIT(IS_ENABLED(CONFIG_RCU_EXPEDITE_BOOT) ? 1 : 0); | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Should normal grace-period primitives be expedited? Intended for | ||
| 72 | * use within RCU. Note that this function takes the rcu_expedited | ||
| 73 | * sysfs/boot variable into account as well as the rcu_expedite_gp() | ||
| 74 | * nesting. So looping on rcu_unexpedite_gp() until rcu_gp_is_expedited() | ||
| 75 | * returns false is a -really- bad idea. | ||
| 76 | */ | ||
| 77 | bool rcu_gp_is_expedited(void) | ||
| 78 | { | ||
| 79 | return rcu_expedited || atomic_read(&rcu_expedited_nesting); | ||
| 80 | } | ||
| 81 | EXPORT_SYMBOL_GPL(rcu_gp_is_expedited); | ||
| 82 | |||
| 83 | /** | ||
| 84 | * rcu_expedite_gp - Expedite future RCU grace periods | ||
| 85 | * | ||
| 86 | * After a call to this function, future calls to synchronize_rcu() and | ||
| 87 | * friends act as the corresponding synchronize_rcu_expedited() function | ||
| 88 | * had instead been called. | ||
| 89 | */ | ||
| 90 | void rcu_expedite_gp(void) | ||
| 91 | { | ||
| 92 | atomic_inc(&rcu_expedited_nesting); | ||
| 93 | } | ||
| 94 | EXPORT_SYMBOL_GPL(rcu_expedite_gp); | ||
| 95 | |||
| 96 | /** | ||
| 97 | * rcu_unexpedite_gp - Cancel prior rcu_expedite_gp() invocation | ||
| 98 | * | ||
| 99 | * Undo a prior call to rcu_expedite_gp(). If all prior calls to | ||
| 100 | * rcu_expedite_gp() are undone by a subsequent call to rcu_unexpedite_gp(), | ||
| 101 | * and if the rcu_expedited sysfs/boot parameter is not set, then all | ||
| 102 | * subsequent calls to synchronize_rcu() and friends will return to | ||
| 103 | * their normal non-expedited behavior. | ||
| 104 | */ | ||
| 105 | void rcu_unexpedite_gp(void) | ||
| 106 | { | ||
| 107 | atomic_dec(&rcu_expedited_nesting); | ||
| 108 | } | ||
| 109 | EXPORT_SYMBOL_GPL(rcu_unexpedite_gp); | ||
| 110 | |||
| 111 | #endif /* #ifndef CONFIG_TINY_RCU */ | ||
| 112 | |||
| 113 | /* | ||
| 114 | * Inform RCU of the end of the in-kernel boot sequence. | ||
| 115 | */ | ||
| 116 | void rcu_end_inkernel_boot(void) | ||
| 117 | { | ||
| 118 | if (IS_ENABLED(CONFIG_RCU_EXPEDITE_BOOT)) | ||
| 119 | rcu_unexpedite_gp(); | ||
| 120 | } | ||
| 121 | |||
| 65 | #ifdef CONFIG_PREEMPT_RCU | 122 | #ifdef CONFIG_PREEMPT_RCU |
| 66 | 123 | ||
| 67 | /* | 124 | /* |
| @@ -199,16 +256,13 @@ EXPORT_SYMBOL_GPL(rcu_read_lock_bh_held); | |||
| 199 | 256 | ||
| 200 | #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ | 257 | #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ |
| 201 | 258 | ||
| 202 | struct rcu_synchronize { | 259 | /** |
| 203 | struct rcu_head head; | 260 | * wakeme_after_rcu() - Callback function to awaken a task after grace period |
| 204 | struct completion completion; | 261 | * @head: Pointer to rcu_head member within rcu_synchronize structure |
| 205 | }; | 262 | * |
| 206 | 263 | * Awaken the corresponding task now that a grace period has elapsed. | |
| 207 | /* | ||
| 208 | * Awaken the corresponding synchronize_rcu() instance now that a | ||
| 209 | * grace period has elapsed. | ||
| 210 | */ | 264 | */ |
| 211 | static void wakeme_after_rcu(struct rcu_head *head) | 265 | void wakeme_after_rcu(struct rcu_head *head) |
| 212 | { | 266 | { |
| 213 | struct rcu_synchronize *rcu; | 267 | struct rcu_synchronize *rcu; |
| 214 | 268 | ||
