diff options
-rw-r--r-- | arch/x86/include/asm/pgtable_64.h | 3 | ||||
-rw-r--r-- | arch/x86/mm/fault.c | 2 | ||||
-rw-r--r-- | arch/x86/mm/init_64.c | 27 |
3 files changed, 22 insertions, 10 deletions
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h index 5be9063545d2..809abb335627 100644 --- a/arch/x86/include/asm/pgtable_64.h +++ b/arch/x86/include/asm/pgtable_64.h | |||
@@ -115,7 +115,8 @@ static inline void native_pgd_clear(pgd_t *pgd) | |||
115 | native_set_pgd(pgd, native_make_pgd(0)); | 115 | native_set_pgd(pgd, native_make_pgd(0)); |
116 | } | 116 | } |
117 | 117 | ||
118 | extern void sync_global_pgds(unsigned long start, unsigned long end); | 118 | extern void sync_global_pgds(unsigned long start, unsigned long end, |
119 | int removed); | ||
119 | 120 | ||
120 | /* | 121 | /* |
121 | * Conversion functions: convert a page and protection to a page entry, | 122 | * Conversion functions: convert a page and protection to a page entry, |
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index a24194681513..d393ac669cc0 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -350,7 +350,7 @@ out: | |||
350 | 350 | ||
351 | void vmalloc_sync_all(void) | 351 | void vmalloc_sync_all(void) |
352 | { | 352 | { |
353 | sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END); | 353 | sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END, 0); |
354 | } | 354 | } |
355 | 355 | ||
356 | /* | 356 | /* |
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 0e996c0a7eff..529625118ff6 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
@@ -178,7 +178,7 @@ __setup("noexec32=", nonx32_setup); | |||
178 | * When memory was added/removed make sure all the processes MM have | 178 | * When memory was added/removed make sure all the processes MM have |
179 | * suitable PGD entries in the local PGD level page. | 179 | * suitable PGD entries in the local PGD level page. |
180 | */ | 180 | */ |
181 | void sync_global_pgds(unsigned long start, unsigned long end) | 181 | void sync_global_pgds(unsigned long start, unsigned long end, int removed) |
182 | { | 182 | { |
183 | unsigned long address; | 183 | unsigned long address; |
184 | 184 | ||
@@ -186,7 +186,12 @@ void sync_global_pgds(unsigned long start, unsigned long end) | |||
186 | const pgd_t *pgd_ref = pgd_offset_k(address); | 186 | const pgd_t *pgd_ref = pgd_offset_k(address); |
187 | struct page *page; | 187 | struct page *page; |
188 | 188 | ||
189 | if (pgd_none(*pgd_ref)) | 189 | /* |
190 | * When it is called after memory hot remove, pgd_none() | ||
191 | * returns true. In this case (removed == 1), we must clear | ||
192 | * the PGD entries in the local PGD level page. | ||
193 | */ | ||
194 | if (pgd_none(*pgd_ref) && !removed) | ||
190 | continue; | 195 | continue; |
191 | 196 | ||
192 | spin_lock(&pgd_lock); | 197 | spin_lock(&pgd_lock); |
@@ -199,12 +204,18 @@ void sync_global_pgds(unsigned long start, unsigned long end) | |||
199 | pgt_lock = &pgd_page_get_mm(page)->page_table_lock; | 204 | pgt_lock = &pgd_page_get_mm(page)->page_table_lock; |
200 | spin_lock(pgt_lock); | 205 | spin_lock(pgt_lock); |
201 | 206 | ||
202 | if (pgd_none(*pgd)) | 207 | if (!pgd_none(*pgd_ref) && !pgd_none(*pgd)) |
203 | set_pgd(pgd, *pgd_ref); | ||
204 | else | ||
205 | BUG_ON(pgd_page_vaddr(*pgd) | 208 | BUG_ON(pgd_page_vaddr(*pgd) |
206 | != pgd_page_vaddr(*pgd_ref)); | 209 | != pgd_page_vaddr(*pgd_ref)); |
207 | 210 | ||
211 | if (removed) { | ||
212 | if (pgd_none(*pgd_ref) && !pgd_none(*pgd)) | ||
213 | pgd_clear(pgd); | ||
214 | } else { | ||
215 | if (pgd_none(*pgd)) | ||
216 | set_pgd(pgd, *pgd_ref); | ||
217 | } | ||
218 | |||
208 | spin_unlock(pgt_lock); | 219 | spin_unlock(pgt_lock); |
209 | } | 220 | } |
210 | spin_unlock(&pgd_lock); | 221 | spin_unlock(&pgd_lock); |
@@ -633,7 +644,7 @@ kernel_physical_mapping_init(unsigned long start, | |||
633 | } | 644 | } |
634 | 645 | ||
635 | if (pgd_changed) | 646 | if (pgd_changed) |
636 | sync_global_pgds(addr, end - 1); | 647 | sync_global_pgds(addr, end - 1, 0); |
637 | 648 | ||
638 | __flush_tlb_all(); | 649 | __flush_tlb_all(); |
639 | 650 | ||
@@ -995,7 +1006,7 @@ remove_pagetable(unsigned long start, unsigned long end, bool direct) | |||
995 | } | 1006 | } |
996 | 1007 | ||
997 | if (pgd_changed) | 1008 | if (pgd_changed) |
998 | sync_global_pgds(start, end - 1); | 1009 | sync_global_pgds(start, end - 1, 1); |
999 | 1010 | ||
1000 | flush_tlb_all(); | 1011 | flush_tlb_all(); |
1001 | } | 1012 | } |
@@ -1342,7 +1353,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) | |||
1342 | else | 1353 | else |
1343 | err = vmemmap_populate_basepages(start, end, node); | 1354 | err = vmemmap_populate_basepages(start, end, node); |
1344 | if (!err) | 1355 | if (!err) |
1345 | sync_global_pgds(start, end - 1); | 1356 | sync_global_pgds(start, end - 1, 0); |
1346 | return err; | 1357 | return err; |
1347 | } | 1358 | } |
1348 | 1359 | ||