aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/rcuclassic.h28
-rw-r--r--kernel/rcuclassic.c177
2 files changed, 122 insertions, 83 deletions
diff --git a/include/linux/rcuclassic.h b/include/linux/rcuclassic.h
index 8c774905dcfe..04c728147be0 100644
--- a/include/linux/rcuclassic.h
+++ b/include/linux/rcuclassic.h
@@ -45,7 +45,7 @@
45struct rcu_ctrlblk { 45struct rcu_ctrlblk {
46 long cur; /* Current batch number. */ 46 long cur; /* Current batch number. */
47 long completed; /* Number of the last completed batch */ 47 long completed; /* Number of the last completed batch */
48 int next_pending; /* Is the next batch already waiting? */ 48 long pending; /* Number of the last pending batch */
49 49
50 int signaled; 50 int signaled;
51 51
@@ -66,11 +66,7 @@ static inline int rcu_batch_after(long a, long b)
66 return (a - b) > 0; 66 return (a - b) > 0;
67} 67}
68 68
69/* 69/* Per-CPU data for Read-Copy UPdate. */
70 * Per-CPU data for Read-Copy UPdate.
71 * nxtlist - new callbacks are added here
72 * curlist - current batch for which quiescent cycle started if any
73 */
74struct rcu_data { 70struct rcu_data {
75 /* 1) quiescent state handling : */ 71 /* 1) quiescent state handling : */
76 long quiescbatch; /* Batch # for grace period */ 72 long quiescbatch; /* Batch # for grace period */
@@ -78,12 +74,24 @@ struct rcu_data {
78 int qs_pending; /* core waits for quiesc state */ 74 int qs_pending; /* core waits for quiesc state */
79 75
80 /* 2) batch handling */ 76 /* 2) batch handling */
81 long batch; /* Batch # for current RCU batch */ 77 /*
78 * if nxtlist is not NULL, then:
79 * batch:
80 * The batch # for the last entry of nxtlist
81 * [*nxttail[1], NULL = *nxttail[2]):
82 * Entries that batch # <= batch
83 * [*nxttail[0], *nxttail[1]):
84 * Entries that batch # <= batch - 1
85 * [nxtlist, *nxttail[0]):
86 * Entries that batch # <= batch - 2
87 * The grace period for these entries has completed, and
88 * the other grace-period-completed entries may be moved
89 * here temporarily in rcu_process_callbacks().
90 */
91 long batch;
82 struct rcu_head *nxtlist; 92 struct rcu_head *nxtlist;
83 struct rcu_head **nxttail; 93 struct rcu_head **nxttail[3];
84 long qlen; /* # of queued callbacks */ 94 long qlen; /* # of queued callbacks */
85 struct rcu_head *curlist;
86 struct rcu_head **curtail;
87 struct rcu_head *donelist; 95 struct rcu_head *donelist;
88 struct rcu_head **donetail; 96 struct rcu_head **donetail;
89 long blimit; /* Upper limit on a processed batch */ 97 long blimit; /* Upper limit on a processed batch */
diff --git a/kernel/rcuclassic.c b/kernel/rcuclassic.c
index aad93cdc9f68..d4271146a9bd 100644
--- a/kernel/rcuclassic.c
+++ b/kernel/rcuclassic.c
@@ -60,12 +60,14 @@ EXPORT_SYMBOL_GPL(rcu_lock_map);
60static struct rcu_ctrlblk rcu_ctrlblk = { 60static struct rcu_ctrlblk rcu_ctrlblk = {
61 .cur = -300, 61 .cur = -300,
62 .completed = -300, 62 .completed = -300,
63 .pending = -300,
63 .lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock), 64 .lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock),
64 .cpumask = CPU_MASK_NONE, 65 .cpumask = CPU_MASK_NONE,
65}; 66};
66static struct rcu_ctrlblk rcu_bh_ctrlblk = { 67static struct rcu_ctrlblk rcu_bh_ctrlblk = {
67 .cur = -300, 68 .cur = -300,
68 .completed = -300, 69 .completed = -300,
70 .pending = -300,
69 .lock = __SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock), 71 .lock = __SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock),
70 .cpumask = CPU_MASK_NONE, 72 .cpumask = CPU_MASK_NONE,
71}; 73};
@@ -118,6 +120,43 @@ static inline void force_quiescent_state(struct rcu_data *rdp,
118} 120}
119#endif 121#endif
120 122
123static void __call_rcu(struct rcu_head *head, struct rcu_ctrlblk *rcp,
124 struct rcu_data *rdp)
125{
126 long batch;
127 smp_mb(); /* reads the most recently updated value of rcu->cur. */
128
129 /*
130 * Determine the batch number of this callback.
131 *
132 * Using ACCESS_ONCE to avoid the following error when gcc eliminates
133 * local variable "batch" and emits codes like this:
134 * 1) rdp->batch = rcp->cur + 1 # gets old value
135 * ......
136 * 2)rcu_batch_after(rcp->cur + 1, rdp->batch) # gets new value
137 * then [*nxttail[0], *nxttail[1]) may contain callbacks
138 * that batch# = rdp->batch, see the comment of struct rcu_data.
139 */
140 batch = ACCESS_ONCE(rcp->cur) + 1;
141
142 if (rdp->nxtlist && rcu_batch_after(batch, rdp->batch)) {
143 /* process callbacks */
144 rdp->nxttail[0] = rdp->nxttail[1];
145 rdp->nxttail[1] = rdp->nxttail[2];
146 if (rcu_batch_after(batch - 1, rdp->batch))
147 rdp->nxttail[0] = rdp->nxttail[2];
148 }
149
150 rdp->batch = batch;
151 *rdp->nxttail[2] = head;
152 rdp->nxttail[2] = &head->next;
153
154 if (unlikely(++rdp->qlen > qhimark)) {
155 rdp->blimit = INT_MAX;
156 force_quiescent_state(rdp, &rcu_ctrlblk);
157 }
158}
159
121/** 160/**
122 * call_rcu - Queue an RCU callback for invocation after a grace period. 161 * call_rcu - Queue an RCU callback for invocation after a grace period.
123 * @head: structure to be used for queueing the RCU updates. 162 * @head: structure to be used for queueing the RCU updates.
@@ -133,18 +172,11 @@ void call_rcu(struct rcu_head *head,
133 void (*func)(struct rcu_head *rcu)) 172 void (*func)(struct rcu_head *rcu))
134{ 173{
135 unsigned long flags; 174 unsigned long flags;
136 struct rcu_data *rdp;
137 175
138 head->func = func; 176 head->func = func;
139 head->next = NULL; 177 head->next = NULL;
140 local_irq_save(flags); 178 local_irq_save(flags);
141 rdp = &__get_cpu_var(rcu_data); 179 __call_rcu(head, &rcu_ctrlblk, &__get_cpu_var(rcu_data));
142 *rdp->nxttail = head;
143 rdp->nxttail = &head->next;
144 if (unlikely(++rdp->qlen > qhimark)) {
145 rdp->blimit = INT_MAX;
146 force_quiescent_state(rdp, &rcu_ctrlblk);
147 }
148 local_irq_restore(flags); 180 local_irq_restore(flags);
149} 181}
150EXPORT_SYMBOL_GPL(call_rcu); 182EXPORT_SYMBOL_GPL(call_rcu);
@@ -169,20 +201,11 @@ void call_rcu_bh(struct rcu_head *head,
169 void (*func)(struct rcu_head *rcu)) 201 void (*func)(struct rcu_head *rcu))
170{ 202{
171 unsigned long flags; 203 unsigned long flags;
172 struct rcu_data *rdp;
173 204
174 head->func = func; 205 head->func = func;
175 head->next = NULL; 206 head->next = NULL;
176 local_irq_save(flags); 207 local_irq_save(flags);
177 rdp = &__get_cpu_var(rcu_bh_data); 208 __call_rcu(head, &rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data));
178 *rdp->nxttail = head;
179 rdp->nxttail = &head->next;
180
181 if (unlikely(++rdp->qlen > qhimark)) {
182 rdp->blimit = INT_MAX;
183 force_quiescent_state(rdp, &rcu_bh_ctrlblk);
184 }
185
186 local_irq_restore(flags); 209 local_irq_restore(flags);
187} 210}
188EXPORT_SYMBOL_GPL(call_rcu_bh); 211EXPORT_SYMBOL_GPL(call_rcu_bh);
@@ -211,12 +234,6 @@ EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
211static inline void raise_rcu_softirq(void) 234static inline void raise_rcu_softirq(void)
212{ 235{
213 raise_softirq(RCU_SOFTIRQ); 236 raise_softirq(RCU_SOFTIRQ);
214 /*
215 * The smp_mb() here is required to ensure that this cpu's
216 * __rcu_process_callbacks() reads the most recently updated
217 * value of rcu->cur.
218 */
219 smp_mb();
220} 237}
221 238
222/* 239/*
@@ -276,14 +293,8 @@ static void rcu_do_batch(struct rcu_data *rdp)
276 */ 293 */
277static void rcu_start_batch(struct rcu_ctrlblk *rcp) 294static void rcu_start_batch(struct rcu_ctrlblk *rcp)
278{ 295{
279 if (rcp->next_pending && 296 if (rcp->cur != rcp->pending &&
280 rcp->completed == rcp->cur) { 297 rcp->completed == rcp->cur) {
281 rcp->next_pending = 0;
282 /*
283 * next_pending == 0 must be visible in
284 * __rcu_process_callbacks() before it can see new value of cur.
285 */
286 smp_wmb();
287 rcp->cur++; 298 rcp->cur++;
288 299
289 /* 300 /*
@@ -364,13 +375,15 @@ static void rcu_check_quiescent_state(struct rcu_ctrlblk *rcp,
364 * which is dead and hence not processing interrupts. 375 * which is dead and hence not processing interrupts.
365 */ 376 */
366static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list, 377static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list,
367 struct rcu_head **tail) 378 struct rcu_head **tail, long batch)
368{ 379{
369 local_irq_disable(); 380 if (list) {
370 *this_rdp->nxttail = list; 381 local_irq_disable();
371 if (list) 382 this_rdp->batch = batch;
372 this_rdp->nxttail = tail; 383 *this_rdp->nxttail[2] = list;
373 local_irq_enable(); 384 this_rdp->nxttail[2] = tail;
385 local_irq_enable();
386 }
374} 387}
375 388
376static void __rcu_offline_cpu(struct rcu_data *this_rdp, 389static void __rcu_offline_cpu(struct rcu_data *this_rdp,
@@ -384,9 +397,9 @@ static void __rcu_offline_cpu(struct rcu_data *this_rdp,
384 if (rcp->cur != rcp->completed) 397 if (rcp->cur != rcp->completed)
385 cpu_quiet(rdp->cpu, rcp); 398 cpu_quiet(rdp->cpu, rcp);
386 spin_unlock_bh(&rcp->lock); 399 spin_unlock_bh(&rcp->lock);
387 rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail); 400 /* spin_lock implies smp_mb() */
388 rcu_move_batch(this_rdp, rdp->curlist, rdp->curtail); 401 rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail, rcp->cur + 1);
389 rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail); 402 rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail[2], rcp->cur + 1);
390 403
391 local_irq_disable(); 404 local_irq_disable();
392 this_rdp->qlen += rdp->qlen; 405 this_rdp->qlen += rdp->qlen;
@@ -420,37 +433,45 @@ static void rcu_offline_cpu(int cpu)
420static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp, 433static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp,
421 struct rcu_data *rdp) 434 struct rcu_data *rdp)
422{ 435{
423 if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) { 436 if (rdp->nxtlist) {
424 *rdp->donetail = rdp->curlist;
425 rdp->donetail = rdp->curtail;
426 rdp->curlist = NULL;
427 rdp->curtail = &rdp->curlist;
428 }
429
430 if (rdp->nxtlist && !rdp->curlist) {
431 local_irq_disable(); 437 local_irq_disable();
432 rdp->curlist = rdp->nxtlist;
433 rdp->curtail = rdp->nxttail;
434 rdp->nxtlist = NULL;
435 rdp->nxttail = &rdp->nxtlist;
436 local_irq_enable();
437 438
438 /* 439 /*
439 * start the next batch of callbacks 440 * move the other grace-period-completed entries to
441 * [rdp->nxtlist, *rdp->nxttail[0]) temporarily
440 */ 442 */
443 if (!rcu_batch_before(rcp->completed, rdp->batch))
444 rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2];
445 else if (!rcu_batch_before(rcp->completed, rdp->batch - 1))
446 rdp->nxttail[0] = rdp->nxttail[1];
441 447
442 /* determine batch number */ 448 /*
443 rdp->batch = rcp->cur + 1; 449 * the grace period for entries in
444 /* see the comment and corresponding wmb() in 450 * [rdp->nxtlist, *rdp->nxttail[0]) has completed and
445 * the rcu_start_batch() 451 * move these entries to donelist
446 */ 452 */
447 smp_rmb(); 453 if (rdp->nxttail[0] != &rdp->nxtlist) {
454 *rdp->donetail = rdp->nxtlist;
455 rdp->donetail = rdp->nxttail[0];
456 rdp->nxtlist = *rdp->nxttail[0];
457 *rdp->donetail = NULL;
458
459 if (rdp->nxttail[1] == rdp->nxttail[0])
460 rdp->nxttail[1] = &rdp->nxtlist;
461 if (rdp->nxttail[2] == rdp->nxttail[0])
462 rdp->nxttail[2] = &rdp->nxtlist;
463 rdp->nxttail[0] = &rdp->nxtlist;
464 }
465
466 local_irq_enable();
448 467
449 if (!rcp->next_pending) { 468 if (rcu_batch_after(rdp->batch, rcp->pending)) {
450 /* and start it/schedule start if it's a new batch */ 469 /* and start it/schedule start if it's a new batch */
451 spin_lock(&rcp->lock); 470 spin_lock(&rcp->lock);
452 rcp->next_pending = 1; 471 if (rcu_batch_after(rdp->batch, rcp->pending)) {
453 rcu_start_batch(rcp); 472 rcp->pending = rdp->batch;
473 rcu_start_batch(rcp);
474 }
454 spin_unlock(&rcp->lock); 475 spin_unlock(&rcp->lock);
455 } 476 }
456 } 477 }
@@ -468,15 +489,26 @@ static void rcu_process_callbacks(struct softirq_action *unused)
468 489
469static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp) 490static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
470{ 491{
471 /* This cpu has pending rcu entries and the grace period 492 if (rdp->nxtlist) {
472 * for them has completed. 493 /*
473 */ 494 * This cpu has pending rcu entries and the grace period
474 if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) 495 * for them has completed.
475 return 1; 496 */
497 if (!rcu_batch_before(rcp->completed, rdp->batch))
498 return 1;
499 if (!rcu_batch_before(rcp->completed, rdp->batch - 1) &&
500 rdp->nxttail[0] != rdp->nxttail[1])
501 return 1;
502 if (rdp->nxttail[0] != &rdp->nxtlist)
503 return 1;
476 504
477 /* This cpu has no pending entries, but there are new entries */ 505 /*
478 if (!rdp->curlist && rdp->nxtlist) 506 * This cpu has pending rcu entries and the new batch
479 return 1; 507 * for then hasn't been started nor scheduled start
508 */
509 if (rcu_batch_after(rdp->batch, rcp->pending))
510 return 1;
511 }
480 512
481 /* This cpu has finished callbacks to invoke */ 513 /* This cpu has finished callbacks to invoke */
482 if (rdp->donelist) 514 if (rdp->donelist)
@@ -512,7 +544,7 @@ int rcu_needs_cpu(int cpu)
512 struct rcu_data *rdp = &per_cpu(rcu_data, cpu); 544 struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
513 struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu); 545 struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu);
514 546
515 return (!!rdp->curlist || !!rdp_bh->curlist || rcu_pending(cpu)); 547 return !!rdp->nxtlist || !!rdp_bh->nxtlist || rcu_pending(cpu);
516} 548}
517 549
518void rcu_check_callbacks(int cpu, int user) 550void rcu_check_callbacks(int cpu, int user)
@@ -559,8 +591,7 @@ static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp,
559 struct rcu_data *rdp) 591 struct rcu_data *rdp)
560{ 592{
561 memset(rdp, 0, sizeof(*rdp)); 593 memset(rdp, 0, sizeof(*rdp));
562 rdp->curtail = &rdp->curlist; 594 rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2] = &rdp->nxtlist;
563 rdp->nxttail = &rdp->nxtlist;
564 rdp->donetail = &rdp->donelist; 595 rdp->donetail = &rdp->donelist;
565 rdp->quiescbatch = rcp->completed; 596 rdp->quiescbatch = rcp->completed;
566 rdp->qs_pending = 0; 597 rdp->qs_pending = 0;