summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2012-10-08 07:54:32 +0200
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-10-09 14:17:01 +0200
commitfc7e48aad35bf98c84cf21aed5c2f100c5ce009b (patch)
tree1d33f49ac9705e1939cbe122d5aafb57aa7af07a /arch
parentc972cc60c23f5a6309292bfcc91a441743ba027e (diff)
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 <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/s390/mm/vmem.c16
1 files changed, 12 insertions, 4 deletions
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;