aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/mm/tlb.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 3b91c981a27f..184a02a4d871 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -318,12 +318,42 @@ void flush_tlb_mm(struct mm_struct *mm)
318 318
319#define FLUSHALL_BAR 16 319#define FLUSHALL_BAR 16
320 320
321#ifdef CONFIG_TRANSPARENT_HUGEPAGE
322static inline unsigned long has_large_page(struct mm_struct *mm,
323 unsigned long start, unsigned long end)
324{
325 pgd_t *pgd;
326 pud_t *pud;
327 pmd_t *pmd;
328 unsigned long addr = ALIGN(start, HPAGE_SIZE);
329 for (; addr < end; addr += HPAGE_SIZE) {
330 pgd = pgd_offset(mm, addr);
331 if (likely(!pgd_none(*pgd))) {
332 pud = pud_offset(pgd, addr);
333 if (likely(!pud_none(*pud))) {
334 pmd = pmd_offset(pud, addr);
335 if (likely(!pmd_none(*pmd)))
336 if (pmd_large(*pmd))
337 return addr;
338 }
339 }
340 }
341 return 0;
342}
343#else
344static inline unsigned long has_large_page(struct mm_struct *mm,
345 unsigned long start, unsigned long end)
346{
347 return 0;
348}
349#endif
321void flush_tlb_range(struct vm_area_struct *vma, 350void flush_tlb_range(struct vm_area_struct *vma,
322 unsigned long start, unsigned long end) 351 unsigned long start, unsigned long end)
323{ 352{
324 struct mm_struct *mm; 353 struct mm_struct *mm;
325 354
326 if (!cpu_has_invlpg || vma->vm_flags & VM_HUGETLB) { 355 if (!cpu_has_invlpg || vma->vm_flags & VM_HUGETLB) {
356flush_all:
327 flush_tlb_mm(vma->vm_mm); 357 flush_tlb_mm(vma->vm_mm);
328 return; 358 return;
329 } 359 }
@@ -346,6 +376,10 @@ void flush_tlb_range(struct vm_area_struct *vma,
346 if ((end - start)/PAGE_SIZE > act_entries/FLUSHALL_BAR) 376 if ((end - start)/PAGE_SIZE > act_entries/FLUSHALL_BAR)
347 local_flush_tlb(); 377 local_flush_tlb();
348 else { 378 else {
379 if (has_large_page(mm, start, end)) {
380 preempt_enable();
381 goto flush_all;
382 }
349 for (addr = start; addr < end; 383 for (addr = start; addr < end;
350 addr += PAGE_SIZE) 384 addr += PAGE_SIZE)
351 __flush_tlb_single(addr); 385 __flush_tlb_single(addr);