Commit 373c84d2 authored by Robert Love's avatar Robert Love Committed by Linus Torvalds

[PATCH] make smp.c preempt-safe

The attached patch cleans up some per-CPU code in arch/i386/kernel/smp.c
that could be problematic under preemption.

The first I solve with the new get_cpu interface, for the second two I
explicitly disable preemption.  I also changed 1 to 1UL in the shift to
properly match the type.
parent 5e40a79f
...@@ -359,10 +359,12 @@ static void inline leave_mm (unsigned long cpu) ...@@ -359,10 +359,12 @@ static void inline leave_mm (unsigned long cpu)
asmlinkage void smp_invalidate_interrupt (void) asmlinkage void smp_invalidate_interrupt (void)
{ {
unsigned long cpu = smp_processor_id(); unsigned long cpu;
cpu = get_cpu();
if (!test_bit(cpu, &flush_cpumask)) if (!test_bit(cpu, &flush_cpumask))
return; goto out;
/* /*
* This was a BUG() but until someone can quote me the * This was a BUG() but until someone can quote me the
* line from the intel manual that guarantees an IPI to * line from the intel manual that guarantees an IPI to
...@@ -383,6 +385,9 @@ asmlinkage void smp_invalidate_interrupt (void) ...@@ -383,6 +385,9 @@ asmlinkage void smp_invalidate_interrupt (void)
} }
ack_APIC_irq(); ack_APIC_irq();
clear_bit(cpu, &flush_cpumask); clear_bit(cpu, &flush_cpumask);
out:
put_cpu();
} }
static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm, static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm,
...@@ -432,16 +437,23 @@ static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm, ...@@ -432,16 +437,23 @@ static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm,
void flush_tlb_current_task(void) void flush_tlb_current_task(void)
{ {
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id()); unsigned long cpu_mask;
preempt_disable();
cpu_mask = mm->cpu_vm_mask & ~(1UL << smp_processor_id());
local_flush_tlb(); local_flush_tlb();
if (cpu_mask) if (cpu_mask)
flush_tlb_others(cpu_mask, mm, FLUSH_ALL); flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
preempt_enable();
} }
void flush_tlb_mm (struct mm_struct * mm) void flush_tlb_mm (struct mm_struct * mm)
{ {
unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id()); unsigned long cpu_mask;
preempt_disable();
cpu_mask = mm->cpu_vm_mask & ~(1UL << smp_processor_id());
if (current->active_mm == mm) { if (current->active_mm == mm) {
if (current->mm) if (current->mm)
...@@ -451,12 +463,17 @@ void flush_tlb_mm (struct mm_struct * mm) ...@@ -451,12 +463,17 @@ void flush_tlb_mm (struct mm_struct * mm)
} }
if (cpu_mask) if (cpu_mask)
flush_tlb_others(cpu_mask, mm, FLUSH_ALL); flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
preempt_enable();
} }
void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
{ {
struct mm_struct *mm = vma->vm_mm; struct mm_struct *mm = vma->vm_mm;
unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id()); unsigned long cpu_mask;
preempt_disable();
cpu_mask = mm->cpu_vm_mask & ~(1UL << smp_processor_id());
if (current->active_mm == mm) { if (current->active_mm == mm) {
if(current->mm) if(current->mm)
...@@ -467,6 +484,8 @@ void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) ...@@ -467,6 +484,8 @@ void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
if (cpu_mask) if (cpu_mask)
flush_tlb_others(cpu_mask, mm, va); flush_tlb_others(cpu_mask, mm, va);
preempt_enable();
} }
static inline void do_flush_tlb_all_local(void) static inline void do_flush_tlb_all_local(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment