diff options
-rw-r--r-- | arch/x86/xen/enlighten.c | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 225ffdc3c4c..9c808693afa 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -125,6 +125,19 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info; | |||
125 | */ | 125 | */ |
126 | static int have_vcpu_info_placement = 1; | 126 | static int have_vcpu_info_placement = 1; |
127 | 127 | ||
128 | struct tls_descs { | ||
129 | struct desc_struct desc[3]; | ||
130 | }; | ||
131 | |||
132 | /* | ||
133 | * Updating the 3 TLS descriptors in the GDT on every task switch is | ||
134 | * surprisingly expensive so we avoid updating them if they haven't | ||
135 | * changed. Since Xen writes different descriptors than the one | ||
136 | * passed in the update_descriptor hypercall we keep shadow copies to | ||
137 | * compare against. | ||
138 | */ | ||
139 | static DEFINE_PER_CPU(struct tls_descs, shadow_tls_desc); | ||
140 | |||
128 | static void clamp_max_cpus(void) | 141 | static void clamp_max_cpus(void) |
129 | { | 142 | { |
130 | #ifdef CONFIG_SMP | 143 | #ifdef CONFIG_SMP |
@@ -548,9 +561,19 @@ static inline bool desc_equal(const struct desc_struct *d1, | |||
548 | static void load_TLS_descriptor(struct thread_struct *t, | 561 | static void load_TLS_descriptor(struct thread_struct *t, |
549 | unsigned int cpu, unsigned int i) | 562 | unsigned int cpu, unsigned int i) |
550 | { | 563 | { |
551 | struct desc_struct *gdt = get_cpu_gdt_table(cpu); | 564 | struct desc_struct *shadow = &per_cpu(shadow_tls_desc, cpu).desc[i]; |
552 | xmaddr_t maddr = arbitrary_virt_to_machine(&gdt[GDT_ENTRY_TLS_MIN+i]); | 565 | struct desc_struct *gdt; |
553 | struct multicall_space mc = __xen_mc_entry(0); | 566 | xmaddr_t maddr; |
567 | struct multicall_space mc; | ||
568 | |||
569 | if (desc_equal(shadow, &t->tls_array[i])) | ||
570 | return; | ||
571 | |||
572 | *shadow = t->tls_array[i]; | ||
573 | |||
574 | gdt = get_cpu_gdt_table(cpu); | ||
575 | maddr = arbitrary_virt_to_machine(&gdt[GDT_ENTRY_TLS_MIN+i]); | ||
576 | mc = __xen_mc_entry(0); | ||
554 | 577 | ||
555 | MULTI_update_descriptor(mc.mc, maddr.maddr, t->tls_array[i]); | 578 | MULTI_update_descriptor(mc.mc, maddr.maddr, t->tls_array[i]); |
556 | } | 579 | } |