diff options
Diffstat (limited to 'arch/x86/kernel/ldt.c')
-rw-r--r-- | arch/x86/kernel/ldt.c | 22 |
1 files changed, 14 insertions, 8 deletions
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index 0224c3637c73..eee32b43fee3 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c | |||
@@ -18,11 +18,12 @@ | |||
18 | #include <asm/ldt.h> | 18 | #include <asm/ldt.h> |
19 | #include <asm/desc.h> | 19 | #include <asm/desc.h> |
20 | #include <asm/mmu_context.h> | 20 | #include <asm/mmu_context.h> |
21 | #include <asm/syscalls.h> | ||
21 | 22 | ||
22 | #ifdef CONFIG_SMP | 23 | #ifdef CONFIG_SMP |
23 | static void flush_ldt(void *null) | 24 | static void flush_ldt(void *current_mm) |
24 | { | 25 | { |
25 | if (current->active_mm) | 26 | if (current->active_mm == current_mm) |
26 | load_LDT(¤t->active_mm->context); | 27 | load_LDT(¤t->active_mm->context); |
27 | } | 28 | } |
28 | #endif | 29 | #endif |
@@ -51,6 +52,8 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload) | |||
51 | memset(newldt + oldsize * LDT_ENTRY_SIZE, 0, | 52 | memset(newldt + oldsize * LDT_ENTRY_SIZE, 0, |
52 | (mincount - oldsize) * LDT_ENTRY_SIZE); | 53 | (mincount - oldsize) * LDT_ENTRY_SIZE); |
53 | 54 | ||
55 | paravirt_alloc_ldt(newldt, mincount); | ||
56 | |||
54 | #ifdef CONFIG_X86_64 | 57 | #ifdef CONFIG_X86_64 |
55 | /* CHECKME: Do we really need this ? */ | 58 | /* CHECKME: Do we really need this ? */ |
56 | wmb(); | 59 | wmb(); |
@@ -62,19 +65,18 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload) | |||
62 | 65 | ||
63 | if (reload) { | 66 | if (reload) { |
64 | #ifdef CONFIG_SMP | 67 | #ifdef CONFIG_SMP |
65 | cpumask_t mask; | ||
66 | |||
67 | preempt_disable(); | 68 | preempt_disable(); |
68 | load_LDT(pc); | 69 | load_LDT(pc); |
69 | mask = cpumask_of_cpu(smp_processor_id()); | 70 | if (!cpus_equal(current->mm->cpu_vm_mask, |
70 | if (!cpus_equal(current->mm->cpu_vm_mask, mask)) | 71 | cpumask_of_cpu(smp_processor_id()))) |
71 | smp_call_function(flush_ldt, NULL, 1, 1); | 72 | smp_call_function(flush_ldt, current->mm, 1); |
72 | preempt_enable(); | 73 | preempt_enable(); |
73 | #else | 74 | #else |
74 | load_LDT(pc); | 75 | load_LDT(pc); |
75 | #endif | 76 | #endif |
76 | } | 77 | } |
77 | if (oldsize) { | 78 | if (oldsize) { |
79 | paravirt_free_ldt(oldldt, oldsize); | ||
78 | if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE) | 80 | if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE) |
79 | vfree(oldldt); | 81 | vfree(oldldt); |
80 | else | 82 | else |
@@ -86,10 +88,13 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload) | |||
86 | static inline int copy_ldt(mm_context_t *new, mm_context_t *old) | 88 | static inline int copy_ldt(mm_context_t *new, mm_context_t *old) |
87 | { | 89 | { |
88 | int err = alloc_ldt(new, old->size, 0); | 90 | int err = alloc_ldt(new, old->size, 0); |
91 | int i; | ||
89 | 92 | ||
90 | if (err < 0) | 93 | if (err < 0) |
91 | return err; | 94 | return err; |
92 | memcpy(new->ldt, old->ldt, old->size * LDT_ENTRY_SIZE); | 95 | |
96 | for(i = 0; i < old->size; i++) | ||
97 | write_ldt_entry(new->ldt, i, old->ldt + i * LDT_ENTRY_SIZE); | ||
93 | return 0; | 98 | return 0; |
94 | } | 99 | } |
95 | 100 | ||
@@ -126,6 +131,7 @@ void destroy_context(struct mm_struct *mm) | |||
126 | if (mm == current->active_mm) | 131 | if (mm == current->active_mm) |
127 | clear_LDT(); | 132 | clear_LDT(); |
128 | #endif | 133 | #endif |
134 | paravirt_free_ldt(mm->context.ldt, mm->context.size); | ||
129 | if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE) | 135 | if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE) |
130 | vfree(mm->context.ldt); | 136 | vfree(mm->context.ldt); |
131 | else | 137 | else |