diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c index 2e43f8029f..de5a6b1a57 100644 --- a/xen/common/sched/core.c +++ b/xen/common/sched/core.c @@ -308,17 +308,26 @@ void vcpu_runstate_get(const struct vcpu *v, { spinlock_t *lock; s_time_t delta; + struct sched_unit *unit; rcu_read_lock(&sched_res_rculock); - lock = likely(v == current) ? NULL : unit_schedule_lock_irq(v->sched_unit); + /* + * Be careful in case of an idle vcpu: the assignment to a unit might + * change even with the scheduling lock held, so be sure to use the + * correct unit for locking in order to avoid triggering an ASSERT() in + * the unlock function. + */ + unit = is_idle_vcpu(v) ? get_sched_res(v->processor)->sched_unit_idle + : v->sched_unit; + lock = likely(v == current) ? NULL : unit_schedule_lock_irq(unit); memcpy(runstate, &v->runstate, sizeof(*runstate)); delta = NOW() - runstate->state_entry_time; if ( delta > 0 ) runstate->time[runstate->state] += delta; if ( unlikely(lock != NULL) ) - unit_schedule_unlock_irq(lock, v->sched_unit); + unit_schedule_unlock_irq(lock, unit); rcu_read_unlock(&sched_res_rculock); }