aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2005-01-04 05:30:36 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-01-04 05:30:36 -0800
commita48d69a5c734ceedc04d351f394d428e032ca4b9 (patch)
tree3cb7fdcb8ec4c9b299c3c2537f35d03b010c7b70 /kernel
parent38f808dd88a2128483e0308e93cd4d2d2b7b5023 (diff)
downloadhistory-a48d69a5c734ceedc04d351f394d428e032ca4b9.tar.gz
[PATCH] rcu: eliminate rcu_ctrlblk.lock
rcu_ctrlblk.lock is used to read the ->cur and ->next_pending atomically in __rcu_process_callbacks(). It can be replaced by a couple of memory barriers. rcu_start_batch: rcp->next_pending = 0; smp_wmb(); rcp->cur++; __rcu_process_callbacks: rdp->batch = rcp->cur + 1; smp_rmb(); if (!rcp->next_pending) rcu_start_batch(rcp, rsp, 1); This way, if __rcu_process_callbacks() sees incremented ->cur value, it must also see that ->next_pending == 0 (or rcu_start_batch() is already in progress on another cpu). Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/rcupdate.c30
1 files changed, 16 insertions, 14 deletions
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 80cac1cd0859b3..abb415bb54392f 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -49,9 +49,9 @@
/* Definition for rcupdate control block. */
struct rcu_ctrlblk rcu_ctrlblk =
- { .cur = -300, .completed = -300 , .lock = SEQCNT_ZERO };
+ { .cur = -300, .completed = -300 };
struct rcu_ctrlblk rcu_bh_ctrlblk =
- { .cur = -300, .completed = -300 , .lock = SEQCNT_ZERO };
+ { .cur = -300, .completed = -300 };
/* Bookkeeping of the progress of the grace period */
struct rcu_state {
@@ -185,10 +185,13 @@ static void rcu_start_batch(struct rcu_ctrlblk *rcp, struct rcu_state *rsp,
rcp->completed == rcp->cur) {
/* Can't change, since spin lock held. */
cpus_andnot(rsp->cpumask, cpu_online_map, nohz_cpu_mask);
- write_seqcount_begin(&rcp->lock);
+
rcp->next_pending = 0;
+ /* next_pending == 0 must be visible in __rcu_process_callbacks()
+ * before it can see new value of cur.
+ */
+ smp_wmb();
rcp->cur++;
- write_seqcount_end(&rcp->lock);
}
}
@@ -319,8 +322,6 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp,
local_irq_disable();
if (rdp->nxtlist && !rdp->curlist) {
- int next_pending, seq;
-
rdp->curlist = rdp->nxtlist;
rdp->curtail = rdp->nxttail;
rdp->nxtlist = NULL;
@@ -330,14 +331,15 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp,
/*
* start the next batch of callbacks
*/
- do {
- seq = read_seqcount_begin(&rcp->lock);
- /* determine batch number */
- rdp->batch = rcp->cur + 1;
- next_pending = rcp->next_pending;
- } while (read_seqcount_retry(&rcp->lock, seq));
-
- if (!next_pending) {
+
+ /* determine batch number */
+ rdp->batch = rcp->cur + 1;
+ /* see the comment and corresponding wmb() in
+ * the rcu_start_batch()
+ */
+ smp_rmb();
+
+ if (!rcp->next_pending) {
/* and start it/schedule start if it's a new batch */
spin_lock(&rsp->lock);
rcu_start_batch(rcp, rsp, 1);