aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/rcupdate.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-05-19 14:06:37 +0100
committerKeir Fraser <keir.fraser@citrix.com>2010-05-19 14:06:37 +0100
commit000026edbf0f117efaaa722ed6c3912aacfa30cc (patch)
tree00259ee865b9e8c79bc066c42bcf74cec6bb70cc /xen/common/rcupdate.c
parentd015de71fe3c77b3d9d2586a22886b78c77c7b6e (diff)
downloadxen-000026edbf0f117efaaa722ed6c3912aacfa30cc.tar.gz
xen-000026edbf0f117efaaa722ed6c3912aacfa30cc.tar.bz2
xen-000026edbf0f117efaaa722ed6c3912aacfa30cc.zip
rcu: Migrate RCU work when taking a CPU offline.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/common/rcupdate.c')
-rw-r--r--xen/common/rcupdate.c39
1 files changed, 36 insertions, 3 deletions
diff --git a/xen/common/rcupdate.c b/xen/common/rcupdate.c
index c8f44bb804..b93c1db697 100644
--- a/xen/common/rcupdate.c
+++ b/xen/common/rcupdate.c
@@ -322,6 +322,36 @@ void rcu_check_callbacks(int cpu)
raise_softirq(RCU_SOFTIRQ);
}
+static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list,
+ struct rcu_head **tail)
+{
+ local_irq_disable();
+ *this_rdp->nxttail = list;
+ if (list)
+ this_rdp->nxttail = tail;
+ local_irq_enable();
+}
+
+static void rcu_offline_cpu(struct rcu_data *this_rdp,
+ struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
+{
+ /* If the cpu going offline owns the grace period we can block
+ * indefinitely waiting for it, so flush it here.
+ */
+ spin_lock(&rcp->lock);
+ if (rcp->cur != rcp->completed)
+ cpu_quiet(rdp->cpu, rcp);
+ spin_unlock(&rcp->lock);
+
+ rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail);
+ rcu_move_batch(this_rdp, rdp->curlist, rdp->curtail);
+ rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail);
+
+ local_irq_disable();
+ this_rdp->qlen += rdp->qlen;
+ local_irq_enable();
+}
+
static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp,
struct rcu_data *rdp)
{
@@ -339,14 +369,17 @@ static int cpu_callback(
struct notifier_block *nfb, unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
+ struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
switch ( action )
{
- case CPU_UP_PREPARE: {
- struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
+ case CPU_UP_PREPARE:
rcu_init_percpu_data(cpu, &rcu_ctrlblk, rdp);
break;
- }
+ case CPU_UP_CANCELED:
+ case CPU_DEAD:
+ rcu_offline_cpu(&this_cpu(rcu_data), &rcu_ctrlblk, rdp);
+ break;
default:
break;
}