1 // SPDX-License-Identifier: GPL-2.0+ << 2 /* 1 /* 3 * RCU-based infrastructure for lightweight re 2 * RCU-based infrastructure for lightweight reader-writer locking 4 * 3 * >> 4 * This program is free software; you can redistribute it and/or modify >> 5 * it under the terms of the GNU General Public License as published by >> 6 * the Free Software Foundation; either version 2 of the License, or >> 7 * (at your option) any later version. >> 8 * >> 9 * This program is distributed in the hope that it will be useful, >> 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of >> 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> 12 * GNU General Public License for more details. >> 13 * >> 14 * You should have received a copy of the GNU General Public License >> 15 * along with this program; if not, you can access it online at >> 16 * http://www.gnu.org/licenses/gpl-2.0.html. >> 17 * 5 * Copyright (c) 2015, Red Hat, Inc. 18 * Copyright (c) 2015, Red Hat, Inc. 6 * 19 * 7 * Author: Oleg Nesterov <oleg@redhat.com> 20 * Author: Oleg Nesterov <oleg@redhat.com> 8 */ 21 */ 9 22 10 #include <linux/rcu_sync.h> 23 #include <linux/rcu_sync.h> 11 #include <linux/sched.h> 24 #include <linux/sched.h> 12 25 13 enum { GP_IDLE = 0, GP_ENTER, GP_PASSED, GP_EX !! 26 #ifdef CONFIG_PROVE_RCU >> 27 #define __INIT_HELD(func) .held = func, >> 28 #else >> 29 #define __INIT_HELD(func) >> 30 #endif >> 31 >> 32 static const struct { >> 33 void (*sync)(void); >> 34 void (*call)(struct rcu_head *, void (*)(struct rcu_head *)); >> 35 void (*wait)(void); >> 36 #ifdef CONFIG_PROVE_RCU >> 37 int (*held)(void); >> 38 #endif >> 39 } gp_ops[] = { >> 40 [RCU_SYNC] = { >> 41 .sync = synchronize_rcu, >> 42 .call = call_rcu, >> 43 .wait = rcu_barrier, >> 44 __INIT_HELD(rcu_read_lock_held) >> 45 }, >> 46 [RCU_SCHED_SYNC] = { >> 47 .sync = synchronize_sched, >> 48 .call = call_rcu_sched, >> 49 .wait = rcu_barrier_sched, >> 50 __INIT_HELD(rcu_read_lock_sched_held) >> 51 }, >> 52 [RCU_BH_SYNC] = { >> 53 .sync = synchronize_rcu_bh, >> 54 .call = call_rcu_bh, >> 55 .wait = rcu_barrier_bh, >> 56 __INIT_HELD(rcu_read_lock_bh_held) >> 57 }, >> 58 }; >> 59 >> 60 enum { GP_IDLE = 0, GP_PENDING, GP_PASSED }; >> 61 enum { CB_IDLE = 0, CB_PENDING, CB_REPLAY }; 14 62 15 #define rss_lock gp_wait.lock 63 #define rss_lock gp_wait.lock 16 64 >> 65 #ifdef CONFIG_PROVE_RCU >> 66 void rcu_sync_lockdep_assert(struct rcu_sync *rsp) >> 67 { >> 68 RCU_LOCKDEP_WARN(!gp_ops[rsp->gp_type].held(), >> 69 "suspicious rcu_sync_is_idle() usage"); >> 70 } >> 71 >> 72 EXPORT_SYMBOL_GPL(rcu_sync_lockdep_assert); >> 73 #endif >> 74 17 /** 75 /** 18 * rcu_sync_init() - Initialize an rcu_sync st 76 * rcu_sync_init() - Initialize an rcu_sync structure 19 * @rsp: Pointer to rcu_sync structure to be i 77 * @rsp: Pointer to rcu_sync structure to be initialized >> 78 * @type: Flavor of RCU with which to synchronize rcu_sync structure 20 */ 79 */ 21 void rcu_sync_init(struct rcu_sync *rsp) !! 80 void rcu_sync_init(struct rcu_sync *rsp, enum rcu_sync_type type) 22 { 81 { 23 memset(rsp, 0, sizeof(*rsp)); 82 memset(rsp, 0, sizeof(*rsp)); 24 init_waitqueue_head(&rsp->gp_wait); 83 init_waitqueue_head(&rsp->gp_wait); >> 84 rsp->gp_type = type; 25 } 85 } 26 86 27 static void rcu_sync_func(struct rcu_head *rhp !! 87 /** >> 88 * rcu_sync_enter_start - Force readers onto slow path for multiple updates >> 89 * @rsp: Pointer to rcu_sync structure to use for synchronization >> 90 * >> 91 * Must be called after rcu_sync_init() and before first use. >> 92 * >> 93 * Ensures rcu_sync_is_idle() returns false and rcu_sync_{enter,exit}() >> 94 * pairs turn into NO-OPs. >> 95 */ >> 96 void rcu_sync_enter_start(struct rcu_sync *rsp) >> 97 { >> 98 rsp->gp_count++; >> 99 rsp->gp_state = GP_PASSED; >> 100 } 28 101 29 static void rcu_sync_call(struct rcu_sync *rsp !! 102 /** >> 103 * rcu_sync_enter() - Force readers onto slowpath >> 104 * @rsp: Pointer to rcu_sync structure to use for synchronization >> 105 * >> 106 * This function is used by updaters who need readers to make use of >> 107 * a slowpath during the update. After this function returns, all >> 108 * subsequent calls to rcu_sync_is_idle() will return false, which >> 109 * tells readers to stay off their fastpaths. A later call to >> 110 * rcu_sync_exit() re-enables reader slowpaths. >> 111 * >> 112 * When called in isolation, rcu_sync_enter() must wait for a grace >> 113 * period, however, closely spaced calls to rcu_sync_enter() can >> 114 * optimize away the grace-period wait via a state machine implemented >> 115 * by rcu_sync_enter(), rcu_sync_exit(), and rcu_sync_func(). >> 116 */ >> 117 void rcu_sync_enter(struct rcu_sync *rsp) 30 { 118 { 31 call_rcu_hurry(&rsp->cb_head, rcu_sync !! 119 bool need_wait, need_sync; >> 120 >> 121 spin_lock_irq(&rsp->rss_lock); >> 122 need_wait = rsp->gp_count++; >> 123 need_sync = rsp->gp_state == GP_IDLE; >> 124 if (need_sync) >> 125 rsp->gp_state = GP_PENDING; >> 126 spin_unlock_irq(&rsp->rss_lock); >> 127 >> 128 BUG_ON(need_wait && need_sync); >> 129 >> 130 if (need_sync) { >> 131 gp_ops[rsp->gp_type].sync(); >> 132 rsp->gp_state = GP_PASSED; >> 133 wake_up_all(&rsp->gp_wait); >> 134 } else if (need_wait) { >> 135 wait_event(rsp->gp_wait, rsp->gp_state == GP_PASSED); >> 136 } else { >> 137 /* >> 138 * Possible when there's a pending CB from a rcu_sync_exit(). >> 139 * Nobody has yet been allowed the 'fast' path and thus we can >> 140 * avoid doing any sync(). The callback will get 'dropped'. >> 141 */ >> 142 BUG_ON(rsp->gp_state != GP_PASSED); >> 143 } 32 } 144 } 33 145 34 /** 146 /** 35 * rcu_sync_func() - Callback function managin 147 * rcu_sync_func() - Callback function managing reader access to fastpath 36 * @rhp: Pointer to rcu_head in rcu_sync struc 148 * @rhp: Pointer to rcu_head in rcu_sync structure to use for synchronization 37 * 149 * 38 * This function is passed to call_rcu() funct !! 150 * This function is passed to one of the call_rcu() functions by 39 * rcu_sync_exit(), so that it is invoked afte 151 * rcu_sync_exit(), so that it is invoked after a grace period following the 40 * that invocation of enter/exit. !! 152 * that invocation of rcu_sync_exit(). It takes action based on events that 41 * << 42 * If it is called by rcu_sync_enter() it sign << 43 * switched onto slow path. << 44 * << 45 * If it is called by rcu_sync_exit() it takes << 46 * have taken place in the meantime, so that c 153 * have taken place in the meantime, so that closely spaced rcu_sync_enter() 47 * and rcu_sync_exit() pairs need not wait for 154 * and rcu_sync_exit() pairs need not wait for a grace period. 48 * 155 * 49 * If another rcu_sync_enter() is invoked befo 156 * If another rcu_sync_enter() is invoked before the grace period 50 * ended, reset state to allow the next rcu_sy 157 * ended, reset state to allow the next rcu_sync_exit() to let the 51 * readers back onto their fastpaths (after a 158 * readers back onto their fastpaths (after a grace period). If both 52 * another rcu_sync_enter() and its matching r 159 * another rcu_sync_enter() and its matching rcu_sync_exit() are invoked 53 * before the grace period ended, re-invoke ca 160 * before the grace period ended, re-invoke call_rcu() on behalf of that 54 * rcu_sync_exit(). Otherwise, set all state 161 * rcu_sync_exit(). Otherwise, set all state back to idle so that readers 55 * can again use their fastpaths. 162 * can again use their fastpaths. 56 */ 163 */ 57 static void rcu_sync_func(struct rcu_head *rhp 164 static void rcu_sync_func(struct rcu_head *rhp) 58 { 165 { 59 struct rcu_sync *rsp = container_of(rh 166 struct rcu_sync *rsp = container_of(rhp, struct rcu_sync, cb_head); 60 unsigned long flags; 167 unsigned long flags; 61 168 62 WARN_ON_ONCE(READ_ONCE(rsp->gp_state) !! 169 BUG_ON(rsp->gp_state != GP_PASSED); 63 WARN_ON_ONCE(READ_ONCE(rsp->gp_state) !! 170 BUG_ON(rsp->cb_state == CB_IDLE); 64 171 65 spin_lock_irqsave(&rsp->rss_lock, flag 172 spin_lock_irqsave(&rsp->rss_lock, flags); 66 if (rsp->gp_count) { 173 if (rsp->gp_count) { 67 /* 174 /* 68 * We're at least a GP after t !! 175 * A new rcu_sync_begin() has happened; drop the callback. 69 */ 176 */ 70 WRITE_ONCE(rsp->gp_state, GP_P !! 177 rsp->cb_state = CB_IDLE; 71 wake_up_locked(&rsp->gp_wait); !! 178 } else if (rsp->cb_state == CB_REPLAY) { 72 } else if (rsp->gp_state == GP_REPLAY) << 73 /* 179 /* 74 * A new rcu_sync_exit() has h !! 180 * A new rcu_sync_exit() has happened; requeue the callback 75 * catch a later GP. !! 181 * to catch a later GP. 76 */ 182 */ 77 WRITE_ONCE(rsp->gp_state, GP_E !! 183 rsp->cb_state = CB_PENDING; 78 rcu_sync_call(rsp); !! 184 gp_ops[rsp->gp_type].call(&rsp->cb_head, rcu_sync_func); 79 } else { 185 } else { 80 /* 186 /* 81 * We're at least a GP after t !! 187 * We're at least a GP after rcu_sync_exit(); eveybody will now 82 * will now have observed the !! 188 * have observed the write side critical section. Let 'em rip!. 83 * Let 'em rip! << 84 */ 189 */ 85 WRITE_ONCE(rsp->gp_state, GP_I !! 190 rsp->cb_state = CB_IDLE; >> 191 rsp->gp_state = GP_IDLE; 86 } 192 } 87 spin_unlock_irqrestore(&rsp->rss_lock, 193 spin_unlock_irqrestore(&rsp->rss_lock, flags); 88 } 194 } 89 195 90 /** 196 /** 91 * rcu_sync_enter() - Force readers onto slowp !! 197 * rcu_sync_exit() - Allow readers back onto fast patch after grace period 92 * @rsp: Pointer to rcu_sync structure to use << 93 * << 94 * This function is used by updaters who need << 95 * a slowpath during the update. After this f << 96 * subsequent calls to rcu_sync_is_idle() will << 97 * tells readers to stay off their fastpaths. << 98 * rcu_sync_exit() re-enables reader fastpaths << 99 * << 100 * When called in isolation, rcu_sync_enter() << 101 * period, however, closely spaced calls to rc << 102 * optimize away the grace-period wait via a s << 103 * by rcu_sync_enter(), rcu_sync_exit(), and r << 104 */ << 105 void rcu_sync_enter(struct rcu_sync *rsp) << 106 { << 107 int gp_state; << 108 << 109 spin_lock_irq(&rsp->rss_lock); << 110 gp_state = rsp->gp_state; << 111 if (gp_state == GP_IDLE) { << 112 WRITE_ONCE(rsp->gp_state, GP_E << 113 WARN_ON_ONCE(rsp->gp_count); << 114 /* << 115 * Note that we could simply d << 116 * avoid the "if (gp_state == << 117 * << 118 * However, synchronize_rcu() << 119 * or rcu_blocking_is_gp() is << 120 * << 121 * Another reason is that we c << 122 * we are called at early boot << 123 */ << 124 } << 125 rsp->gp_count++; << 126 spin_unlock_irq(&rsp->rss_lock); << 127 << 128 if (gp_state == GP_IDLE) { << 129 /* << 130 * See the comment above, this << 131 * call_rcu(rcu_sync_func) whi << 132 */ << 133 synchronize_rcu(); << 134 rcu_sync_func(&rsp->cb_head); << 135 /* Not really needed, wait_eve << 136 return; << 137 } << 138 << 139 wait_event(rsp->gp_wait, READ_ONCE(rsp << 140 } << 141 << 142 /** << 143 * rcu_sync_exit() - Allow readers back onto f << 144 * @rsp: Pointer to rcu_sync structure to use 198 * @rsp: Pointer to rcu_sync structure to use for synchronization 145 * 199 * 146 * This function is used by updaters who have 200 * This function is used by updaters who have completed, and can therefore 147 * now allow readers to make use of their fast 201 * now allow readers to make use of their fastpaths after a grace period 148 * has elapsed. After this grace period has c 202 * has elapsed. After this grace period has completed, all subsequent 149 * calls to rcu_sync_is_idle() will return tru 203 * calls to rcu_sync_is_idle() will return true, which tells readers that 150 * they can once again use their fastpaths. 204 * they can once again use their fastpaths. 151 */ 205 */ 152 void rcu_sync_exit(struct rcu_sync *rsp) 206 void rcu_sync_exit(struct rcu_sync *rsp) 153 { 207 { 154 WARN_ON_ONCE(READ_ONCE(rsp->gp_state) << 155 << 156 spin_lock_irq(&rsp->rss_lock); 208 spin_lock_irq(&rsp->rss_lock); 157 WARN_ON_ONCE(rsp->gp_count == 0); << 158 if (!--rsp->gp_count) { 209 if (!--rsp->gp_count) { 159 if (rsp->gp_state == GP_PASSED !! 210 if (rsp->cb_state == CB_IDLE) { 160 WRITE_ONCE(rsp->gp_sta !! 211 rsp->cb_state = CB_PENDING; 161 rcu_sync_call(rsp); !! 212 gp_ops[rsp->gp_type].call(&rsp->cb_head, rcu_sync_func); 162 } else if (rsp->gp_state == GP !! 213 } else if (rsp->cb_state == CB_PENDING) { 163 WRITE_ONCE(rsp->gp_sta !! 214 rsp->cb_state = CB_REPLAY; 164 } 215 } 165 } 216 } 166 spin_unlock_irq(&rsp->rss_lock); 217 spin_unlock_irq(&rsp->rss_lock); 167 } 218 } 168 219 169 /** 220 /** 170 * rcu_sync_dtor() - Clean up an rcu_sync stru 221 * rcu_sync_dtor() - Clean up an rcu_sync structure 171 * @rsp: Pointer to rcu_sync structure to be c 222 * @rsp: Pointer to rcu_sync structure to be cleaned up 172 */ 223 */ 173 void rcu_sync_dtor(struct rcu_sync *rsp) 224 void rcu_sync_dtor(struct rcu_sync *rsp) 174 { 225 { 175 int gp_state; !! 226 int cb_state; 176 227 177 WARN_ON_ONCE(READ_ONCE(rsp->gp_state) !! 228 BUG_ON(rsp->gp_count); 178 229 179 spin_lock_irq(&rsp->rss_lock); 230 spin_lock_irq(&rsp->rss_lock); 180 WARN_ON_ONCE(rsp->gp_count); !! 231 if (rsp->cb_state == CB_REPLAY) 181 if (rsp->gp_state == GP_REPLAY) !! 232 rsp->cb_state = CB_PENDING; 182 WRITE_ONCE(rsp->gp_state, GP_E !! 233 cb_state = rsp->cb_state; 183 gp_state = rsp->gp_state; << 184 spin_unlock_irq(&rsp->rss_lock); 234 spin_unlock_irq(&rsp->rss_lock); 185 235 186 if (gp_state != GP_IDLE) { !! 236 if (cb_state != CB_IDLE) { 187 rcu_barrier(); !! 237 gp_ops[rsp->gp_type].wait(); 188 WARN_ON_ONCE(rsp->gp_state != !! 238 BUG_ON(rsp->cb_state != CB_IDLE); 189 } 239 } 190 } 240 } 191 241
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.