summaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r--mm/page_alloc.c55
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
1065static 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 */
1066void __defermem_init deferred_init_memmap(int nid) 1085void __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;
1174free_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