diff options
-rw-r--r-- | arch/x86/mm/tlb.c | 34 |
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 | ||
322 | static 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 | ||
344 | static inline unsigned long has_large_page(struct mm_struct *mm, | ||
345 | unsigned long start, unsigned long end) | ||
346 | { | ||
347 | return 0; | ||
348 | } | ||
349 | #endif | ||
321 | void flush_tlb_range(struct vm_area_struct *vma, | 350 | void 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) { |
356 | flush_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); |