mirror of
https://github.com/xen-project/xen.git
synced 2026-10-30 03:00:05 +01:00
Fix context_switch(). It is necessary to set_current() and
then check curr_vcpu all with interrupts disabled. This in turn requires us to hoist the heck of next's vcpu_dirty_cpumask as sending the flush IPI needs us to have interrupts enabled to avoid deadlock. Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
1 parent
1676162e17
commit
89e23317ba
1 file changed
+21
-11
+21
-11
@@ -689,6 +689,9 @@ static void __context_switch(void)
|
||||
struct vcpu *p = percpu_ctxt[cpu].curr_vcpu;
|
||||
struct vcpu *n = current;
|
||||
|
||||
ASSERT(p != n);
|
||||
ASSERT(cpus_empty(n->vcpu_dirty_cpumask));
|
||||
|
||||
if ( !is_idle_domain(p->domain) )
|
||||
{
|
||||
memcpy(&p->arch.guest_context.user_regs,
|
||||
@@ -748,24 +751,31 @@ static void __context_switch(void)
|
||||
void context_switch(struct vcpu *prev, struct vcpu *next)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
cpumask_t dirty_mask = next->vcpu_dirty_cpumask;
|
||||
|
||||
ASSERT(local_irq_is_enabled());
|
||||
|
||||
/* Allow at most one CPU at a time to be dirty. */
|
||||
ASSERT(cpus_weight(dirty_mask) <= 1);
|
||||
if ( unlikely(!cpu_isset(cpu, dirty_mask) && !cpus_empty(dirty_mask)) )
|
||||
{
|
||||
/* Other cpus call __sync_lazy_execstate from flush ipi handler. */
|
||||
flush_tlb_mask(dirty_mask);
|
||||
}
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
set_current(next);
|
||||
|
||||
if ( (percpu_ctxt[cpu].curr_vcpu != next) &&
|
||||
!is_idle_domain(next->domain) )
|
||||
if ( (percpu_ctxt[cpu].curr_vcpu == next) || is_idle_domain(next->domain) )
|
||||
{
|
||||
local_irq_enable();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This may happen if next has been migrated by the scheduler. */
|
||||
if ( unlikely(!cpus_empty(next->vcpu_dirty_cpumask)) )
|
||||
{
|
||||
ASSERT(!cpu_isset(cpu, next->vcpu_dirty_cpumask));
|
||||
sync_vcpu_execstate(next);
|
||||
ASSERT(cpus_empty(next->vcpu_dirty_cpumask));
|
||||
}
|
||||
|
||||
local_irq_disable();
|
||||
__context_switch();
|
||||
|
||||
/* Re-enable interrupts before restoring state which may fault. */
|
||||
local_irq_enable();
|
||||
|
||||
if ( VMX_DOMAIN(next) )
|
||||
|
||||