diff options
Diffstat (limited to 'mm/bootmem.c')
-rw-r--r-- | mm/bootmem.c | 138 |
1 files changed, 75 insertions, 63 deletions
diff --git a/mm/bootmem.c b/mm/bootmem.c index 0131170c9d54..bcb63ac48cc5 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c | |||
@@ -77,16 +77,16 @@ unsigned long __init bootmem_bootmap_pages(unsigned long pages) | |||
77 | */ | 77 | */ |
78 | static void __init link_bootmem(bootmem_data_t *bdata) | 78 | static void __init link_bootmem(bootmem_data_t *bdata) |
79 | { | 79 | { |
80 | struct list_head *iter; | 80 | bootmem_data_t *ent; |
81 | 81 | ||
82 | list_for_each(iter, &bdata_list) { | 82 | list_for_each_entry(ent, &bdata_list, list) { |
83 | bootmem_data_t *ent; | 83 | if (bdata->node_min_pfn < ent->node_min_pfn) { |
84 | 84 | list_add_tail(&bdata->list, &ent->list); | |
85 | ent = list_entry(iter, bootmem_data_t, list); | 85 | return; |
86 | if (bdata->node_min_pfn < ent->node_min_pfn) | 86 | } |
87 | break; | ||
88 | } | 87 | } |
89 | list_add_tail(&bdata->list, iter); | 88 | |
89 | list_add_tail(&bdata->list, &bdata_list); | ||
90 | } | 90 | } |
91 | 91 | ||
92 | /* | 92 | /* |
@@ -203,7 +203,8 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata) | |||
203 | } else { | 203 | } else { |
204 | unsigned long off = 0; | 204 | unsigned long off = 0; |
205 | 205 | ||
206 | while (vec && off < BITS_PER_LONG) { | 206 | vec >>= start & (BITS_PER_LONG - 1); |
207 | while (vec) { | ||
207 | if (vec & 1) { | 208 | if (vec & 1) { |
208 | page = pfn_to_page(start + off); | 209 | page = pfn_to_page(start + off); |
209 | __free_pages_bootmem(page, 0); | 210 | __free_pages_bootmem(page, 0); |
@@ -467,7 +468,7 @@ static unsigned long __init align_off(struct bootmem_data *bdata, | |||
467 | return ALIGN(base + off, align) - base; | 468 | return ALIGN(base + off, align) - base; |
468 | } | 469 | } |
469 | 470 | ||
470 | static void * __init alloc_bootmem_core(struct bootmem_data *bdata, | 471 | static void * __init alloc_bootmem_bdata(struct bootmem_data *bdata, |
471 | unsigned long size, unsigned long align, | 472 | unsigned long size, unsigned long align, |
472 | unsigned long goal, unsigned long limit) | 473 | unsigned long goal, unsigned long limit) |
473 | { | 474 | { |
@@ -588,14 +589,14 @@ static void * __init alloc_arch_preferred_bootmem(bootmem_data_t *bdata, | |||
588 | p_bdata = bootmem_arch_preferred_node(bdata, size, align, | 589 | p_bdata = bootmem_arch_preferred_node(bdata, size, align, |
589 | goal, limit); | 590 | goal, limit); |
590 | if (p_bdata) | 591 | if (p_bdata) |
591 | return alloc_bootmem_core(p_bdata, size, align, | 592 | return alloc_bootmem_bdata(p_bdata, size, align, |
592 | goal, limit); | 593 | goal, limit); |
593 | } | 594 | } |
594 | #endif | 595 | #endif |
595 | return NULL; | 596 | return NULL; |
596 | } | 597 | } |
597 | 598 | ||
598 | static void * __init ___alloc_bootmem_nopanic(unsigned long size, | 599 | static void * __init alloc_bootmem_core(unsigned long size, |
599 | unsigned long align, | 600 | unsigned long align, |
600 | unsigned long goal, | 601 | unsigned long goal, |
601 | unsigned long limit) | 602 | unsigned long limit) |
@@ -603,7 +604,6 @@ static void * __init ___alloc_bootmem_nopanic(unsigned long size, | |||
603 | bootmem_data_t *bdata; | 604 | bootmem_data_t *bdata; |
604 | void *region; | 605 | void *region; |
605 | 606 | ||
606 | restart: | ||
607 | region = alloc_arch_preferred_bootmem(NULL, size, align, goal, limit); | 607 | region = alloc_arch_preferred_bootmem(NULL, size, align, goal, limit); |
608 | if (region) | 608 | if (region) |
609 | return region; | 609 | return region; |
@@ -614,11 +614,25 @@ restart: | |||
614 | if (limit && bdata->node_min_pfn >= PFN_DOWN(limit)) | 614 | if (limit && bdata->node_min_pfn >= PFN_DOWN(limit)) |
615 | break; | 615 | break; |
616 | 616 | ||
617 | region = alloc_bootmem_core(bdata, size, align, goal, limit); | 617 | region = alloc_bootmem_bdata(bdata, size, align, goal, limit); |
618 | if (region) | 618 | if (region) |
619 | return region; | 619 | return region; |
620 | } | 620 | } |
621 | 621 | ||
622 | return NULL; | ||
623 | } | ||
624 | |||
625 | static void * __init ___alloc_bootmem_nopanic(unsigned long size, | ||
626 | unsigned long align, | ||
627 | unsigned long goal, | ||
628 | unsigned long limit) | ||
629 | { | ||
630 | void *ptr; | ||
631 | |||
632 | restart: | ||
633 | ptr = alloc_bootmem_core(size, align, goal, limit); | ||
634 | if (ptr) | ||
635 | return ptr; | ||
622 | if (goal) { | 636 | if (goal) { |
623 | goal = 0; | 637 | goal = 0; |
624 | goto restart; | 638 | goto restart; |
@@ -684,21 +698,60 @@ void * __init __alloc_bootmem(unsigned long size, unsigned long align, | |||
684 | return ___alloc_bootmem(size, align, goal, limit); | 698 | return ___alloc_bootmem(size, align, goal, limit); |
685 | } | 699 | } |
686 | 700 | ||
687 | static void * __init ___alloc_bootmem_node(bootmem_data_t *bdata, | 701 | void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat, |
688 | unsigned long size, unsigned long align, | 702 | unsigned long size, unsigned long align, |
689 | unsigned long goal, unsigned long limit) | 703 | unsigned long goal, unsigned long limit) |
690 | { | 704 | { |
691 | void *ptr; | 705 | void *ptr; |
692 | 706 | ||
693 | ptr = alloc_arch_preferred_bootmem(bdata, size, align, goal, limit); | 707 | again: |
708 | ptr = alloc_arch_preferred_bootmem(pgdat->bdata, size, | ||
709 | align, goal, limit); | ||
694 | if (ptr) | 710 | if (ptr) |
695 | return ptr; | 711 | return ptr; |
696 | 712 | ||
697 | ptr = alloc_bootmem_core(bdata, size, align, goal, limit); | 713 | /* do not panic in alloc_bootmem_bdata() */ |
714 | if (limit && goal + size > limit) | ||
715 | limit = 0; | ||
716 | |||
717 | ptr = alloc_bootmem_bdata(pgdat->bdata, size, align, goal, limit); | ||
698 | if (ptr) | 718 | if (ptr) |
699 | return ptr; | 719 | return ptr; |
700 | 720 | ||
701 | return ___alloc_bootmem(size, align, goal, limit); | 721 | ptr = alloc_bootmem_core(size, align, goal, limit); |
722 | if (ptr) | ||
723 | return ptr; | ||
724 | |||
725 | if (goal) { | ||
726 | goal = 0; | ||
727 | goto again; | ||
728 | } | ||
729 | |||
730 | return NULL; | ||
731 | } | ||
732 | |||
733 | void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size, | ||
734 | unsigned long align, unsigned long goal) | ||
735 | { | ||
736 | if (WARN_ON_ONCE(slab_is_available())) | ||
737 | return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); | ||
738 | |||
739 | return ___alloc_bootmem_node_nopanic(pgdat, size, align, goal, 0); | ||
740 | } | ||
741 | |||
742 | void * __init ___alloc_bootmem_node(pg_data_t *pgdat, unsigned long size, | ||
743 | unsigned long align, unsigned long goal, | ||
744 | unsigned long limit) | ||
745 | { | ||
746 | void *ptr; | ||
747 | |||
748 | ptr = ___alloc_bootmem_node_nopanic(pgdat, size, align, goal, 0); | ||
749 | if (ptr) | ||
750 | return ptr; | ||
751 | |||
752 | printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size); | ||
753 | panic("Out of memory"); | ||
754 | return NULL; | ||
702 | } | 755 | } |
703 | 756 | ||
704 | /** | 757 | /** |
@@ -722,7 +775,7 @@ void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size, | |||
722 | if (WARN_ON_ONCE(slab_is_available())) | 775 | if (WARN_ON_ONCE(slab_is_available())) |
723 | return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); | 776 | return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); |
724 | 777 | ||
725 | return ___alloc_bootmem_node(pgdat->bdata, size, align, goal, 0); | 778 | return ___alloc_bootmem_node(pgdat, size, align, goal, 0); |
726 | } | 779 | } |
727 | 780 | ||
728 | void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size, | 781 | void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size, |
@@ -743,7 +796,7 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size, | |||
743 | unsigned long new_goal; | 796 | unsigned long new_goal; |
744 | 797 | ||
745 | new_goal = MAX_DMA32_PFN << PAGE_SHIFT; | 798 | new_goal = MAX_DMA32_PFN << PAGE_SHIFT; |
746 | ptr = alloc_bootmem_core(pgdat->bdata, size, align, | 799 | ptr = alloc_bootmem_bdata(pgdat->bdata, size, align, |
747 | new_goal, 0); | 800 | new_goal, 0); |
748 | if (ptr) | 801 | if (ptr) |
749 | return ptr; | 802 | return ptr; |
@@ -754,47 +807,6 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size, | |||
754 | 807 | ||
755 | } | 808 | } |
756 | 809 | ||
757 | #ifdef CONFIG_SPARSEMEM | ||
758 | /** | ||
759 | * alloc_bootmem_section - allocate boot memory from a specific section | ||
760 | * @size: size of the request in bytes | ||
761 | * @section_nr: sparse map section to allocate from | ||
762 | * | ||
763 | * Return NULL on failure. | ||
764 | */ | ||
765 | void * __init alloc_bootmem_section(unsigned long size, | ||
766 | unsigned long section_nr) | ||
767 | { | ||
768 | bootmem_data_t *bdata; | ||
769 | unsigned long pfn, goal; | ||
770 | |||
771 | pfn = section_nr_to_pfn(section_nr); | ||
772 | goal = pfn << PAGE_SHIFT; | ||
773 | bdata = &bootmem_node_data[early_pfn_to_nid(pfn)]; | ||
774 | |||
775 | return alloc_bootmem_core(bdata, size, SMP_CACHE_BYTES, goal, 0); | ||
776 | } | ||
777 | #endif | ||
778 | |||
779 | void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size, | ||
780 | unsigned long align, unsigned long goal) | ||
781 | { | ||
782 | void *ptr; | ||
783 | |||
784 | if (WARN_ON_ONCE(slab_is_available())) | ||
785 | return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); | ||
786 | |||
787 | ptr = alloc_arch_preferred_bootmem(pgdat->bdata, size, align, goal, 0); | ||
788 | if (ptr) | ||
789 | return ptr; | ||
790 | |||
791 | ptr = alloc_bootmem_core(pgdat->bdata, size, align, goal, 0); | ||
792 | if (ptr) | ||
793 | return ptr; | ||
794 | |||
795 | return __alloc_bootmem_nopanic(size, align, goal); | ||
796 | } | ||
797 | |||
798 | #ifndef ARCH_LOW_ADDRESS_LIMIT | 810 | #ifndef ARCH_LOW_ADDRESS_LIMIT |
799 | #define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL | 811 | #define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL |
800 | #endif | 812 | #endif |
@@ -839,6 +851,6 @@ void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size, | |||
839 | if (WARN_ON_ONCE(slab_is_available())) | 851 | if (WARN_ON_ONCE(slab_is_available())) |
840 | return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); | 852 | return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); |
841 | 853 | ||
842 | return ___alloc_bootmem_node(pgdat->bdata, size, align, | 854 | return ___alloc_bootmem_node(pgdat, size, align, |
843 | goal, ARCH_LOW_ADDRESS_LIMIT); | 855 | goal, ARCH_LOW_ADDRESS_LIMIT); |
844 | } | 856 | } |