diff options
Diffstat (limited to 'mm/sparse.c')
| -rw-r--r-- | mm/sparse.c | 196 |
1 files changed, 178 insertions, 18 deletions
diff --git a/mm/sparse.c b/mm/sparse.c index 6ce4aab69e99..22896d589133 100644 --- a/mm/sparse.c +++ b/mm/sparse.c | |||
| @@ -271,7 +271,8 @@ static unsigned long *__kmalloc_section_usemap(void) | |||
| 271 | 271 | ||
| 272 | #ifdef CONFIG_MEMORY_HOTREMOVE | 272 | #ifdef CONFIG_MEMORY_HOTREMOVE |
| 273 | static unsigned long * __init | 273 | static unsigned long * __init |
| 274 | sparse_early_usemap_alloc_pgdat_section(struct pglist_data *pgdat) | 274 | sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat, |
| 275 | unsigned long count) | ||
| 275 | { | 276 | { |
| 276 | unsigned long section_nr; | 277 | unsigned long section_nr; |
| 277 | 278 | ||
| @@ -286,7 +287,7 @@ sparse_early_usemap_alloc_pgdat_section(struct pglist_data *pgdat) | |||
| 286 | * this problem. | 287 | * this problem. |
| 287 | */ | 288 | */ |
| 288 | section_nr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT); | 289 | section_nr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT); |
| 289 | return alloc_bootmem_section(usemap_size(), section_nr); | 290 | return alloc_bootmem_section(usemap_size() * count, section_nr); |
| 290 | } | 291 | } |
| 291 | 292 | ||
| 292 | static void __init check_usemap_section_nr(int nid, unsigned long *usemap) | 293 | static void __init check_usemap_section_nr(int nid, unsigned long *usemap) |
| @@ -329,7 +330,8 @@ static void __init check_usemap_section_nr(int nid, unsigned long *usemap) | |||
| 329 | } | 330 | } |
| 330 | #else | 331 | #else |
| 331 | static unsigned long * __init | 332 | static unsigned long * __init |
| 332 | sparse_early_usemap_alloc_pgdat_section(struct pglist_data *pgdat) | 333 | sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat, |
| 334 | unsigned long count) | ||
| 333 | { | 335 | { |
| 334 | return NULL; | 336 | return NULL; |
| 335 | } | 337 | } |
| @@ -339,27 +341,40 @@ static void __init check_usemap_section_nr(int nid, unsigned long *usemap) | |||
| 339 | } | 341 | } |
| 340 | #endif /* CONFIG_MEMORY_HOTREMOVE */ | 342 | #endif /* CONFIG_MEMORY_HOTREMOVE */ |
| 341 | 343 | ||
| 342 | static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum) | 344 | static void __init sparse_early_usemaps_alloc_node(unsigned long**usemap_map, |
| 345 | unsigned long pnum_begin, | ||
| 346 | unsigned long pnum_end, | ||
| 347 | unsigned long usemap_count, int nodeid) | ||
| 343 | { | 348 | { |
| 344 | unsigned long *usemap; | 349 | void *usemap; |
| 345 | struct mem_section *ms = __nr_to_section(pnum); | 350 | unsigned long pnum; |
| 346 | int nid = sparse_early_nid(ms); | 351 | int size = usemap_size(); |
| 347 | |||
| 348 | usemap = sparse_early_usemap_alloc_pgdat_section(NODE_DATA(nid)); | ||
| 349 | if (usemap) | ||
| 350 | return usemap; | ||
| 351 | 352 | ||
| 352 | usemap = alloc_bootmem_node(NODE_DATA(nid), usemap_size()); | 353 | usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nodeid), |
| 354 | usemap_count); | ||
| 353 | if (usemap) { | 355 | if (usemap) { |
| 354 | check_usemap_section_nr(nid, usemap); | 356 | for (pnum = pnum_begin; pnum < pnum_end; pnum++) { |
| 355 | return usemap; | 357 | if (!present_section_nr(pnum)) |
| 358 | continue; | ||
| 359 | usemap_map[pnum] = usemap; | ||
| 360 | usemap += size; | ||
| 361 | } | ||
| 362 | return; | ||
| 356 | } | 363 | } |
| 357 | 364 | ||
| 358 | /* Stupid: suppress gcc warning for SPARSEMEM && !NUMA */ | 365 | usemap = alloc_bootmem_node(NODE_DATA(nodeid), size * usemap_count); |
| 359 | nid = 0; | 366 | if (usemap) { |
| 367 | for (pnum = pnum_begin; pnum < pnum_end; pnum++) { | ||
| 368 | if (!present_section_nr(pnum)) | ||
| 369 | continue; | ||
| 370 | usemap_map[pnum] = usemap; | ||
| 371 | usemap += size; | ||
| 372 | check_usemap_section_nr(nodeid, usemap_map[pnum]); | ||
| 373 | } | ||
| 374 | return; | ||
| 375 | } | ||
| 360 | 376 | ||
| 361 | printk(KERN_WARNING "%s: allocation failed\n", __func__); | 377 | printk(KERN_WARNING "%s: allocation failed\n", __func__); |
| 362 | return NULL; | ||
| 363 | } | 378 | } |
| 364 | 379 | ||
| 365 | #ifndef CONFIG_SPARSEMEM_VMEMMAP | 380 | #ifndef CONFIG_SPARSEMEM_VMEMMAP |
| @@ -375,8 +390,65 @@ struct page __init *sparse_mem_map_populate(unsigned long pnum, int nid) | |||
| 375 | PAGE_ALIGN(sizeof(struct page) * PAGES_PER_SECTION)); | 390 | PAGE_ALIGN(sizeof(struct page) * PAGES_PER_SECTION)); |
| 376 | return map; | 391 | return map; |
| 377 | } | 392 | } |
| 393 | void __init sparse_mem_maps_populate_node(struct page **map_map, | ||
| 394 | unsigned long pnum_begin, | ||
| 395 | unsigned long pnum_end, | ||
| 396 | unsigned long map_count, int nodeid) | ||
| 397 | { | ||
| 398 | void *map; | ||
| 399 | unsigned long pnum; | ||
| 400 | unsigned long size = sizeof(struct page) * PAGES_PER_SECTION; | ||
| 401 | |||
| 402 | map = alloc_remap(nodeid, size * map_count); | ||
| 403 | if (map) { | ||
| 404 | for (pnum = pnum_begin; pnum < pnum_end; pnum++) { | ||
| 405 | if (!present_section_nr(pnum)) | ||
| 406 | continue; | ||
| 407 | map_map[pnum] = map; | ||
| 408 | map += size; | ||
| 409 | } | ||
| 410 | return; | ||
| 411 | } | ||
| 412 | |||
| 413 | size = PAGE_ALIGN(size); | ||
| 414 | map = alloc_bootmem_pages_node(NODE_DATA(nodeid), size * map_count); | ||
| 415 | if (map) { | ||
| 416 | for (pnum = pnum_begin; pnum < pnum_end; pnum++) { | ||
| 417 | if (!present_section_nr(pnum)) | ||
| 418 | continue; | ||
| 419 | map_map[pnum] = map; | ||
| 420 | map += size; | ||
| 421 | } | ||
| 422 | return; | ||
| 423 | } | ||
| 424 | |||
| 425 | /* fallback */ | ||
| 426 | for (pnum = pnum_begin; pnum < pnum_end; pnum++) { | ||
| 427 | struct mem_section *ms; | ||
| 428 | |||
| 429 | if (!present_section_nr(pnum)) | ||
| 430 | continue; | ||
| 431 | map_map[pnum] = sparse_mem_map_populate(pnum, nodeid); | ||
| 432 | if (map_map[pnum]) | ||
| 433 | continue; | ||
| 434 | ms = __nr_to_section(pnum); | ||
| 435 | printk(KERN_ERR "%s: sparsemem memory map backing failed " | ||
| 436 | "some memory will not be available.\n", __func__); | ||
| 437 | ms->section_mem_map = 0; | ||
| 438 | } | ||
| 439 | } | ||
| 378 | #endif /* !CONFIG_SPARSEMEM_VMEMMAP */ | 440 | #endif /* !CONFIG_SPARSEMEM_VMEMMAP */ |
| 379 | 441 | ||
| 442 | #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER | ||
| 443 | static void __init sparse_early_mem_maps_alloc_node(struct page **map_map, | ||
| 444 | unsigned long pnum_begin, | ||
| 445 | unsigned long pnum_end, | ||
| 446 | unsigned long map_count, int nodeid) | ||
| 447 | { | ||
| 448 | sparse_mem_maps_populate_node(map_map, pnum_begin, pnum_end, | ||
| 449 | map_count, nodeid); | ||
| 450 | } | ||
| 451 | #else | ||
| 380 | static struct page __init *sparse_early_mem_map_alloc(unsigned long pnum) | 452 | static struct page __init *sparse_early_mem_map_alloc(unsigned long pnum) |
| 381 | { | 453 | { |
| 382 | struct page *map; | 454 | struct page *map; |
| @@ -392,10 +464,12 @@ static struct page __init *sparse_early_mem_map_alloc(unsigned long pnum) | |||
| 392 | ms->section_mem_map = 0; | 464 | ms->section_mem_map = 0; |
| 393 | return NULL; | 465 | return NULL; |
| 394 | } | 466 | } |
| 467 | #endif | ||
| 395 | 468 | ||
| 396 | void __attribute__((weak)) __meminit vmemmap_populate_print_last(void) | 469 | void __attribute__((weak)) __meminit vmemmap_populate_print_last(void) |
| 397 | { | 470 | { |
| 398 | } | 471 | } |
| 472 | |||
| 399 | /* | 473 | /* |
| 400 | * Allocate the accumulated non-linear sections, allocate a mem_map | 474 | * Allocate the accumulated non-linear sections, allocate a mem_map |
| 401 | * for each and record the physical to section mapping. | 475 | * for each and record the physical to section mapping. |
| @@ -407,6 +481,14 @@ void __init sparse_init(void) | |||
| 407 | unsigned long *usemap; | 481 | unsigned long *usemap; |
| 408 | unsigned long **usemap_map; | 482 | unsigned long **usemap_map; |
| 409 | int size; | 483 | int size; |
| 484 | int nodeid_begin = 0; | ||
| 485 | unsigned long pnum_begin = 0; | ||
| 486 | unsigned long usemap_count; | ||
| 487 | #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER | ||
| 488 | unsigned long map_count; | ||
| 489 | int size2; | ||
| 490 | struct page **map_map; | ||
| 491 | #endif | ||
| 410 | 492 | ||
| 411 | /* | 493 | /* |
| 412 | * map is using big page (aka 2M in x86 64 bit) | 494 | * map is using big page (aka 2M in x86 64 bit) |
| @@ -425,10 +507,81 @@ void __init sparse_init(void) | |||
| 425 | panic("can not allocate usemap_map\n"); | 507 | panic("can not allocate usemap_map\n"); |
| 426 | 508 | ||
| 427 | for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) { | 509 | for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) { |
| 510 | struct mem_section *ms; | ||
| 511 | |||
| 428 | if (!present_section_nr(pnum)) | 512 | if (!present_section_nr(pnum)) |
| 429 | continue; | 513 | continue; |
| 430 | usemap_map[pnum] = sparse_early_usemap_alloc(pnum); | 514 | ms = __nr_to_section(pnum); |
| 515 | nodeid_begin = sparse_early_nid(ms); | ||
| 516 | pnum_begin = pnum; | ||
| 517 | break; | ||
| 431 | } | 518 | } |
| 519 | usemap_count = 1; | ||
| 520 | for (pnum = pnum_begin + 1; pnum < NR_MEM_SECTIONS; pnum++) { | ||
| 521 | struct mem_section *ms; | ||
| 522 | int nodeid; | ||
| 523 | |||
| 524 | if (!present_section_nr(pnum)) | ||
| 525 | continue; | ||
| 526 | ms = __nr_to_section(pnum); | ||
| 527 | nodeid = sparse_early_nid(ms); | ||
| 528 | if (nodeid == nodeid_begin) { | ||
| 529 | usemap_count++; | ||
| 530 | continue; | ||
| 531 | } | ||
| 532 | /* ok, we need to take cake of from pnum_begin to pnum - 1*/ | ||
| 533 | sparse_early_usemaps_alloc_node(usemap_map, pnum_begin, pnum, | ||
| 534 | usemap_count, nodeid_begin); | ||
| 535 | /* new start, update count etc*/ | ||
| 536 | nodeid_begin = nodeid; | ||
| 537 | pnum_begin = pnum; | ||
| 538 | usemap_count = 1; | ||
| 539 | } | ||
| 540 | /* ok, last chunk */ | ||
| 541 | sparse_early_usemaps_alloc_node(usemap_map, pnum_begin, NR_MEM_SECTIONS, | ||
| 542 | usemap_count, nodeid_begin); | ||
| 543 | |||
| 544 | #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER | ||
| 545 | size2 = sizeof(struct page *) * NR_MEM_SECTIONS; | ||
| 546 | map_map = alloc_bootmem(size2); | ||
| 547 | if (!map_map) | ||
| 548 | panic("can not allocate map_map\n"); | ||
| 549 | |||
| 550 | for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) { | ||
| 551 | struct mem_section *ms; | ||
| 552 | |||
| 553 | if (!present_section_nr(pnum)) | ||
| 554 | continue; | ||
| 555 | ms = __nr_to_section(pnum); | ||
| 556 | nodeid_begin = sparse_early_nid(ms); | ||
| 557 | pnum_begin = pnum; | ||
| 558 | break; | ||
| 559 | } | ||
| 560 | map_count = 1; | ||
| 561 | for (pnum = pnum_begin + 1; pnum < NR_MEM_SECTIONS; pnum++) { | ||
| 562 | struct mem_section *ms; | ||
| 563 | int nodeid; | ||
| 564 | |||
| 565 | if (!present_section_nr(pnum)) | ||
| 566 | continue; | ||
| 567 | ms = __nr_to_section(pnum); | ||
| 568 | nodeid = sparse_early_nid(ms); | ||
| 569 | if (nodeid == nodeid_begin) { | ||
| 570 | map_count++; | ||
| 571 | continue; | ||
| 572 | } | ||
| 573 | /* ok, we need to take cake of from pnum_begin to pnum - 1*/ | ||
| 574 | sparse_early_mem_maps_alloc_node(map_map, pnum_begin, pnum, | ||
| 575 | map_count, nodeid_begin); | ||
| 576 | /* new start, update count etc*/ | ||
| 577 | nodeid_begin = nodeid; | ||
| 578 | pnum_begin = pnum; | ||
| 579 | map_count = 1; | ||
| 580 | } | ||
| 581 | /* ok, last chunk */ | ||
| 582 | sparse_early_mem_maps_alloc_node(map_map, pnum_begin, NR_MEM_SECTIONS, | ||
| 583 | map_count, nodeid_begin); | ||
| 584 | #endif | ||
| 432 | 585 | ||
| 433 | for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) { | 586 | for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) { |
| 434 | if (!present_section_nr(pnum)) | 587 | if (!present_section_nr(pnum)) |
| @@ -438,7 +591,11 @@ void __init sparse_init(void) | |||
| 438 | if (!usemap) | 591 | if (!usemap) |
| 439 | continue; | 592 | continue; |
| 440 | 593 | ||
| 594 | #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER | ||
| 595 | map = map_map[pnum]; | ||
| 596 | #else | ||
| 441 | map = sparse_early_mem_map_alloc(pnum); | 597 | map = sparse_early_mem_map_alloc(pnum); |
| 598 | #endif | ||
| 442 | if (!map) | 599 | if (!map) |
| 443 | continue; | 600 | continue; |
| 444 | 601 | ||
| @@ -448,6 +605,9 @@ void __init sparse_init(void) | |||
| 448 | 605 | ||
| 449 | vmemmap_populate_print_last(); | 606 | vmemmap_populate_print_last(); |
| 450 | 607 | ||
| 608 | #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER | ||
| 609 | free_bootmem(__pa(map_map), size2); | ||
| 610 | #endif | ||
| 451 | free_bootmem(__pa(usemap_map), size); | 611 | free_bootmem(__pa(usemap_map), size); |
| 452 | } | 612 | } |
| 453 | 613 | ||
