Blame view

kernel/srcu.c 19.5 KB
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * Sleepable Read-Copy Update mechanism for mutual exclusion.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   *
   * Copyright (C) IBM Corporation, 2006
4e87b2d7e   Lai Jiangshan   srcu: Credit Lai ...
19
   * Copyright (C) Fujitsu, 2012
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
20
21
   *
   * Author: Paul McKenney <paulmck@us.ibm.com>
4e87b2d7e   Lai Jiangshan   srcu: Credit Lai ...
22
   *	   Lai Jiangshan <laijs@cn.fujitsu.com>
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
23
24
25
26
27
   *
   * For detailed explanation of Read-Copy Update mechanism see -
   * 		Documentation/RCU/ *.txt
   *
   */
9984de1a5   Paul Gortmaker   kernel: Map most ...
28
  #include <linux/export.h>
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
29
30
31
32
33
  #include <linux/mutex.h>
  #include <linux/percpu.h>
  #include <linux/preempt.h>
  #include <linux/rcupdate.h>
  #include <linux/sched.h>
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
34
  #include <linux/smp.h>
46fdb0937   Paul E. McKenney   rcu: Make synchro...
35
  #include <linux/delay.h>
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
36
  #include <linux/srcu.h>
3705b88db   Antti P Miettinen   rcu: Add a module...
37
38
39
  #include <trace/events/rcu.h>
  
  #include "rcu.h"
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  /*
   * Initialize an rcu_batch structure to empty.
   */
  static inline void rcu_batch_init(struct rcu_batch *b)
  {
  	b->head = NULL;
  	b->tail = &b->head;
  }
  
  /*
   * Enqueue a callback onto the tail of the specified rcu_batch structure.
   */
  static inline void rcu_batch_queue(struct rcu_batch *b, struct rcu_head *head)
  {
  	*b->tail = head;
  	b->tail = &head->next;
  }
  
  /*
   * Is the specified rcu_batch structure empty?
   */
  static inline bool rcu_batch_empty(struct rcu_batch *b)
  {
  	return b->tail == &b->head;
  }
  
  /*
   * Remove the callback at the head of the specified rcu_batch structure
   * and return a pointer to it, or return NULL if the structure is empty.
   */
  static inline struct rcu_head *rcu_batch_dequeue(struct rcu_batch *b)
  {
  	struct rcu_head *head;
  
  	if (rcu_batch_empty(b))
  		return NULL;
  
  	head = b->head;
  	b->head = head->next;
  	if (b->tail == &head->next)
  		rcu_batch_init(b);
  
  	return head;
  }
  
  /*
   * Move all callbacks from the rcu_batch structure specified by "from" to
   * the structure specified by "to".
   */
  static inline void rcu_batch_move(struct rcu_batch *to, struct rcu_batch *from)
  {
  	if (!rcu_batch_empty(from)) {
  		*to->tail = from->head;
  		to->tail = from->tail;
  		rcu_batch_init(from);
  	}
  }
632ee2001   Paul E. McKenney   rcu: Introduce lo...
97
98
99
  static int init_srcu_struct_fields(struct srcu_struct *sp)
  {
  	sp->completed = 0;
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
100
101
102
103
104
105
106
  	spin_lock_init(&sp->queue_lock);
  	sp->running = false;
  	rcu_batch_init(&sp->batch_queue);
  	rcu_batch_init(&sp->batch_check0);
  	rcu_batch_init(&sp->batch_check1);
  	rcu_batch_init(&sp->batch_done);
  	INIT_DELAYED_WORK(&sp->work, process_srcu);
632ee2001   Paul E. McKenney   rcu: Introduce lo...
107
108
109
110
111
112
113
114
115
  	sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array);
  	return sp->per_cpu_ref ? 0 : -ENOMEM;
  }
  
  #ifdef CONFIG_DEBUG_LOCK_ALLOC
  
  int __init_srcu_struct(struct srcu_struct *sp, const char *name,
  		       struct lock_class_key *key)
  {
632ee2001   Paul E. McKenney   rcu: Introduce lo...
116
117
118
  	/* Don't re-initialize a lock while it is held. */
  	debug_check_no_locks_freed((void *)sp, sizeof(*sp));
  	lockdep_init_map(&sp->dep_map, name, key, 0);
632ee2001   Paul E. McKenney   rcu: Introduce lo...
119
120
121
122
123
  	return init_srcu_struct_fields(sp);
  }
  EXPORT_SYMBOL_GPL(__init_srcu_struct);
  
  #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
