diff options
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 55 |
1 files changed, 49 insertions, 6 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0f770cc13450..e3f00f622f28 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -1062,6 +1062,25 @@ void __defer_init __free_pages_bootmem(struct page *page, unsigned long pfn, | |||
1062 | } | 1062 | } |
1063 | 1063 | ||
1064 | #ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT | 1064 | #ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT |
1065 | static void __defermem_init deferred_free_range(struct page *page, | ||
1066 | unsigned long pfn, int nr_pages) | ||
1067 | { | ||
1068 | int i; | ||
1069 | |||
1070 | if (!page) | ||
1071 | return; | ||
1072 | |||
1073 | /* Free a large naturally-aligned chunk if possible */ | ||
1074 | if (nr_pages == MAX_ORDER_NR_PAGES && | ||
1075 | (pfn & (MAX_ORDER_NR_PAGES-1)) == 0) { | ||
1076 | __free_pages_boot_core(page, pfn, MAX_ORDER-1); | ||
1077 | return; | ||
1078 | } | ||
1079 | |||
1080 | for (i = 0; i < nr_pages; i++, page++, pfn++) | ||
1081 | __free_pages_boot_core(page, pfn, 0); | ||
1082 | } | ||
1083 | |||
1065 | /* Initialise remaining memory on a node */ | 1084 | /* Initialise remaining memory on a node */ |
1066 | void __defermem_init deferred_init_memmap(int nid) | 1085 | void __defermem_init deferred_init_memmap(int nid) |
1067 | { | 1086 | { |
@@ -1092,6 +1111,9 @@ void __defermem_init deferred_init_memmap(int nid) | |||
1092 | for_each_mem_pfn_range(i, nid, &walk_start, &walk_end, NULL) { | 1111 | for_each_mem_pfn_range(i, nid, &walk_start, &walk_end, NULL) { |
1093 | unsigned long pfn, end_pfn; | 1112 | unsigned long pfn, end_pfn; |
1094 | struct page *page = NULL; | 1113 | struct page *page = NULL; |
1114 | struct page *free_base_page = NULL; | ||
1115 | unsigned long free_base_pfn = 0; | ||
1116 | int nr_to_free = 0; | ||
1095 | 1117 | ||
1096 | end_pfn = min(walk_end, zone_end_pfn(zone)); | 1118 | end_pfn = min(walk_end, zone_end_pfn(zone)); |
1097 | pfn = first_init_pfn; | 1119 | pfn = first_init_pfn; |
@@ -1102,7 +1124,7 @@ void __defermem_init deferred_init_memmap(int nid) | |||
1102 | 1124 | ||
1103 | for (; pfn < end_pfn; pfn++) { | 1125 | for (; pfn < end_pfn; pfn++) { |
1104 | if (!pfn_valid_within(pfn)) | 1126 | if (!pfn_valid_within(pfn)) |
1105 | continue; | 1127 | goto free_range; |
1106 | 1128 | ||
1107 | /* | 1129 | /* |
1108 | * Ensure pfn_valid is checked every | 1130 | * Ensure pfn_valid is checked every |
@@ -1111,32 +1133,53 @@ void __defermem_init deferred_init_memmap(int nid) | |||
1111 | if ((pfn & (MAX_ORDER_NR_PAGES - 1)) == 0) { | 1133 | if ((pfn & (MAX_ORDER_NR_PAGES - 1)) == 0) { |
1112 | if (!pfn_valid(pfn)) { | 1134 | if (!pfn_valid(pfn)) { |
1113 | page = NULL; | 1135 | page = NULL; |
1114 | continue; | 1136 | goto free_range; |
1115 | } | 1137 | } |
1116 | } | 1138 | } |
1117 | 1139 | ||
1118 | if (!meminit_pfn_in_nid(pfn, nid, &nid_init_state)) { | 1140 | if (!meminit_pfn_in_nid(pfn, nid, &nid_init_state)) { |
1119 | page = NULL; | 1141 | page = NULL; |
1120 | continue; | 1142 | goto free_range; |
1121 | } | 1143 | } |
1122 | 1144 | ||
1123 | /* Minimise pfn page lookups and scheduler checks */ | 1145 | /* Minimise pfn page lookups and scheduler checks */ |
1124 | if (page && (pfn & (MAX_ORDER_NR_PAGES - 1)) != 0) { | 1146 | if (page && (pfn & (MAX_ORDER_NR_PAGES - 1)) != 0) { |
1125 | page++; | 1147 | page++; |
1126 | } else { | 1148 | } else { |
1149 | nr_pages += nr_to_free; | ||
1150 | deferred_free_range(free_base_page, | ||
1151 | free_base_pfn, nr_to_free); | ||
1152 | free_base_page = NULL; | ||
1153 | free_base_pfn = nr_to_free = 0; | ||
1154 | |||
1127 | page = pfn_to_page(pfn); | 1155 | page = pfn_to_page(pfn); |
1128 | cond_resched(); | 1156 | cond_resched(); |
1129 | } | 1157 | } |
1130 | 1158 | ||
1131 | if (page->flags) { | 1159 | if (page->flags) { |
1132 | VM_BUG_ON(page_zone(page) != zone); | 1160 | VM_BUG_ON(page_zone(page) != zone); |
1133 | continue; | 1161 | goto free_range; |
1134 | } | 1162 | } |
1135 | 1163 | ||
1136 | __init_single_page(page, pfn, zid, nid); | 1164 | __init_single_page(page, pfn, zid, nid); |
1137 | __free_pages_boot_core(page, pfn, 0); | 1165 | if (!free_base_page) { |
1138 | nr_pages++; | 1166 | free_base_page = page; |
1167 | free_base_pfn = pfn; | ||
1168 | nr_to_free = 0; | ||
1169 | } | ||
1170 | nr_to_free++; | ||
1171 | |||
1172 | /* Where possible, batch up pages for a single free */ | ||
1173 | continue; | ||
1174 | free_range: | ||
1175 | /* Free the current block of pages to allocator */ | ||
1176 | nr_pages += nr_to_free; | ||
1177 | deferred_free_range(free_base_page, free_base_pfn, | ||
1178 | nr_to_free); | ||
1179 | free_base_page = NULL; | ||
1180 | free_base_pfn = nr_to_free = 0; | ||
1139 | } | 1181 | } |
1182 | |||
1140 | first_init_pfn = max(end_pfn, first_init_pfn); | 1183 | first_init_pfn = max(end_pfn, first_init_pfn); |
1141 | } | 1184 | } |
1142 | 1185 | ||