From fc7e48aad35bf98c84cf21aed5c2f100c5ce009b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 8 Oct 2012 07:54:32 +0200 Subject: s390/mm,vmem: fix vmem_add_mem()/vmem_remove_range() vmem_add_mem() should only then insert a large page if pmd_none() is true for the specific entry. We might have a leftover from a previous mapping. In addition make vmem_remove_range()'s page table walk code more complete and fix a couple of potential endless loops (which can never happen :). Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/vmem.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'arch/s390/mm') diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index d402b19f1df2..387c7c60b5b8 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -109,8 +109,8 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) pm_dir = pmd_offset(pu_dir, address); #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) - if (MACHINE_HAS_EDAT1 && address && !(address & ~PMD_MASK) && - (address + PMD_SIZE <= end)) { + if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address && + !(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) { pte_val(pte) |= _SEGMENT_ENTRY_LARGE; pmd_val(*pm_dir) = pte_val(pte); address += PMD_SIZE; @@ -151,12 +151,20 @@ static void vmem_remove_range(unsigned long start, unsigned long size) pte_val(pte) = _PAGE_TYPE_EMPTY; while (address < end) { pg_dir = pgd_offset_k(address); + if (pgd_none(*pg_dir)) { + address += PGDIR_SIZE; + continue; + } pu_dir = pud_offset(pg_dir, address); - if (pud_none(*pu_dir)) + if (pud_none(*pu_dir)) { + address += PUD_SIZE; continue; + } pm_dir = pmd_offset(pu_dir, address); - if (pmd_none(*pm_dir)) + if (pmd_none(*pm_dir)) { + address += PMD_SIZE; continue; + } if (pmd_large(*pm_dir)) { pmd_clear(pm_dir); address += PMD_SIZE; -- cgit v1.2.3-55-g7522