124
125
126
127
128
129
130
131
  /**
   * init_srcu_struct - initialize a sleep-RCU structure
   * @sp: structure to initialize.
   *
   * Must invoke this on a given srcu_struct before passing that srcu_struct
   * to any other function.  Each srcu_struct represents a separate domain
   * of SRCU protection.
   */
e6a92013b   Alan Stern   [PATCH] SRCU: rep...
132
  int init_srcu_struct(struct srcu_struct *sp)
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
133
  {
632ee2001   Paul E. McKenney   rcu: Introduce lo...
134
  	return init_srcu_struct_fields(sp);
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
135
  }
0cd397d33   Paul E. McKenney   rcu: Add synchron...
136
  EXPORT_SYMBOL_GPL(init_srcu_struct);
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
137

632ee2001   Paul E. McKenney   rcu: Introduce lo...
138
  #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
139
  /*
b52ce066c   Lai Jiangshan   rcu: Implement a ...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
   * Returns approximate total of the readers' ->seq[] values for the
   * rank of per-CPU counters specified by idx.
   */
  static unsigned long srcu_readers_seq_idx(struct srcu_struct *sp, int idx)
  {
  	int cpu;
  	unsigned long sum = 0;
  	unsigned long t;
  
  	for_each_possible_cpu(cpu) {
  		t = ACCESS_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->seq[idx]);
  		sum += t;
  	}
  	return sum;
  }
  
  /*
cef50120b   Paul E. McKenney   rcu: Direct algor...
157
   * Returns approximate number of readers active on the specified rank
b52ce066c   Lai Jiangshan   rcu: Implement a ...
158
   * of the per-CPU ->c[] counters.
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
159
   */
cef50120b   Paul E. McKenney   rcu: Direct algor...
160
161
162
163
164
  static unsigned long srcu_readers_active_idx(struct srcu_struct *sp, int idx)
  {
  	int cpu;
  	unsigned long sum = 0;
  	unsigned long t;
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
165

cef50120b   Paul E. McKenney   rcu: Direct algor...
166
167
168
  	for_each_possible_cpu(cpu) {
  		t = ACCESS_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->c[idx]);
  		sum += t;
cef50120b   Paul E. McKenney   rcu: Direct algor...
169
  	}
b52ce066c   Lai Jiangshan   rcu: Implement a ...
170
  	return sum;
cef50120b   Paul E. McKenney   rcu: Direct algor...
171
172
173
  }
  
  /*
b52ce066c   Lai Jiangshan   rcu: Implement a ...
174
175
176
177
178
179
180
   * Return true if the number of pre-existing readers is determined to
   * be stably zero.  An example unstable zero can occur if the call
   * to srcu_readers_active_idx() misses an __srcu_read_lock() increment,
   * but due to task migration, sees the corresponding __srcu_read_unlock()
   * decrement.  This can happen because srcu_readers_active_idx() takes
   * time to sum the array, and might in fact be interrupted or preempted
   * partway through the summation.
cef50120b   Paul E. McKenney   rcu: Direct algor...
181
182
   */
  static bool srcu_readers_active_idx_check(struct srcu_struct *sp, int idx)
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
183
  {
b52ce066c   Lai Jiangshan   rcu: Implement a ...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  	unsigned long seq;
  
  	seq = srcu_readers_seq_idx(sp, idx);
  
  	/*
  	 * The following smp_mb() A pairs with the smp_mb() B located in
  	 * __srcu_read_lock().  This pairing ensures that if an
  	 * __srcu_read_lock() increments its counter after the summation
  	 * in srcu_readers_active_idx(), then the corresponding SRCU read-side
  	 * critical section will see any changes made prior to the start
  	 * of the current SRCU grace period.
  	 *
  	 * Also, if the above call to srcu_readers_seq_idx() saw the
  	 * increment of ->seq[], then the call to srcu_readers_active_idx()
  	 * must see the increment of ->c[].
  	 */
  	smp_mb(); /* A */
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
201

cef50120b   Paul E. McKenney   rcu: Direct algor...
202
203
204
205
206
  	/*
  	 * Note that srcu_readers_active_idx() can incorrectly return
  	 * zero even though there is a pre-existing reader throughout.
  	 * To see this, suppose that task A is in a very long SRCU
  	 * read-side critical section that started on CPU 0, and that
b52ce066c   Lai Jiangshan   rcu: Implement a ...
207
  	 * no other reader exists, so that the sum of the counters
cef50120b   Paul E. McKenney   rcu: Direct algor...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  	 * is equal to one.  Then suppose that task B starts executing
  	 * srcu_readers_active_idx(), summing up to CPU 1, and then that
  	 * task C starts reading on CPU 0, so that its increment is not
  	 * summed, but finishes reading on CPU 2, so that its decrement
  	 * -is- summed.  Then when task B completes its sum, it will
  	 * incorrectly get zero, despite the fact that task A has been
  	 * in its SRCU read-side critical section the whole time.
  	 *
  	 * We therefore do a validation step should srcu_readers_active_idx()
  	 * return zero.
  	 */
  	if (srcu_readers_active_idx(sp, idx) != 0)
  		return false;
  
  	/*
b52ce066c   Lai Jiangshan   rcu: Implement a ...
223
224
225
226
227
228
  	 * The remainder of this function is the validation step.
  	 * The following smp_mb() D pairs with the smp_mb() C in
  	 * __srcu_read_unlock().  If the __srcu_read_unlock() was seen
  	 * by srcu_readers_active_idx() above, then any destructive
  	 * operation performed after the grace period will happen after
  	 * the corresponding SRCU read-side critical section.
cef50120b   Paul E. McKenney   rcu: Direct algor...
229
  	 *
b52ce066c   Lai Jiangshan   rcu: Implement a ...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  	 * Note that there can be at most NR_CPUS worth of readers using
  	 * the old index, which is not enough to overflow even a 32-bit
  	 * integer.  (Yes, this does mean that systems having more than
  	 * a billion or so CPUs need to be 64-bit systems.)  Therefore,
  	 * the sum of the ->seq[] counters cannot possibly overflow.
  	 * Therefore, the only way that the return values of the two
  	 * calls to srcu_readers_seq_idx() can be equal is if there were
  	 * no increments of the corresponding rank of ->seq[] counts
  	 * in the interim.  But the missed-increment scenario laid out
  	 * above includes an increment of the ->seq[] counter by
  	 * the corresponding __srcu_read_lock().  Therefore, if this
  	 * scenario occurs, the return values from the two calls to
  	 * srcu_readers_seq_idx() will differ, and thus the validation
  	 * step below suffices.
cef50120b   Paul E. McKenney   rcu: Direct algor...
244
  	 */
b52ce066c   Lai Jiangshan   rcu: Implement a ...
245
246
247
  	smp_mb(); /* D */
  
  	return srcu_readers_seq_idx(sp, idx) == seq;
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
248
249
250
251
252
253
254
255
256
257
  }
  
  /**
   * srcu_readers_active - returns approximate number of readers.
   * @sp: which srcu_struct to count active readers (holding srcu_read_lock).
   *
   * Note that this is not an atomic primitive, and can therefore suffer
   * severe errors when invoked on an active srcu_struct.  That said, it
   * can be useful as an error check at cleanup time.
   */
