[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] xen/sched: fix locking in sched_tick_[suspend|resume]()



sched_tick_suspend() and sched_tick_resume() should not call the
scheduler specific timer handlers in case the cpu they are running on
is just being moved to or from a cpupool.

Use a new percpu lock for that purpose.

Reported-by: Sergey Dyasli <sergey.dyasli@xxxxxxxxxx>
Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
---
To be applied on top of my core scheduling series.
---
 xen/common/schedule.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/xen/common/schedule.c b/xen/common/schedule.c
index 217fcb09ce..744f8cb5db 100644
--- a/xen/common/schedule.c
+++ b/xen/common/schedule.c
@@ -68,6 +68,9 @@ cpumask_t sched_res_mask;
 /* Common lock for free cpus. */
 static DEFINE_SPINLOCK(sched_free_cpu_lock);
 
+/* Lock for guarding per-scheduler calls against scheduler changes on a cpu. */
+static DEFINE_PER_CPU(spinlock_t, sched_cpu_lock);
+
 /* Various timer handlers. */
 static void s_timer_fn(void *unused);
 static void vcpu_periodic_timer_fn(void *data);
@@ -2472,6 +2475,8 @@ static int cpu_schedule_up(unsigned int cpu)
     if ( sr == NULL )
         return -ENOMEM;
 
+    spin_lock_init(&per_cpu(sched_cpu_lock, cpu));
+
     sr->master_cpu = cpu;
     cpumask_copy(sr->cpus, cpumask_of(cpu));
     set_sched_res(cpu, sr);
@@ -2763,11 +2768,14 @@ int schedule_cpu_add(unsigned int cpu, struct cpupool 
*c)
     struct scheduler *new_ops = c->sched;
     struct sched_resource *sr;
     spinlock_t *old_lock, *new_lock;
+    spinlock_t *cpu_lock = &per_cpu(sched_cpu_lock, cpu);
     unsigned long flags;
     int ret = 0;
 
     rcu_read_lock(&sched_res_rculock);
 
+    spin_lock(cpu_lock);
+
     sr = get_sched_res(cpu);
 
     ASSERT(cpumask_test_cpu(cpu, &cpupool_free_cpus));
@@ -2879,6 +2887,8 @@ int schedule_cpu_add(unsigned int cpu, struct cpupool *c)
     cpu_raise_softirq(cpu, SCHEDULE_SOFTIRQ);
 
 out:
+    spin_unlock(cpu_lock);
+
     rcu_read_unlock(&sched_res_rculock);
 
     return ret;
@@ -2897,12 +2907,15 @@ int schedule_cpu_rm(unsigned int cpu)
     struct sched_unit *unit;
     struct scheduler *old_ops;
     spinlock_t *old_lock;
+    spinlock_t *cpu_lock = &per_cpu(sched_cpu_lock, cpu);
     unsigned long flags;
     int idx, ret = -ENOMEM;
     unsigned int cpu_iter;
 
     rcu_read_lock(&sched_res_rculock);
 
+    spin_lock(cpu_lock);
+
     sr = get_sched_res(cpu);
     old_ops = sr->scheduler;
 
@@ -3004,6 +3017,8 @@ int schedule_cpu_rm(unsigned int cpu)
     sr->cpupool = NULL;
 
 out:
+    spin_unlock(cpu_lock);
+
     rcu_read_unlock(&sched_res_rculock);
     xfree(sr_new);
 
@@ -3084,11 +3099,17 @@ void sched_tick_suspend(void)
 {
     struct scheduler *sched;
     unsigned int cpu = smp_processor_id();
+    spinlock_t *lock = &per_cpu(sched_cpu_lock, cpu);
 
     rcu_read_lock(&sched_res_rculock);
 
+    spin_lock(lock);
+
     sched = get_sched_res(cpu)->scheduler;
     sched_do_tick_suspend(sched, cpu);
+
+    spin_unlock(lock);
+
     rcu_idle_enter(cpu);
     rcu_idle_timer_start();
 
@@ -3099,14 +3120,20 @@ void sched_tick_resume(void)
 {
     struct scheduler *sched;
     unsigned int cpu = smp_processor_id();
+    spinlock_t *lock = &per_cpu(sched_cpu_lock, cpu);
 
     rcu_read_lock(&sched_res_rculock);
 
     rcu_idle_timer_stop();
     rcu_idle_exit(cpu);
+
+    spin_lock(lock);
+
     sched = get_sched_res(cpu)->scheduler;
     sched_do_tick_resume(sched, cpu);
 
+    spin_unlock(lock);
+
     rcu_read_unlock(&sched_res_rculock);
 }
 
-- 
2.16.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.