diff options
Diffstat (limited to 'mm/bootmem.c')
-rw-r--r-- | mm/bootmem.c | 92 |
1 files changed, 54 insertions, 38 deletions
diff --git a/mm/bootmem.c b/mm/bootmem.c index e5415a5414a5..89646f77b427 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c | |||
@@ -408,6 +408,7 @@ static void * __init alloc_bootmem_core(struct bootmem_data *bdata, | |||
408 | unsigned long size, unsigned long align, | 408 | unsigned long size, unsigned long align, |
409 | unsigned long goal, unsigned long limit) | 409 | unsigned long goal, unsigned long limit) |
410 | { | 410 | { |
411 | unsigned long fallback = 0; | ||
411 | unsigned long min, max, start, sidx, midx, step; | 412 | unsigned long min, max, start, sidx, midx, step; |
412 | 413 | ||
413 | BUG_ON(!size); | 414 | BUG_ON(!size); |
@@ -443,8 +444,11 @@ static void * __init alloc_bootmem_core(struct bootmem_data *bdata, | |||
443 | midx = max - PFN_DOWN(bdata->node_boot_start); | 444 | midx = max - PFN_DOWN(bdata->node_boot_start); |
444 | 445 | ||
445 | if (bdata->hint_idx > sidx) { | 446 | if (bdata->hint_idx > sidx) { |
446 | /* Make sure we retry on failure */ | 447 | /* |
447 | goal = 1; | 448 | * Handle the valid case of sidx being zero and still |
449 | * catch the fallback below. | ||
450 | */ | ||
451 | fallback = sidx + 1; | ||
448 | sidx = ALIGN(bdata->hint_idx, step); | 452 | sidx = ALIGN(bdata->hint_idx, step); |
449 | } | 453 | } |
450 | 454 | ||
@@ -492,10 +496,39 @@ find_block: | |||
492 | return region; | 496 | return region; |
493 | } | 497 | } |
494 | 498 | ||
499 | if (fallback) { | ||
500 | sidx = ALIGN(fallback - 1, step); | ||
501 | fallback = 0; | ||
502 | goto find_block; | ||
503 | } | ||
504 | |||
505 | return NULL; | ||
506 | } | ||
507 | |||
508 | static void * __init ___alloc_bootmem_nopanic(unsigned long size, | ||
509 | unsigned long align, | ||
510 | unsigned long goal, | ||
511 | unsigned long limit) | ||
512 | { | ||
513 | bootmem_data_t *bdata; | ||
514 | |||
515 | restart: | ||
516 | list_for_each_entry(bdata, &bdata_list, list) { | ||
517 | void *region; | ||
518 | |||
519 | if (goal && bdata->node_low_pfn <= PFN_DOWN(goal)) | ||
520 | continue; | ||
521 | if (limit && bdata->node_boot_start >= limit) | ||
522 | break; | ||
523 | |||
524 | region = alloc_bootmem_core(bdata, size, align, goal, limit); | ||
525 | if (region) | ||
526 | return region; | ||
527 | } | ||
528 | |||
495 | if (goal) { | 529 | if (goal) { |
496 | goal = 0; | 530 | goal = 0; |
497 | sidx = 0; | 531 | goto restart; |
498 | goto find_block; | ||
499 | } | 532 | } |
500 | 533 | ||
501 | return NULL; | 534 | return NULL; |
@@ -515,16 +548,23 @@ find_block: | |||
515 | * Returns NULL on failure. | 548 | * Returns NULL on failure. |
516 | */ | 549 | */ |
517 | void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align, | 550 | void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align, |
518 | unsigned long goal) | 551 | unsigned long goal) |
519 | { | 552 | { |
520 | bootmem_data_t *bdata; | 553 | return ___alloc_bootmem_nopanic(size, align, goal, 0); |
521 | void *ptr; | 554 | } |
522 | 555 | ||
523 | list_for_each_entry(bdata, &bdata_list, list) { | 556 | static void * __init ___alloc_bootmem(unsigned long size, unsigned long align, |
524 | ptr = alloc_bootmem_core(bdata, size, align, goal, 0); | 557 | unsigned long goal, unsigned long limit) |
525 | if (ptr) | 558 | { |
526 | return ptr; | 559 | void *mem = ___alloc_bootmem_nopanic(size, align, goal, limit); |
527 | } | 560 | |
561 | if (mem) | ||
562 | return mem; | ||
563 | /* | ||
564 | * Whoops, we cannot satisfy the allocation request. | ||
565 | */ | ||
566 | printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size); | ||
567 | panic("Out of memory"); | ||
528 | return NULL; | 568 | return NULL; |
529 | } | 569 | } |
530 | 570 | ||
@@ -544,16 +584,7 @@ void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align, | |||
544 | void * __init __alloc_bootmem(unsigned long size, unsigned long align, | 584 | void * __init __alloc_bootmem(unsigned long size, unsigned long align, |
545 | unsigned long goal) | 585 | unsigned long goal) |
546 | { | 586 | { |
547 | void *mem = __alloc_bootmem_nopanic(size,align,goal); | 587 | return ___alloc_bootmem(size, align, goal, 0); |
548 | |||
549 | if (mem) | ||
550 | return mem; | ||
551 | /* | ||
552 | * Whoops, we cannot satisfy the allocation request. | ||
553 | */ | ||
554 | printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size); | ||
555 | panic("Out of memory"); | ||
556 | return NULL; | ||
557 | } | 588 | } |
558 | 589 | ||
559 | /** | 590 | /** |
@@ -653,22 +684,7 @@ void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size, | |||
653 | void * __init __alloc_bootmem_low(unsigned long size, unsigned long align, | 684 | void * __init __alloc_bootmem_low(unsigned long size, unsigned long align, |
654 | unsigned long goal) | 685 | unsigned long goal) |
655 | { | 686 | { |
656 | bootmem_data_t *bdata; | 687 | return ___alloc_bootmem(size, align, goal, ARCH_LOW_ADDRESS_LIMIT); |
657 | void *ptr; | ||
658 | |||
659 | list_for_each_entry(bdata, &bdata_list, list) { | ||
660 | ptr = alloc_bootmem_core(bdata, size, align, goal, | ||
661 | ARCH_LOW_ADDRESS_LIMIT); | ||
662 | if (ptr) | ||
663 | return ptr; | ||
664 | } | ||
665 | |||
666 | /* | ||
667 | * Whoops, we cannot satisfy the allocation request. | ||
668 | */ | ||
669 | printk(KERN_ALERT "low bootmem alloc of %lu bytes failed!\n", size); | ||
670 | panic("Out of low memory"); | ||
671 | return NULL; | ||
672 | } | 688 | } |
673 | 689 | ||
674 | /** | 690 | /** |