bb695170d   Adrian Bunk   make srcu_readers...
258
  static int srcu_readers_active(struct srcu_struct *sp)
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
259
  {
dc8791750   Lai Jiangshan   rcu: Improve srcu...
260
261
262
263
264
265
266
267
  	int cpu;
  	unsigned long sum = 0;
  
  	for_each_possible_cpu(cpu) {
  		sum += ACCESS_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->c[0]);
  		sum += ACCESS_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->c[1]);
  	}
  	return sum;
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
268
269
270
271
272
273
274
275
276
277
278
  }
  
  /**
   * cleanup_srcu_struct - deconstruct a sleep-RCU structure
   * @sp: structure to clean up.
   *
   * Must invoke this after you are finished using a given srcu_struct that
   * was initialized via init_srcu_struct(), else you leak memory.
   */
  void cleanup_srcu_struct(struct srcu_struct *sp)
  {
ab4d2986e   Lai Jiangshan   srcu: Simple clea...
279
280
  	if (WARN_ON(srcu_readers_active(sp)))
  		return; /* Leakage unless caller handles error. */
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
281
282
283
  	free_percpu(sp->per_cpu_ref);
  	sp->per_cpu_ref = NULL;
  }
0cd397d33   Paul E. McKenney   rcu: Add synchron...
284
  EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
285

632ee2001   Paul E. McKenney   rcu: Introduce lo...
286
  /*
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
287
288
289
290
   * Counts the new reader in the appropriate per-CPU element of the
   * srcu_struct.  Must be called from process context.
   * Returns an index that must be passed to the matching srcu_read_unlock().
   */
632ee2001   Paul E. McKenney   rcu: Introduce lo...
291
  int __srcu_read_lock(struct srcu_struct *sp)
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
292
293
  {
  	int idx;
7a6b55e71   Lai Jiangshan   srcu: use ACCESS_...
294
  	idx = ACCESS_ONCE(sp->completed) & 0x1;
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
295
  	preempt_disable();
b52ce066c   Lai Jiangshan   rcu: Implement a ...
296
  	ACCESS_ONCE(this_cpu_ptr(sp->per_cpu_ref)->c[idx]) += 1;
cef50120b   Paul E. McKenney   rcu: Direct algor...
297
  	smp_mb(); /* B */  /* Avoid leaking the critical section. */
b52ce066c   Lai Jiangshan   rcu: Implement a ...
298
  	ACCESS_ONCE(this_cpu_ptr(sp->per_cpu_ref)->seq[idx]) += 1;
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
299
300
301
  	preempt_enable();
  	return idx;
  }
632ee2001   Paul E. McKenney   rcu: Introduce lo...
302
  EXPORT_SYMBOL_GPL(__srcu_read_lock);
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
303

632ee2001   Paul E. McKenney   rcu: Introduce lo...
304
  /*
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
305
306
307
308
309
   * Removes the count for the old reader from the appropriate per-CPU
   * element of the srcu_struct.  Note that this may well be a different
   * CPU than that which was incremented by the corresponding srcu_read_lock().
   * Must be called from process context.
   */
632ee2001   Paul E. McKenney   rcu: Introduce lo...
310
  void __srcu_read_unlock(struct srcu_struct *sp, int idx)
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
311
  {
cef50120b   Paul E. McKenney   rcu: Direct algor...
312
  	smp_mb(); /* C */  /* Avoid leaking the critical section. */
5a41344a3   Lai Jiangshan   srcu: Simplify __...
313
  	this_cpu_dec(sp->per_cpu_ref->c[idx]);
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
314
  }
632ee2001   Paul E. McKenney   rcu: Introduce lo...
315
  EXPORT_SYMBOL_GPL(__srcu_read_unlock);
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
316

0cd397d33   Paul E. McKenney   rcu: Add synchron...
317
  /*
c072a388d   Paul E. McKenney   rcu: demote SRCU_...
318
319
320
321
322
323
324
   * We use an adaptive strategy for synchronize_srcu() and especially for
   * synchronize_srcu_expedited().  We spin for a fixed time period
   * (defined below) to allow SRCU readers to exit their read-side critical
   * sections.  If there are still some readers after 10 microseconds,
   * we repeatedly block for 1-millisecond time periods.  This approach
   * has done well in testing, so there is no need for a config parameter.
   */
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
325
  #define SRCU_RETRY_CHECK_DELAY		5
