Commit 9da61aef0fd5b17dd4bf4baf33db12c470def774
Committed by
Linus Torvalds
1 parent
27a85ef1b8
Exists in
master
and in
4 other branches
[PATCH] hugepage: Fix hugepage logic in free_pgtables()
free_pgtables() has special logic to call hugetlb_free_pgd_range() instead of the normal free_pgd_range() on hugepage VMAs. However, the test it uses to do so is incorrect: it calls is_hugepage_only_range on a hugepage sized range at the start of the vma. is_hugepage_only_range() will return true if the given range has any intersection with a hugepage address region, and in this case the given region need not be hugepage aligned. So, for example, this test can return true if called on, say, a 4k VMA immediately preceding a (nicely aligned) hugepage VMA. At present we get away with this because the powerpc version of hugetlb_free_pgd_range() is just a call to free_pgd_range(). On ia64 (the only other arch with a non-trivial is_hugepage_only_range()) we get away with it for a different reason; the hugepage area is not contiguous with the rest of the user address space, and VMAs are not permitted in between, so the test can't return a false positive there. Nonetheless this should be fixed. We do that in the patch below by replacing the is_hugepage_only_range() test with an explicit test of the VMA using is_vm_hugetlb_page(). This in turn changes behaviour for platforms where is_hugepage_only_range() returns false always (everything except powerpc and ia64). We address this by ensuring that hugetlb_free_pgd_range() is defined to be identical to free_pgd_range() (instead of a no-op) on everything except ia64. Even so, it will prevent some otherwise possible coalescing of calls down to free_pgd_range(). Since this only happens for hugepage VMAs, removing this small optimization seems unlikely to cause any trouble. This patch causes no regressions on the libhugetlbfs testsuite - ppc64 POWER5 (8-way), ppc64 G5 (2-way) and i386 Pentium M (UP). Signed-off-by: David Gibson <dwg@au1.ibm.com> Cc: William Lee Irwin III <wli@holomorphy.com> Acked-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 4 changed files with 8 additions and 12 deletions Side-by-side Diff
include/asm-ia64/page.h
include/asm-powerpc/pgtable.h
... | ... | @@ -468,11 +468,6 @@ |
468 | 468 | |
469 | 469 | extern void paging_init(void); |
470 | 470 | |
471 | -#ifdef CONFIG_HUGETLB_PAGE | |
472 | -#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) \ | |
473 | - free_pgd_range(tlb, addr, end, floor, ceiling) | |
474 | -#endif | |
475 | - | |
476 | 471 | /* |
477 | 472 | * This gets called at the end of handling a page fault, when |
478 | 473 | * the kernel has put a new PTE into the page table for the process. |
include/linux/hugetlb.h
... | ... | @@ -43,10 +43,12 @@ |
43 | 43 | |
44 | 44 | #ifndef ARCH_HAS_HUGEPAGE_ONLY_RANGE |
45 | 45 | #define is_hugepage_only_range(mm, addr, len) 0 |
46 | -#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) \ | |
47 | - do { } while (0) | |
48 | 46 | #endif |
49 | 47 | |
48 | +#ifndef ARCH_HAS_HUGETLB_FREE_PGD_RANGE | |
49 | +#define hugetlb_free_pgd_range free_pgd_range | |
50 | +#endif | |
51 | + | |
50 | 52 | #ifndef ARCH_HAS_PREPARE_HUGEPAGE_RANGE |
51 | 53 | #define prepare_hugepage_range(addr, len) \ |
52 | 54 | is_aligned_hugepage_range(addr, len) |
... | ... | @@ -93,8 +95,7 @@ |
93 | 95 | #define prepare_hugepage_range(addr, len) (-EINVAL) |
94 | 96 | #define pmd_huge(x) 0 |
95 | 97 | #define is_hugepage_only_range(mm, addr, len) 0 |
96 | -#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) \ | |
97 | - do { } while (0) | |
98 | +#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; }) | |
98 | 99 | #define hugetlb_fault(mm, vma, addr, write) ({ BUG(); 0; }) |
99 | 100 | |
100 | 101 | #define hugetlb_change_protection(vma, address, end, newprot) |
mm/memory.c
... | ... | @@ -277,7 +277,7 @@ |
277 | 277 | anon_vma_unlink(vma); |
278 | 278 | unlink_file_vma(vma); |
279 | 279 | |
280 | - if (is_hugepage_only_range(vma->vm_mm, addr, HPAGE_SIZE)) { | |
280 | + if (is_vm_hugetlb_page(vma)) { | |
281 | 281 | hugetlb_free_pgd_range(tlb, addr, vma->vm_end, |
282 | 282 | floor, next? next->vm_start: ceiling); |
283 | 283 | } else { |
... | ... | @@ -285,8 +285,7 @@ |
285 | 285 | * Optimization: gather nearby vmas into one call down |
286 | 286 | */ |
287 | 287 | while (next && next->vm_start <= vma->vm_end + PMD_SIZE |
288 | - && !is_hugepage_only_range(vma->vm_mm, next->vm_start, | |
289 | - HPAGE_SIZE)) { | |
288 | + && !is_vm_hugetlb_page(vma)) { | |
290 | 289 | vma = next; |
291 | 290 | next = vma->vm_next; |
292 | 291 | anon_vma_unlink(vma); |