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

x86/mm: Add support for gbpages to kernel_ident_mapping_init()

Kernel identity mappings on x86-64 kernels are created in two
ways: by the early x86 boot code, or by kernel_ident_mapping_init().

Native kernels (which is the dominant usecase) use the former,
but the kexec and the hibernation code uses kernel_ident_mapping_init().

There's a subtle difference between these two ways of how identity
mappings are created, the current kernel_ident_mapping_init() code
creates identity mappings always using 2MB page(PMD level) - while
the native kernel boot path also utilizes gbpages where available.

This difference is suboptimal both for performance and for memory
usage: kernel_ident_mapping_init() needs to allocate pages for the
page tables when creating the new identity mappings.

This patch adds 1GB page(PUD level) support to kernel_ident_mapping_init()
to address these concerns.

The primary advantage would be better TLB coverage/performance,
because we'd utilize 1GB TLBs instead of 2MB ones.

It is also useful for machines with large number of memory to
save paging structure allocations(around 4MB/TB using 2MB page)
when setting identity mappings for all the memory, after using
1GB page it will consume only 8KB/TB.

( Note that this change alone does not activate gbpages in kexec,
we are doing that in a separate patch. )

Signed-off-by: Xunlei Pang <xlpang@redhat.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: akpm@linux-foundation.org
Cc: kexec@lists.infradead.org
Link: http://lkml.kernel.org/r/1493862171-8799-1-git-send-email-xlpang@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Xunlei Pang and committed by
Ingo Molnar
66aad4fd 60854a12

+18 -5
+1 -1
arch/x86/boot/compressed/pagetable.c
··· 70 70 * Due to relocation, pointers must be assigned at run time not build time. 71 71 */ 72 72 static struct x86_mapping_info mapping_info = { 73 - .pmd_flag = __PAGE_KERNEL_LARGE_EXEC, 73 + .page_flag = __PAGE_KERNEL_LARGE_EXEC, 74 74 }; 75 75 76 76 /* Locates and clears a region for a new top level page table. */
+2 -1
arch/x86/include/asm/init.h
··· 4 4 struct x86_mapping_info { 5 5 void *(*alloc_pgt_page)(void *); /* allocate buf for page table */ 6 6 void *context; /* context for alloc_pgt_page */ 7 - unsigned long pmd_flag; /* page flag for PMD entry */ 7 + unsigned long page_flag; /* page flag for PMD or PUD entry */ 8 8 unsigned long offset; /* ident mapping offset */ 9 + bool direct_gbpages; /* PUD level 1GB page support */ 9 10 }; 10 11 11 12 int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
+1 -1
arch/x86/kernel/machine_kexec_64.c
··· 113 113 struct x86_mapping_info info = { 114 114 .alloc_pgt_page = alloc_pgt_page, 115 115 .context = image, 116 - .pmd_flag = __PAGE_KERNEL_LARGE_EXEC, 116 + .page_flag = __PAGE_KERNEL_LARGE_EXEC, 117 117 }; 118 118 unsigned long mstart, mend; 119 119 pgd_t *level4p;
+13 -1
arch/x86/mm/ident_map.c
··· 13 13 if (pmd_present(*pmd)) 14 14 continue; 15 15 16 - set_pmd(pmd, __pmd((addr - info->offset) | info->pmd_flag)); 16 + set_pmd(pmd, __pmd((addr - info->offset) | info->page_flag)); 17 17 } 18 18 } 19 19 ··· 29 29 next = (addr & PUD_MASK) + PUD_SIZE; 30 30 if (next > end) 31 31 next = end; 32 + 33 + if (info->direct_gbpages) { 34 + pud_t pudval; 35 + 36 + if (pud_present(*pud)) 37 + continue; 38 + 39 + addr &= PUD_MASK; 40 + pudval = __pud((addr - info->offset) | info->page_flag); 41 + set_pud(pud, pudval); 42 + continue; 43 + } 32 44 33 45 if (pud_present(*pud)) { 34 46 pmd = pmd_offset(pud, 0);
+1 -1
arch/x86/power/hibernate_64.c
··· 104 104 { 105 105 struct x86_mapping_info info = { 106 106 .alloc_pgt_page = alloc_pgt_page, 107 - .pmd_flag = __PAGE_KERNEL_LARGE_EXEC, 107 + .page_flag = __PAGE_KERNEL_LARGE_EXEC, 108 108 .offset = __PAGE_OFFSET, 109 109 }; 110 110 unsigned long mstart, mend;