d9792edd7   Lai Jiangshan   rcu: Use single v...
326
327
  #define SYNCHRONIZE_SRCU_TRYCOUNT	2
  #define SYNCHRONIZE_SRCU_EXP_TRYCOUNT	12
cef50120b   Paul E. McKenney   rcu: Direct algor...
328

18108ebfe   Lai Jiangshan   rcu: Improve SRCU...
329
  /*
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
330
   * @@@ Wait until all pre-existing readers complete.  Such readers
18108ebfe   Lai Jiangshan   rcu: Improve SRCU...
331
   * will have used the index specified by "idx".
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
332
333
   * the caller should ensures the ->completed is not changed while checking
   * and idx = (->completed & 1) ^ 1
18108ebfe   Lai Jiangshan   rcu: Improve SRCU...
334
   */
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
335
  static bool try_check_zero(struct srcu_struct *sp, int idx, int trycount)
cef50120b   Paul E. McKenney   rcu: Direct algor...
336
  {
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
337
338
339
340
341
342
  	for (;;) {
  		if (srcu_readers_active_idx_check(sp, idx))
  			return true;
  		if (--trycount <= 0)
  			return false;
  		udelay(SRCU_RETRY_CHECK_DELAY);
cef50120b   Paul E. McKenney   rcu: Direct algor...
343
  	}
cef50120b   Paul E. McKenney   rcu: Direct algor...
344
  }
c072a388d   Paul E. McKenney   rcu: demote SRCU_...
345

931ea9d1a   Lai Jiangshan   rcu: Implement pe...
346
347
348
349
350
  /*
   * Increment the ->completed counter so that future SRCU readers will
   * use the other rank of the ->c[] and ->seq[] arrays.  This allows
   * us to wait for pre-existing readers in a starvation-free manner.
   */
18108ebfe   Lai Jiangshan   rcu: Improve SRCU...
351
  static void srcu_flip(struct srcu_struct *sp)
944ce9af4   Lai Jiangshan   rcu: Flip ->compl...
352
  {
18108ebfe   Lai Jiangshan   rcu: Improve SRCU...
353
  	sp->completed++;
944ce9af4   Lai Jiangshan   rcu: Flip ->compl...
354
355
356
  }
  
  /*
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
357
358
359
360
361
362
363
364
365
366
367
368
369
370
   * Enqueue an SRCU callback on the specified srcu_struct structure,
   * initiating grace-period processing if it is not already running.
   */
  void call_srcu(struct srcu_struct *sp, struct rcu_head *head,
  		void (*func)(struct rcu_head *head))
  {
  	unsigned long flags;
  
  	head->next = NULL;
  	head->func = func;
  	spin_lock_irqsave(&sp->queue_lock, flags);
  	rcu_batch_queue(&sp->batch_queue, head);
  	if (!sp->running) {
  		sp->running = true;
3b07e9ca2   Tejun Heo   workqueue: deprec...
371
  		schedule_delayed_work(&sp->work, 0);
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  	}
  	spin_unlock_irqrestore(&sp->queue_lock, flags);
  }
  EXPORT_SYMBOL_GPL(call_srcu);
  
  struct rcu_synchronize {
  	struct rcu_head head;
  	struct completion completion;
  };
  
  /*
   * Awaken the corresponding synchronize_srcu() instance now that a
   * grace period has elapsed.
   */
  static void wakeme_after_rcu(struct rcu_head *head)
  {
  	struct rcu_synchronize *rcu;
  
  	rcu = container_of(head, struct rcu_synchronize, head);
  	complete(&rcu->completion);
  }
  
  static void srcu_advance_batches(struct srcu_struct *sp, int trycount);
  static void srcu_reschedule(struct srcu_struct *sp);
  
  /*
0cd397d33   Paul E. McKenney   rcu: Add synchron...
398
   * Helper function for synchronize_srcu() and synchronize_srcu_expedited().
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
399
   */
