aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/xen/mmu.c
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@xensource.com>2007-10-16 14:51:30 -0400
committerJeremy Fitzhardinge <jeremy@goop.org>2007-10-16 14:51:30 -0400
commit9f79991d4186089e228274196413572cc000143b (patch)
treecd50a308dca1d650ab77c7019ff3bdcadc7ab0ea /arch/x86/xen/mmu.c
parent91e0c5f3dad47838cb2ecc1865ce789a0b7182b1 (diff)
xen: deal with stale cr3 values when unpinning pagetables
When a pagetable is no longer in use, it must be unpinned so that its pages can be freed. However, this is only possible if there are no stray uses of the pagetable. The code currently deals with all the usual cases, but there's a rare case where a vcpu is changing cr3, but is doing so lazily, and the change hasn't actually happened by the time the pagetable is unpinned, even though it appears to have been completed. This change adds a second per-cpu cr3 variable - xen_current_cr3 - which tracks the actual state of the vcpu cr3. It is only updated once the actual hypercall to set cr3 has been completed. Other processors wishing to unpin a pagetable can check other vcpu's xen_current_cr3 values to see if any cross-cpu IPIs are needed to clean things up. [ Stable folks: 2.6.23 bugfix ] Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com> Cc: Stable Kernel <stable@kernel.org>
Diffstat (limited to 'arch/x86/xen/mmu.c')
-rw-r--r--arch/x86/xen/mmu.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index c4a391f88980..72f08ab43a4d 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -514,20 +514,43 @@ static void drop_other_mm_ref(void *info)
514 514
515 if (__get_cpu_var(cpu_tlbstate).active_mm == mm) 515 if (__get_cpu_var(cpu_tlbstate).active_mm == mm)
516 leave_mm(smp_processor_id()); 516 leave_mm(smp_processor_id());
517
518 /* If this cpu still has a stale cr3 reference, then make sure
519 it has been flushed. */
520 if (x86_read_percpu(xen_current_cr3) == __pa(mm->pgd)) {
521 load_cr3(swapper_pg_dir);
522 arch_flush_lazy_cpu_mode();
523 }
517} 524}
518 525
519static void drop_mm_ref(struct mm_struct *mm) 526static void drop_mm_ref(struct mm_struct *mm)
520{ 527{
528 cpumask_t mask;
529 unsigned cpu;
530
521 if (current->active_mm == mm) { 531 if (current->active_mm == mm) {
522 if (current->mm == mm) 532 if (current->mm == mm)
523 load_cr3(swapper_pg_dir); 533 load_cr3(swapper_pg_dir);
524 else 534 else
525 leave_mm(smp_processor_id()); 535 leave_mm(smp_processor_id());
536 arch_flush_lazy_cpu_mode();
537 }
538
539 /* Get the "official" set of cpus referring to our pagetable. */
540 mask = mm->cpu_vm_mask;
541
542 /* It's possible that a vcpu may have a stale reference to our
543 cr3, because its in lazy mode, and it hasn't yet flushed
544 its set of pending hypercalls yet. In this case, we can
545 look at its actual current cr3 value, and force it to flush
546 if needed. */
547 for_each_online_cpu(cpu) {
548 if (per_cpu(xen_current_cr3, cpu) == __pa(mm->pgd))
549 cpu_set(cpu, mask);
526 } 550 }
527 551
528 if (!cpus_empty(mm->cpu_vm_mask)) 552 if (!cpus_empty(mask))
529 xen_smp_call_function_mask(mm->cpu_vm_mask, drop_other_mm_ref, 553 xen_smp_call_function_mask(mask, drop_other_mm_ref, mm, 1);
530 mm, 1);
531} 554}
532#else 555#else
533static void drop_mm_ref(struct mm_struct *mm) 556static void drop_mm_ref(struct mm_struct *mm)