Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86, mm: do not leak page->ptl for pmd page tables

There are two code paths how page with pmd page table can be freed:
pmd_free() and pmd_free_tlb().

I've missed the second one and didn't add page table destructor call
there. It leads to leak of page->ptl for pmd page tables, if
dynamically allocated page->ptl is in use.

The patch adds the missed destructor and modifies documentation
accordingly.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Reported-by: Andrey Vagin <avagin@openvz.org>
Tested-by: Andrey Vagin <avagin@openvz.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Kirill A. Shutemov and committed by
Linus Torvalds
c283610e 3a72660b

+6 -4
+3 -3
Documentation/vm/split_page_table_lock
··· 63 63 PMD split lock enabling requires pgtable_pmd_page_ctor() call on PMD table 64 64 allocation and pgtable_pmd_page_dtor() on freeing. 65 65 66 - Allocation usually happens in pmd_alloc_one(), freeing in pmd_free(), but 67 - make sure you cover all PMD table allocation / freeing paths: i.e X86_PAE 68 - preallocate few PMDs on pgd_alloc(). 66 + Allocation usually happens in pmd_alloc_one(), freeing in pmd_free() and 67 + pmd_free_tlb(), but make sure you cover all PMD table allocation / freeing 68 + paths: i.e X86_PAE preallocate few PMDs on pgd_alloc(). 69 69 70 70 With everything in place you can set CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK. 71 71
+3 -1
arch/x86/mm/pgtable.c
··· 61 61 #if PAGETABLE_LEVELS > 2 62 62 void ___pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd) 63 63 { 64 + struct page *page = virt_to_page(pmd); 64 65 paravirt_release_pmd(__pa(pmd) >> PAGE_SHIFT); 65 66 /* 66 67 * NOTE! For PAE, any changes to the top page-directory-pointer-table ··· 70 69 #ifdef CONFIG_X86_PAE 71 70 tlb->need_flush_all = 1; 72 71 #endif 73 - tlb_remove_page(tlb, virt_to_page(pmd)); 72 + pgtable_pmd_page_dtor(page); 73 + tlb_remove_page(tlb, page); 74 74 } 75 75 76 76 #if PAGETABLE_LEVELS > 3