d9792edd7   Lai Jiangshan   rcu: Use single v...
400
  static void __synchronize_srcu(struct srcu_struct *sp, int trycount)
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
401
  {
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
402
403
404
  	struct rcu_synchronize rcu;
  	struct rcu_head *head = &rcu.head;
  	bool done = false;
18108ebfe   Lai Jiangshan   rcu: Improve SRCU...
405

fe15d706c   Paul E. McKenney   rcu: Add lockdep-...
406
407
408
409
410
  	rcu_lockdep_assert(!lock_is_held(&sp->dep_map) &&
  			   !lock_is_held(&rcu_bh_lock_map) &&
  			   !lock_is_held(&rcu_lock_map) &&
  			   !lock_is_held(&rcu_sched_lock_map),
  			   "Illegal synchronize_srcu() in same-type SRCU (or RCU) read-side critical section");
6e6f1b307   Lai Jiangshan   srcu: Add might_s...
411
  	might_sleep();
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
  	init_completion(&rcu.completion);
  
  	head->next = NULL;
  	head->func = wakeme_after_rcu;
  	spin_lock_irq(&sp->queue_lock);
  	if (!sp->running) {
  		/* steal the processing owner */
  		sp->running = true;
  		rcu_batch_queue(&sp->batch_check0, head);
  		spin_unlock_irq(&sp->queue_lock);
  
  		srcu_advance_batches(sp, trycount);
  		if (!rcu_batch_empty(&sp->batch_done)) {
  			BUG_ON(sp->batch_done.head != head);
  			rcu_batch_dequeue(&sp->batch_done);
  			done = true;
  		}
  		/* give the processing owner to work_struct */
  		srcu_reschedule(sp);
  	} else {
  		rcu_batch_queue(&sp->batch_queue, head);
  		spin_unlock_irq(&sp->queue_lock);
  	}
944ce9af4   Lai Jiangshan   rcu: Flip ->compl...
435

931ea9d1a   Lai Jiangshan   rcu: Implement pe...
436
437
  	if (!done)
  		wait_for_completion(&rcu.completion);
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
438
439
440
  }
  
  /**
0cd397d33   Paul E. McKenney   rcu: Add synchron...
441
442
443
   * synchronize_srcu - wait for prior SRCU read-side critical-section completion
   * @sp: srcu_struct with which to synchronize.
   *
34a64b6bb   Lai Jiangshan   srcu: Update sync...
444
445
446
447
448
449
   * Wait for the count to drain to zero of both indexes. To avoid the
   * possible starvation of synchronize_srcu(), it waits for the count of
   * the index=((->completed & 1) ^ 1) to drain to zero at first,
   * and then flip the completed and wait for the count of the other index.
   *
   * Can block; must be called from process context.
0cd397d33   Paul E. McKenney   rcu: Add synchron...
450
451
452
453
454
455
456
457
   *
   * Note that it is illegal to call synchronize_srcu() from the corresponding
   * SRCU read-side critical section; doing so will result in deadlock.
   * However, it is perfectly legal to call synchronize_srcu() on one
   * srcu_struct from some other srcu_struct's read-side critical section.
   */
  void synchronize_srcu(struct srcu_struct *sp)
  {
3705b88db   Antti P Miettinen   rcu: Add a module...
458
459
460
  	__synchronize_srcu(sp, rcu_expedited
  			   ? SYNCHRONIZE_SRCU_EXP_TRYCOUNT
  			   : SYNCHRONIZE_SRCU_TRYCOUNT);
0cd397d33   Paul E. McKenney   rcu: Add synchron...
461
462
463
464
  }
  EXPORT_SYMBOL_GPL(synchronize_srcu);
  
  /**
236fefafe   Paul E. McKenney   rcu: Call out dan...
465
   * synchronize_srcu_expedited - Brute-force SRCU grace period
0cd397d33   Paul E. McKenney   rcu: Add synchron...
466
467
   * @sp: srcu_struct with which to synchronize.
   *
cef50120b   Paul E. McKenney   rcu: Direct algor...
468
469
   * Wait for an SRCU grace period to elapse, but be more aggressive about
   * spinning rather than blocking when waiting.
0cd397d33   Paul E. McKenney   rcu: Add synchron...
470
   *
49271ca60   Lai Jiangshan   srcu: Update sync...
471
472
473
474
475
   * Note that it is also illegal to call synchronize_srcu_expedited()
   * from the corresponding SRCU read-side critical section;
   * doing so will result in deadlock.  However, it is perfectly legal
   * to call synchronize_srcu_expedited() on one srcu_struct from some
   * other srcu_struct's read-side critical section, as long as
236fefafe   Paul E. McKenney   rcu: Call out dan...
476
   * the resulting graph of srcu_structs is acyclic.
0cd397d33   Paul E. McKenney   rcu: Add synchron...
477
478
479
   */
  void synchronize_srcu_expedited(struct srcu_struct *sp)
  {
d9792edd7   Lai Jiangshan   rcu: Use single v...
480
  	__synchronize_srcu(sp, SYNCHRONIZE_SRCU_EXP_TRYCOUNT);
0cd397d33   Paul E. McKenney   rcu: Add synchron...
481
482
483
484
  }
  EXPORT_SYMBOL_GPL(synchronize_srcu_expedited);
  
  /**
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
485
486
487
488
489
490
491
492
493
   * srcu_barrier - Wait until all in-flight call_srcu() callbacks complete.
   */
  void srcu_barrier(struct srcu_struct *sp)
  {
  	synchronize_srcu(sp);
  }
  EXPORT_SYMBOL_GPL(srcu_barrier);
  
  /**
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
494
495
496
497
498
499
   * srcu_batches_completed - return batches completed.
   * @sp: srcu_struct on which to report batch completion.
   *
   * Report the number of batches, correlated with, but not necessarily
   * precisely the same as, the number of grace periods that have elapsed.
   */
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
500
501
502
503
  long srcu_batches_completed(struct srcu_struct *sp)
  {
  	return sp->completed;
  }
