aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/wait.c
diff options
context:
space:
mode:
authorKeir Fraser <keir@xen.org>2011-11-24 15:50:08 +0000
committerKeir Fraser <keir@xen.org>2011-11-24 15:50:08 +0000
commit44fc6177ee75cf11fb5cf4079f9482acb634055f (patch)
treef1b89b1938fae35e98f12a4b9b8bb155fe16d6fb /xen/common/wait.c
parent9333781f509b67bf5c08a790664a660bab3dc819 (diff)
downloadxen-44fc6177ee75cf11fb5cf4079f9482acb634055f.tar.gz
xen-44fc6177ee75cf11fb5cf4079f9482acb634055f.tar.bz2
xen-44fc6177ee75cf11fb5cf4079f9482acb634055f.zip
x86/waitqueue: Because we have per-cpu stacks, we must wake up on teh
same cpu that we slept on. Otherwise stack references are bogus on wakeup. Signed-off-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/common/wait.c')
-rw-r--r--xen/common/wait.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/xen/common/wait.c b/xen/common/wait.c
index b125dc5be2..d4feecb56e 100644
--- a/xen/common/wait.c
+++ b/xen/common/wait.c
@@ -34,6 +34,8 @@ struct waitqueue_vcpu {
*/
void *esp;
char *stack;
+ cpumask_t saved_affinity;
+ unsigned int wakeup_cpu;
#endif
};
@@ -106,9 +108,19 @@ void wake_up(struct waitqueue_head *wq)
static void __prepare_to_wait(struct waitqueue_vcpu *wqv)
{
char *cpu_info = (char *)get_cpu_info();
+ struct vcpu *curr = current;
ASSERT(wqv->esp == 0);
+ /* Save current VCPU affinity; force wakeup on *this* CPU only. */
+ wqv->wakeup_cpu = smp_processor_id();
+ cpumask_copy(&wqv->saved_affinity, curr->cpu_affinity);
+ if ( vcpu_set_affinity(curr, cpumask_of(wqv->wakeup_cpu)) )
+ {
+ gdprintk(XENLOG_ERR, "Unable to set vcpu affinity\n");
+ domain_crash_synchronous();
+ }
+
asm volatile (
#ifdef CONFIG_X86_64
"push %%rax; push %%rbx; push %%rcx; push %%rdx; push %%rdi; "
@@ -144,6 +156,7 @@ static void __prepare_to_wait(struct waitqueue_vcpu *wqv)
static void __finish_wait(struct waitqueue_vcpu *wqv)
{
wqv->esp = NULL;
+ (void)vcpu_set_affinity(current, &wqv->saved_affinity);
}
void check_wakeup_from_wait(void)
@@ -155,6 +168,20 @@ void check_wakeup_from_wait(void)
if ( likely(wqv->esp == NULL) )
return;
+ /* Check if we woke up on the wrong CPU. */
+ if ( unlikely(smp_processor_id() != wqv->wakeup_cpu) )
+ {
+ /* Re-set VCPU affinity and re-enter the scheduler. */
+ struct vcpu *curr = current;
+ cpumask_copy(&wqv->saved_affinity, curr->cpu_affinity);
+ if ( vcpu_set_affinity(curr, cpumask_of(wqv->wakeup_cpu)) )
+ {
+ gdprintk(XENLOG_ERR, "Unable to set vcpu affinity\n");
+ domain_crash_synchronous();
+ }
+ wait(); /* takes us back into the scheduler */
+ }
+
asm volatile (
"mov %1,%%"__OP"sp; rep movsb; jmp *(%%"__OP"sp)"
: : "S" (wqv->stack), "D" (wqv->esp),