diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2012-10-08 01:54:32 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-10-09 08:17:01 -0400 |
commit | fc7e48aad35bf98c84cf21aed5c2f100c5ce009b (patch) | |
tree | 1d33f49ac9705e1939cbe122d5aafb57aa7af07a /arch/s390 | |
parent | c972cc60c23f5a6309292bfcc91a441743ba027e (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/s390')
-rw-r--r-- | arch/s390/mm/vmem.c | 16 |
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) | |||
109 | pm_dir = pmd_offset(pu_dir, address); | 109 | pm_dir = pmd_offset(pu_dir, address); |
110 | 110 | ||
111 | #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) | 111 | #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) |
112 | if (MACHINE_HAS_EDAT1 && address && !(address & ~PMD_MASK) && | 112 | if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address && |
113 | (address + PMD_SIZE <= end)) { | 113 | !(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) { |
114 | pte_val(pte) |= _SEGMENT_ENTRY_LARGE; | 114 | pte_val(pte) |= _SEGMENT_ENTRY_LARGE; |
115 | pmd_val(*pm_dir) = pte_val(pte); | 115 | pmd_val(*pm_dir) = pte_val(pte); |
116 | address += PMD_SIZE; | 116 | address += PMD_SIZE; |
@@ -151,12 +151,20 @@ static void vmem_remove_range(unsigned long start, unsigned long size) | |||
151 | pte_val(pte) = _PAGE_TYPE_EMPTY; | 151 | pte_val(pte) = _PAGE_TYPE_EMPTY; |
152 | while (address < end) { | 152 | while (address < end) { |
153 | pg_dir = pgd_offset_k(address); | 153 | pg_dir = pgd_offset_k(address); |
154 | if (pgd_none(*pg_dir)) { | ||
155 | address += PGDIR_SIZE; | ||
156 | continue; | ||
157 | } | ||
154 | pu_dir = pud_offset(pg_dir, address); | 158 | pu_dir = pud_offset(pg_dir, address); |
155 | if (pud_none(*pu_dir)) | 159 | if (pud_none(*pu_dir)) { |
160 | address += PUD_SIZE; | ||
156 | continue; | 161 | continue; |
162 | } | ||
157 | pm_dir = pmd_offset(pu_dir, address); | 163 | pm_dir = pmd_offset(pu_dir, address); |
158 | if (pmd_none(*pm_dir)) | 164 | if (pmd_none(*pm_dir)) { |
165 | address += PMD_SIZE; | ||
159 | continue; | 166 | continue; |
167 | } | ||
160 | if (pmd_large(*pm_dir)) { | 168 | if (pmd_large(*pm_dir)) { |
161 | pmd_clear(pm_dir); | 169 | pmd_clear(pm_dir); |
162 | address += PMD_SIZE; | 170 | address += PMD_SIZE; |