diff options
Diffstat (limited to 'mm/sparse.c')
| -rw-r--r-- | mm/sparse.c | 116 |
1 files changed, 106 insertions, 10 deletions
diff --git a/mm/sparse.c b/mm/sparse.c index 36511c7b5e2c..39db301b920d 100644 --- a/mm/sparse.c +++ b/mm/sparse.c | |||
| @@ -147,22 +147,41 @@ static inline int sparse_early_nid(struct mem_section *section) | |||
| 147 | return (section->section_mem_map >> SECTION_NID_SHIFT); | 147 | return (section->section_mem_map >> SECTION_NID_SHIFT); |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | /* Record a memory area against a node. */ | 150 | /* Validate the physical addressing limitations of the model */ |
| 151 | void __init memory_present(int nid, unsigned long start, unsigned long end) | 151 | void __meminit mminit_validate_memmodel_limits(unsigned long *start_pfn, |
| 152 | unsigned long *end_pfn) | ||
| 152 | { | 153 | { |
| 153 | unsigned long max_arch_pfn = 1UL << (MAX_PHYSMEM_BITS-PAGE_SHIFT); | 154 | unsigned long max_sparsemem_pfn = 1UL << (MAX_PHYSMEM_BITS-PAGE_SHIFT); |
| 154 | unsigned long pfn; | ||
| 155 | 155 | ||
| 156 | /* | 156 | /* |
| 157 | * Sanity checks - do not allow an architecture to pass | 157 | * Sanity checks - do not allow an architecture to pass |
| 158 | * in larger pfns than the maximum scope of sparsemem: | 158 | * in larger pfns than the maximum scope of sparsemem: |
| 159 | */ | 159 | */ |
| 160 | if (start >= max_arch_pfn) | 160 | if (*start_pfn > max_sparsemem_pfn) { |
| 161 | return; | 161 | mminit_dprintk(MMINIT_WARNING, "pfnvalidation", |
| 162 | if (end >= max_arch_pfn) | 162 | "Start of range %lu -> %lu exceeds SPARSEMEM max %lu\n", |
| 163 | end = max_arch_pfn; | 163 | *start_pfn, *end_pfn, max_sparsemem_pfn); |
| 164 | WARN_ON_ONCE(1); | ||
| 165 | *start_pfn = max_sparsemem_pfn; | ||
| 166 | *end_pfn = max_sparsemem_pfn; | ||
| 167 | } | ||
| 168 | |||
| 169 | if (*end_pfn > max_sparsemem_pfn) { | ||
| 170 | mminit_dprintk(MMINIT_WARNING, "pfnvalidation", | ||
| 171 | "End of range %lu -> %lu exceeds SPARSEMEM max %lu\n", | ||
| 172 | *start_pfn, *end_pfn, max_sparsemem_pfn); | ||
| 173 | WARN_ON_ONCE(1); | ||
| 174 | *end_pfn = max_sparsemem_pfn; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | /* Record a memory area against a node. */ | ||
| 179 | void __init memory_present(int nid, unsigned long start, unsigned long end) | ||
| 180 | { | ||
| 181 | unsigned long pfn; | ||
| 164 | 182 | ||
| 165 | start &= PAGE_SECTION_MASK; | 183 | start &= PAGE_SECTION_MASK; |
| 184 | mminit_validate_memmodel_limits(&start, &end); | ||
| 166 | for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) { | 185 | for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) { |
| 167 | unsigned long section = pfn_to_section_nr(pfn); | 186 | unsigned long section = pfn_to_section_nr(pfn); |
| 168 | struct mem_section *ms; | 187 | struct mem_section *ms; |
| @@ -187,6 +206,7 @@ unsigned long __init node_memmap_size_bytes(int nid, unsigned long start_pfn, | |||
| 187 | unsigned long pfn; | 206 | unsigned long pfn; |
| 188 | unsigned long nr_pages = 0; | 207 | unsigned long nr_pages = 0; |
| 189 | 208 | ||
| 209 | mminit_validate_memmodel_limits(&start_pfn, &end_pfn); | ||
| 190 | for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { | 210 | for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { |
| 191 | if (nid != early_pfn_to_nid(pfn)) | 211 | if (nid != early_pfn_to_nid(pfn)) |
| 192 | continue; | 212 | continue; |
| @@ -248,16 +268,92 @@ static unsigned long *__kmalloc_section_usemap(void) | |||
| 248 | } | 268 | } |
| 249 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 269 | #endif /* CONFIG_MEMORY_HOTPLUG */ |
| 250 | 270 | ||
| 271 | #ifdef CONFIG_MEMORY_HOTREMOVE | ||
| 272 | static unsigned long * __init | ||
| 273 | sparse_early_usemap_alloc_pgdat_section(struct pglist_data *pgdat) | ||
| 274 | { | ||
| 275 | unsigned long section_nr; | ||
| 276 | |||
| 277 | /* | ||
| 278 | * A page may contain usemaps for other sections preventing the | ||
| 279 | * page being freed and making a section unremovable while | ||
| 280 | * other sections referencing the usemap retmain active. Similarly, | ||
| 281 | * a pgdat can prevent a section being removed. If section A | ||
| 282 | * contains a pgdat and section B contains the usemap, both | ||
| 283 | * sections become inter-dependent. This allocates usemaps | ||
| 284 | * from the same section as the pgdat where possible to avoid | ||
| 285 | * this problem. | ||
| 286 | */ | ||
| 287 | section_nr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT); | ||
| 288 | return alloc_bootmem_section(usemap_size(), section_nr); | ||
| 289 | } | ||
| 290 | |||
| 291 | static void __init check_usemap_section_nr(int nid, unsigned long *usemap) | ||
| 292 | { | ||
| 293 | unsigned long usemap_snr, pgdat_snr; | ||
| 294 | static unsigned long old_usemap_snr = NR_MEM_SECTIONS; | ||
| 295 | static unsigned long old_pgdat_snr = NR_MEM_SECTIONS; | ||
| 296 | struct pglist_data *pgdat = NODE_DATA(nid); | ||
| 297 | int usemap_nid; | ||
| 298 | |||
| 299 | usemap_snr = pfn_to_section_nr(__pa(usemap) >> PAGE_SHIFT); | ||
| 300 | pgdat_snr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT); | ||
| 301 | if (usemap_snr == pgdat_snr) | ||
| 302 | return; | ||
| 303 | |||
| 304 | if (old_usemap_snr == usemap_snr && old_pgdat_snr == pgdat_snr) | ||
| 305 | /* skip redundant message */ | ||
| 306 | return; | ||
| 307 | |||
| 308 | old_usemap_snr = usemap_snr; | ||
| 309 | old_pgdat_snr = pgdat_snr; | ||
| 310 | |||
| 311 | usemap_nid = sparse_early_nid(__nr_to_section(usemap_snr)); | ||
| 312 | if (usemap_nid != nid) { | ||
| 313 | printk(KERN_INFO | ||
| 314 | "node %d must be removed before remove section %ld\n", | ||
| 315 | nid, usemap_snr); | ||
| 316 | return; | ||
| 317 | } | ||
| 318 | /* | ||
| 319 | * There is a circular dependency. | ||
| 320 | * Some platforms allow un-removable section because they will just | ||
| 321 | * gather other removable sections for dynamic partitioning. | ||
| 322 | * Just notify un-removable section's number here. | ||
| 323 | */ | ||
| 324 | printk(KERN_INFO "Section %ld and %ld (node %d)", usemap_snr, | ||
| 325 | pgdat_snr, nid); | ||
| 326 | printk(KERN_CONT | ||
| 327 | " have a circular dependency on usemap and pgdat allocations\n"); | ||
| 328 | } | ||
| 329 | #else | ||
| 330 | static unsigned long * __init | ||
| 331 | sparse_early_usemap_alloc_pgdat_section(struct pglist_data *pgdat) | ||
| 332 | { | ||
| 333 | return NULL; | ||
| 334 | } | ||
| 335 | |||
| 336 | static void __init check_usemap_section_nr(int nid, unsigned long *usemap) | ||
| 337 | { | ||
| 338 | } | ||
| 339 | #endif /* CONFIG_MEMORY_HOTREMOVE */ | ||
| 340 | |||
| 251 | static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum) | 341 | static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum) |
| 252 | { | 342 | { |
| 253 | unsigned long *usemap; | 343 | unsigned long *usemap; |
| 254 | struct mem_section *ms = __nr_to_section(pnum); | 344 | struct mem_section *ms = __nr_to_section(pnum); |
| 255 | int nid = sparse_early_nid(ms); | 345 | int nid = sparse_early_nid(ms); |
| 256 | 346 | ||
| 257 | usemap = alloc_bootmem_node(NODE_DATA(nid), usemap_size()); | 347 | usemap = sparse_early_usemap_alloc_pgdat_section(NODE_DATA(nid)); |
| 258 | if (usemap) | 348 | if (usemap) |
| 259 | return usemap; | 349 | return usemap; |
| 260 | 350 | ||
| 351 | usemap = alloc_bootmem_node(NODE_DATA(nid), usemap_size()); | ||
| 352 | if (usemap) { | ||
| 353 | check_usemap_section_nr(nid, usemap); | ||
| 354 | return usemap; | ||
| 355 | } | ||
| 356 | |||
| 261 | /* Stupid: suppress gcc warning for SPARSEMEM && !NUMA */ | 357 | /* Stupid: suppress gcc warning for SPARSEMEM && !NUMA */ |
| 262 | nid = 0; | 358 | nid = 0; |
| 263 | 359 | ||
| @@ -280,7 +376,7 @@ struct page __init *sparse_mem_map_populate(unsigned long pnum, int nid) | |||
| 280 | } | 376 | } |
| 281 | #endif /* !CONFIG_SPARSEMEM_VMEMMAP */ | 377 | #endif /* !CONFIG_SPARSEMEM_VMEMMAP */ |
| 282 | 378 | ||
| 283 | struct page __init *sparse_early_mem_map_alloc(unsigned long pnum) | 379 | static struct page __init *sparse_early_mem_map_alloc(unsigned long pnum) |
| 284 | { | 380 | { |
| 285 | struct page *map; | 381 | struct page *map; |
| 286 | struct mem_section *ms = __nr_to_section(pnum); | 382 | struct mem_section *ms = __nr_to_section(pnum); |
