aboutsummaryrefslogtreecommitdiffstats
path: root/lib/percpu-refcount.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/percpu-refcount.c')
-rw-r--r--lib/percpu-refcount.c169
1 files changed, 95 insertions, 74 deletions
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c
index 27fe74948882..9ac959ef4cae 100644
--- a/lib/percpu-refcount.c
+++ b/lib/percpu-refcount.c
@@ -33,6 +33,7 @@
33 33
34#define PERCPU_COUNT_BIAS (1LU << (BITS_PER_LONG - 1)) 34#define PERCPU_COUNT_BIAS (1LU << (BITS_PER_LONG - 1))
35 35
36static DEFINE_SPINLOCK(percpu_ref_switch_lock);
36static DECLARE_WAIT_QUEUE_HEAD(percpu_ref_switch_waitq); 37static DECLARE_WAIT_QUEUE_HEAD(percpu_ref_switch_waitq);
37 38
38static unsigned long __percpu *percpu_count_ptr(struct percpu_ref *ref) 39static unsigned long __percpu *percpu_count_ptr(struct percpu_ref *ref)
@@ -82,6 +83,7 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release,
82 atomic_long_set(&ref->count, start_count); 83 atomic_long_set(&ref->count, start_count);
83 84
84 ref->release = release; 85 ref->release = release;
86 ref->confirm_switch = NULL;
85 return 0; 87 return 0;
86} 88}
87EXPORT_SYMBOL_GPL(percpu_ref_init); 89EXPORT_SYMBOL_GPL(percpu_ref_init);
@@ -101,6 +103,8 @@ void percpu_ref_exit(struct percpu_ref *ref)
101 unsigned long __percpu *percpu_count = percpu_count_ptr(ref); 103 unsigned long __percpu *percpu_count = percpu_count_ptr(ref);
102 104
103 if (percpu_count) { 105 if (percpu_count) {
106 /* non-NULL confirm_switch indicates switching in progress */
107 WARN_ON_ONCE(ref->confirm_switch);
104 free_percpu(percpu_count); 108 free_percpu(percpu_count);
105 ref->percpu_count_ptr = __PERCPU_REF_ATOMIC_DEAD; 109 ref->percpu_count_ptr = __PERCPU_REF_ATOMIC_DEAD;
106 } 110 }
@@ -161,66 +165,23 @@ static void percpu_ref_noop_confirm_switch(struct percpu_ref *ref)
161static void __percpu_ref_switch_to_atomic(struct percpu_ref *ref, 165static void __percpu_ref_switch_to_atomic(struct percpu_ref *ref,
162 percpu_ref_func_t *confirm_switch) 166 percpu_ref_func_t *confirm_switch)
163{ 167{
164 if (!(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC)) { 168 if (ref->percpu_count_ptr & __PERCPU_REF_ATOMIC) {
165 /* switching from percpu to atomic */ 169 if (confirm_switch)
166 ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC; 170 confirm_switch(ref);
167 171 return;
168 /*
169 * Non-NULL ->confirm_switch is used to indicate that
170 * switching is in progress. Use noop one if unspecified.
171 */
172 WARN_ON_ONCE(ref->confirm_switch);
173 ref->confirm_switch =
174 confirm_switch ?: percpu_ref_noop_confirm_switch;
175
176 percpu_ref_get(ref); /* put after confirmation */
177 call_rcu_sched(&ref->rcu, percpu_ref_switch_to_atomic_rcu);
178 } else if (confirm_switch) {
179 /*
180 * Somebody already set ATOMIC. Switching may still be in
181 * progress. @confirm_switch must be invoked after the
182 * switching is complete and a full sched RCU grace period
183 * has passed. Wait synchronously for the previous
184 * switching and schedule @confirm_switch invocation.
185 */
186 wait_event(percpu_ref_switch_waitq, !ref->confirm_switch);
187 ref->confirm_switch = confirm_switch;
188
189 percpu_ref_get(ref); /* put after confirmation */
190 call_rcu_sched(&ref->rcu, percpu_ref_call_confirm_rcu);
191 } 172 }
192}
193 173
194/** 174 /* switching from percpu to atomic */
195 * percpu_ref_switch_to_atomic - switch a percpu_ref to atomic mode 175 ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC;
196 * @ref: percpu_ref to switch to atomic mode 176
197 * @confirm_switch: optional confirmation callback 177 /*
198 * 178 * Non-NULL ->confirm_switch is used to indicate that switching is
199 * There's no reason to use this function for the usual reference counting. 179 * in progress. Use noop one if unspecified.
200 * Use percpu_ref_kill[_and_confirm](). 180 */
201 * 181 ref->confirm_switch = confirm_switch ?: percpu_ref_noop_confirm_switch;
202 * Schedule switching of @ref to atomic mode. All its percpu counts will 182
203 * be collected to the main atomic counter. On completion, when all CPUs 183 percpu_ref_get(ref); /* put after confirmation */
204 * are guaraneed to be in atomic mode, @confirm_switch, which may not 184 call_rcu_sched(&ref->rcu, percpu_ref_switch_to_atomic_rcu);
205 * block, is invoked. This function may be invoked concurrently with all
206 * the get/put operations and can safely be mixed with kill and reinit
207 * operations. Note that @ref will stay in atomic mode across kill/reinit
208 * cycles until percpu_ref_switch_to_percpu() is called.
209 *
210 * This function normally doesn't block and can be called from any context
211 * but it may block if @confirm_kill is specified and @ref is already in
212 * the process of switching to atomic mode. In such cases, @confirm_switch
213 * will be invoked after the switching is complete.
214 *
215 * Due to the way percpu_ref is implemented, @confirm_switch will be called
216 * after at least one full sched RCU grace period has passed but this is an
217 * implementation detail and must not be depended upon.
218 */
219void percpu_ref_switch_to_atomic(struct percpu_ref *ref,
220 percpu_ref_func_t *confirm_switch)
221{
222 ref->force_atomic = true;
223 __percpu_ref_switch_to_atomic(ref, confirm_switch);
224} 185}
225 186
226static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref) 187static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref)
@@ -233,8 +194,6 @@ static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref)
233 if (!(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC)) 194 if (!(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC))
234 return; 195 return;
235 196
236 wait_event(percpu_ref_switch_waitq, !ref->confirm_switch);
237
238 atomic_long_add(PERCPU_COUNT_BIAS, &ref->count); 197 atomic_long_add(PERCPU_COUNT_BIAS, &ref->count);
239 198
240 /* 199 /*
@@ -250,6 +209,58 @@ static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref)
250 ref->percpu_count_ptr & ~__PERCPU_REF_ATOMIC); 209 ref->percpu_count_ptr & ~__PERCPU_REF_ATOMIC);
251} 210}
252 211
212static void __percpu_ref_switch_mode(struct percpu_ref *ref,
213 percpu_ref_func_t *confirm_switch)
214{
215 lockdep_assert_held(&percpu_ref_switch_lock);
216
217 /*
218 * If the previous ATOMIC switching hasn't finished yet, wait for
219 * its completion. If the caller ensures that ATOMIC switching
220 * isn't in progress, this function can be called from any context.
221 */
222 wait_event_lock_irq(percpu_ref_switch_waitq, !ref->confirm_switch,
223 percpu_ref_switch_lock);
224
225 if (ref->force_atomic || (ref->percpu_count_ptr & __PERCPU_REF_DEAD))
226 __percpu_ref_switch_to_atomic(ref, confirm_switch);
227 else
228 __percpu_ref_switch_to_percpu(ref);
229}
230
231/**
232 * percpu_ref_switch_to_atomic - switch a percpu_ref to atomic mode
233 * @ref: percpu_ref to switch to atomic mode
234 * @confirm_switch: optional confirmation callback
235 *
236 * There's no reason to use this function for the usual reference counting.
237 * Use percpu_ref_kill[_and_confirm]().
238 *
239 * Schedule switching of @ref to atomic mode. All its percpu counts will
240 * be collected to the main atomic counter. On completion, when all CPUs
241 * are guaraneed to be in atomic mode, @confirm_switch, which may not
242 * block, is invoked. This function may be invoked concurrently with all
243 * the get/put operations and can safely be mixed with kill and reinit
244 * operations. Note that @ref will stay in atomic mode across kill/reinit
245 * cycles until percpu_ref_switch_to_percpu() is called.
246 *
247 * This function may block if @ref is in the process of switching to atomic
248 * mode. If the caller ensures that @ref is not in the process of
249 * switching to atomic mode, this function can be called from any context.
250 */
251void percpu_ref_switch_to_atomic(struct percpu_ref *ref,
252 percpu_ref_func_t *confirm_switch)
253{
254 unsigned long flags;
255
256 spin_lock_irqsave(&percpu_ref_switch_lock, flags);
257
258 ref->force_atomic = true;
259 __percpu_ref_switch_mode(ref, confirm_switch);
260
261 spin_unlock_irqrestore(&percpu_ref_switch_lock, flags);
262}
263
253/** 264/**
254 * percpu_ref_switch_to_percpu - switch a percpu_ref to percpu mode 265 * percpu_ref_switch_to_percpu - switch a percpu_ref to percpu mode
255 * @ref: percpu_ref to switch to percpu mode 266 * @ref: percpu_ref to switch to percpu mode
@@ -264,17 +275,20 @@ static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref)
264 * dying or dead, the actual switching takes place on the following 275 * dying or dead, the actual switching takes place on the following
265 * percpu_ref_reinit(). 276 * percpu_ref_reinit().
266 * 277 *
267 * This function normally doesn't block and can be called from any context 278 * This function may block if @ref is in the process of switching to atomic
268 * but it may block if @ref is in the process of switching to atomic mode 279 * mode. If the caller ensures that @ref is not in the process of
269 * by percpu_ref_switch_atomic(). 280 * switching to atomic mode, this function can be called from any context.
270 */ 281 */
271void percpu_ref_switch_to_percpu(struct percpu_ref *ref) 282void percpu_ref_switch_to_percpu(struct percpu_ref *ref)
272{ 283{
284 unsigned long flags;
285
286 spin_lock_irqsave(&percpu_ref_switch_lock, flags);
287
273 ref->force_atomic = false; 288 ref->force_atomic = false;
289 __percpu_ref_switch_mode(ref, NULL);
274 290
275 /* a dying or dead ref can't be switched to percpu mode w/o reinit */ 291 spin_unlock_irqrestore(&percpu_ref_switch_lock, flags);
276 if (!(ref->percpu_count_ptr & __PERCPU_REF_DEAD))
277 __percpu_ref_switch_to_percpu(ref);
278} 292}
279 293
280/** 294/**
@@ -290,21 +304,23 @@ void percpu_ref_switch_to_percpu(struct percpu_ref *ref)
290 * 304 *
291 * This function normally doesn't block and can be called from any context 305 * This function normally doesn't block and can be called from any context
292 * but it may block if @confirm_kill is specified and @ref is in the 306 * but it may block if @confirm_kill is specified and @ref is in the
293 * process of switching to atomic mode by percpu_ref_switch_atomic(). 307 * process of switching to atomic mode by percpu_ref_switch_to_atomic().
294 *
295 * Due to the way percpu_ref is implemented, @confirm_switch will be called
296 * after at least one full sched RCU grace period has passed but this is an
297 * implementation detail and must not be depended upon.
298 */ 308 */
299void percpu_ref_kill_and_confirm(struct percpu_ref *ref, 309void percpu_ref_kill_and_confirm(struct percpu_ref *ref,
300 percpu_ref_func_t *confirm_kill) 310 percpu_ref_func_t *confirm_kill)
301{ 311{
312 unsigned long flags;
313
314 spin_lock_irqsave(&percpu_ref_switch_lock, flags);
315
302 WARN_ONCE(ref->percpu_count_ptr & __PERCPU_REF_DEAD, 316 WARN_ONCE(ref->percpu_count_ptr & __PERCPU_REF_DEAD,
303 "%s called more than once on %pf!", __func__, ref->release); 317 "%s called more than once on %pf!", __func__, ref->release);
304 318
305 ref->percpu_count_ptr |= __PERCPU_REF_DEAD; 319 ref->percpu_count_ptr |= __PERCPU_REF_DEAD;
306 __percpu_ref_switch_to_atomic(ref, confirm_kill); 320 __percpu_ref_switch_mode(ref, confirm_kill);
307 percpu_ref_put(ref); 321 percpu_ref_put(ref);
322
323 spin_unlock_irqrestore(&percpu_ref_switch_lock, flags);
308} 324}
309EXPORT_SYMBOL_GPL(percpu_ref_kill_and_confirm); 325EXPORT_SYMBOL_GPL(percpu_ref_kill_and_confirm);
310 326
@@ -321,11 +337,16 @@ EXPORT_SYMBOL_GPL(percpu_ref_kill_and_confirm);
321 */ 337 */
322void percpu_ref_reinit(struct percpu_ref *ref) 338void percpu_ref_reinit(struct percpu_ref *ref)
323{ 339{
340 unsigned long flags;
341
342 spin_lock_irqsave(&percpu_ref_switch_lock, flags);
343
324 WARN_ON_ONCE(!percpu_ref_is_zero(ref)); 344 WARN_ON_ONCE(!percpu_ref_is_zero(ref));
325 345
326 ref->percpu_count_ptr &= ~__PERCPU_REF_DEAD; 346 ref->percpu_count_ptr &= ~__PERCPU_REF_DEAD;
327 percpu_ref_get(ref); 347 percpu_ref_get(ref);
328 if (!ref->force_atomic) 348 __percpu_ref_switch_mode(ref, NULL);
329 __percpu_ref_switch_to_percpu(ref); 349
350 spin_unlock_irqrestore(&percpu_ref_switch_lock, flags);
330} 351}
331EXPORT_SYMBOL_GPL(percpu_ref_reinit); 352EXPORT_SYMBOL_GPL(percpu_ref_reinit);