621934ee7   Paul E. McKenney   [PATCH] srcu-3: R...
504
  EXPORT_SYMBOL_GPL(srcu_batches_completed);
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
  
  #define SRCU_CALLBACK_BATCH	10
  #define SRCU_INTERVAL		1
  
  /*
   * Move any new SRCU callbacks to the first stage of the SRCU grace
   * period pipeline.
   */
  static void srcu_collect_new(struct srcu_struct *sp)
  {
  	if (!rcu_batch_empty(&sp->batch_queue)) {
  		spin_lock_irq(&sp->queue_lock);
  		rcu_batch_move(&sp->batch_check0, &sp->batch_queue);
  		spin_unlock_irq(&sp->queue_lock);
  	}
  }
  
  /*
   * Core SRCU state machine.  Advance callbacks from ->batch_check0 to
   * ->batch_check1 and then to ->batch_done as readers drain.
   */
  static void srcu_advance_batches(struct srcu_struct *sp, int trycount)
  {
  	int idx = 1 ^ (sp->completed & 1);
  
  	/*
  	 * Because readers might be delayed for an extended period after
  	 * fetching ->completed for their index, at any point in time there
  	 * might well be readers using both idx=0 and idx=1.  We therefore
  	 * need to wait for readers to clear from both index values before
  	 * invoking a callback.
  	 */
  
  	if (rcu_batch_empty(&sp->batch_check0) &&
  	    rcu_batch_empty(&sp->batch_check1))
  		return; /* no callbacks need to be advanced */
  
  	if (!try_check_zero(sp, idx, trycount))
  		return; /* failed to advance, will try after SRCU_INTERVAL */
  
  	/*
  	 * The callbacks in ->batch_check1 have already done with their
  	 * first zero check and flip back when they were enqueued on
  	 * ->batch_check0 in a previous invocation of srcu_advance_batches().
  	 * (Presumably try_check_zero() returned false during that
  	 * invocation, leaving the callbacks stranded on ->batch_check1.)
  	 * They are therefore ready to invoke, so move them to ->batch_done.
  	 */
  	rcu_batch_move(&sp->batch_done, &sp->batch_check1);
  
  	if (rcu_batch_empty(&sp->batch_check0))
  		return; /* no callbacks need to be advanced */
  	srcu_flip(sp);
  
  	/*
  	 * The callbacks in ->batch_check0 just finished their
  	 * first check zero and flip, so move them to ->batch_check1
  	 * for future checking on the other idx.
  	 */
  	rcu_batch_move(&sp->batch_check1, &sp->batch_check0);
  
  	/*
  	 * SRCU read-side critical sections are normally short, so check
  	 * at least twice in quick succession after a flip.
  	 */
  	trycount = trycount < 2 ? 2 : trycount;
  	if (!try_check_zero(sp, idx^1, trycount))
  		return; /* failed to advance, will try after SRCU_INTERVAL */
  
  	/*
  	 * The callbacks in ->batch_check1 have now waited for all
  	 * pre-existing readers using both idx values.  They are therefore
  	 * ready to invoke, so move them to ->batch_done.
  	 */
  	rcu_batch_move(&sp->batch_done, &sp->batch_check1);
  }
  
  /*
   * Invoke a limited number of SRCU callbacks that have passed through
   * their grace period.  If there are more to do, SRCU will reschedule
   * the workqueue.
   */
  static void srcu_invoke_callbacks(struct srcu_struct *sp)
  {
  	int i;
  	struct rcu_head *head;
  
  	for (i = 0; i < SRCU_CALLBACK_BATCH; i++) {
  		head = rcu_batch_dequeue(&sp->batch_done);
  		if (!head)
  			break;
  		local_bh_disable();
  		head->func(head);
  		local_bh_enable();
  	}
  }
  
  /*
   * Finished one round of SRCU grace period.  Start another if there are
   * more SRCU callbacks queued, otherwise put SRCU into not-running state.
   */
  static void srcu_reschedule(struct srcu_struct *sp)
  {
  	bool pending = true;
  
  	if (rcu_batch_empty(&sp->batch_done) &&
  	    rcu_batch_empty(&sp->batch_check1) &&
  	    rcu_batch_empty(&sp->batch_check0) &&
  	    rcu_batch_empty(&sp->batch_queue)) {
  		spin_lock_irq(&sp->queue_lock);
  		if (rcu_batch_empty(&sp->batch_done) &&
  		    rcu_batch_empty(&sp->batch_check1) &&
  		    rcu_batch_empty(&sp->batch_check0) &&
  		    rcu_batch_empty(&sp->batch_queue)) {
  			sp->running = false;
  			pending = false;
  		}
  		spin_unlock_irq(&sp->queue_lock);
  	}
  
  	if (pending)
3b07e9ca2   Tejun Heo   workqueue: deprec...
626
  		schedule_delayed_work(&sp->work, SRCU_INTERVAL);
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
627
628
629
630
631
  }
  
  /*
   * This is the work-queue function that handles SRCU grace periods.
   */
f2ebfbc99   Lai Jiangshan   srcu: Export proc...
632
  void process_srcu(struct work_struct *work)
931ea9d1a   Lai Jiangshan   rcu: Implement pe...
633
634
635
636
637
638
639
640
641
642
  {
  	struct srcu_struct *sp;
  
  	sp = container_of(work, struct srcu_struct, work.work);
  
  	srcu_collect_new(sp);
  	srcu_advance_batches(sp, 1);
  	srcu_invoke_callbacks(sp);
  	srcu_reschedule(sp);
  }
f2ebfbc99   Lai Jiangshan   srcu: Export proc...
643
  EXPORT_SYMBOL_GPL(process_srcu);