diff options
Diffstat (limited to 'arch/x86/mm/init_64.c')
-rw-r--r-- | arch/x86/mm/init_64.c | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 5d984769cbd8..4cb8763868fc 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 | ||
@@ -976,25 +987,26 @@ static void __meminit | |||
976 | remove_pagetable(unsigned long start, unsigned long end, bool direct) | 987 | remove_pagetable(unsigned long start, unsigned long end, bool direct) |
977 | { | 988 | { |
978 | unsigned long next; | 989 | unsigned long next; |
990 | unsigned long addr; | ||
979 | pgd_t *pgd; | 991 | pgd_t *pgd; |
980 | pud_t *pud; | 992 | pud_t *pud; |
981 | bool pgd_changed = false; | 993 | bool pgd_changed = false; |
982 | 994 | ||
983 | for (; start < end; start = next) { | 995 | for (addr = start; addr < end; addr = next) { |
984 | next = pgd_addr_end(start, end); | 996 | next = pgd_addr_end(addr, end); |
985 | 997 | ||
986 | pgd = pgd_offset_k(start); | 998 | pgd = pgd_offset_k(addr); |
987 | if (!pgd_present(*pgd)) | 999 | if (!pgd_present(*pgd)) |
988 | continue; | 1000 | continue; |
989 | 1001 | ||
990 | pud = (pud_t *)pgd_page_vaddr(*pgd); | 1002 | pud = (pud_t *)pgd_page_vaddr(*pgd); |
991 | remove_pud_table(pud, start, next, direct); | 1003 | remove_pud_table(pud, addr, next, direct); |
992 | if (free_pud_table(pud, pgd)) | 1004 | if (free_pud_table(pud, pgd)) |
993 | pgd_changed = true; | 1005 | pgd_changed = true; |
994 | } | 1006 | } |
995 | 1007 | ||
996 | if (pgd_changed) | 1008 | if (pgd_changed) |
997 | sync_global_pgds(start, end - 1); | 1009 | sync_global_pgds(start, end - 1, 1); |
998 | 1010 | ||
999 | flush_tlb_all(); | 1011 | flush_tlb_all(); |
1000 | } | 1012 | } |
@@ -1341,7 +1353,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) | |||
1341 | else | 1353 | else |
1342 | err = vmemmap_populate_basepages(start, end, node); | 1354 | err = vmemmap_populate_basepages(start, end, node); |
1343 | if (!err) | 1355 | if (!err) |
1344 | sync_global_pgds(start, end - 1); | 1356 | sync_global_pgds(start, end - 1, 0); |
1345 | return err; | 1357 | return err; |
1346 | } | 1358 | } |
1347 | 1359 | ||