Commit 20167d34 authored by Jan Beulich's avatar Jan Beulich Committed by Ingo Molnar

x86-64: Fix accounting in kernel_physical_mapping_init()

When finding a present and acceptable 2M/1G mapping, the number
of pages mapped this way shouldn't be incremented (as it was
already incremented when the earlier part of the mapping was
established). Instead, last_map_addr needs to be updated in this
case.

Further, address increments were wrong in one place each in both
phys_pmd_init() and phys_pud_init() (lacking the aligning down
to the respective page boundary).

As we're now doing the same calculation several times, fold it
into a single instance using a local variable (matching how
kernel_physical_mapping_init() itself does it at the PGD level).

Observed during code inspection, not because of an actual
problem.
Signed-off-by: default avatarJan Beulich <jbeulich@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/4FB3C27202000078000841A0@nat28.tlf.novell.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 3e7f3db0
...@@ -408,12 +408,12 @@ static unsigned long __meminit ...@@ -408,12 +408,12 @@ static unsigned long __meminit
phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end, phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
unsigned long page_size_mask, pgprot_t prot) unsigned long page_size_mask, pgprot_t prot)
{ {
unsigned long pages = 0; unsigned long pages = 0, next;
unsigned long last_map_addr = end; unsigned long last_map_addr = end;
int i = pmd_index(address); int i = pmd_index(address);
for (; i < PTRS_PER_PMD; i++, address += PMD_SIZE) { for (; i < PTRS_PER_PMD; i++, address = next) {
unsigned long pte_phys; unsigned long pte_phys;
pmd_t *pmd = pmd_page + pmd_index(address); pmd_t *pmd = pmd_page + pmd_index(address);
pte_t *pte; pte_t *pte;
...@@ -427,6 +427,8 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end, ...@@ -427,6 +427,8 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
break; break;
} }
next = (address & PMD_MASK) + PMD_SIZE;
if (pmd_val(*pmd)) { if (pmd_val(*pmd)) {
if (!pmd_large(*pmd)) { if (!pmd_large(*pmd)) {
spin_lock(&init_mm.page_table_lock); spin_lock(&init_mm.page_table_lock);
...@@ -450,7 +452,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end, ...@@ -450,7 +452,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
* attributes. * attributes.
*/ */
if (page_size_mask & (1 << PG_LEVEL_2M)) { if (page_size_mask & (1 << PG_LEVEL_2M)) {
pages++; last_map_addr = next;
continue; continue;
} }
new_prot = pte_pgprot(pte_clrhuge(*(pte_t *)pmd)); new_prot = pte_pgprot(pte_clrhuge(*(pte_t *)pmd));
...@@ -463,7 +465,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end, ...@@ -463,7 +465,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
pfn_pte(address >> PAGE_SHIFT, pfn_pte(address >> PAGE_SHIFT,
__pgprot(pgprot_val(prot) | _PAGE_PSE))); __pgprot(pgprot_val(prot) | _PAGE_PSE)));
spin_unlock(&init_mm.page_table_lock); spin_unlock(&init_mm.page_table_lock);
last_map_addr = (address & PMD_MASK) + PMD_SIZE; last_map_addr = next;
continue; continue;
} }
...@@ -483,11 +485,11 @@ static unsigned long __meminit ...@@ -483,11 +485,11 @@ static unsigned long __meminit
phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
unsigned long page_size_mask) unsigned long page_size_mask)
{ {
unsigned long pages = 0; unsigned long pages = 0, next;
unsigned long last_map_addr = end; unsigned long last_map_addr = end;
int i = pud_index(addr); int i = pud_index(addr);
for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE) { for (; i < PTRS_PER_PUD; i++, addr = next) {
unsigned long pmd_phys; unsigned long pmd_phys;
pud_t *pud = pud_page + pud_index(addr); pud_t *pud = pud_page + pud_index(addr);
pmd_t *pmd; pmd_t *pmd;
...@@ -496,8 +498,9 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, ...@@ -496,8 +498,9 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
if (addr >= end) if (addr >= end)
break; break;
if (!after_bootmem && next = (addr & PUD_MASK) + PUD_SIZE;
!e820_any_mapped(addr, addr+PUD_SIZE, 0)) {
if (!after_bootmem && !e820_any_mapped(addr, next, 0)) {
set_pud(pud, __pud(0)); set_pud(pud, __pud(0));
continue; continue;
} }
...@@ -524,7 +527,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, ...@@ -524,7 +527,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
* attributes. * attributes.
*/ */
if (page_size_mask & (1 << PG_LEVEL_1G)) { if (page_size_mask & (1 << PG_LEVEL_1G)) {
pages++; last_map_addr = next;
continue; continue;
} }
prot = pte_pgprot(pte_clrhuge(*(pte_t *)pud)); prot = pte_pgprot(pte_clrhuge(*(pte_t *)pud));
...@@ -536,7 +539,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, ...@@ -536,7 +539,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
set_pte((pte_t *)pud, set_pte((pte_t *)pud,
pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE)); pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
spin_unlock(&init_mm.page_table_lock); spin_unlock(&init_mm.page_table_lock);
last_map_addr = (addr & PUD_MASK) + PUD_SIZE; last_map_addr = next;
continue; continue;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment