aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorJiang Liu <liuj97@gmail.com>2013-07-03 18:03:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-03 19:07:33 -0400
commit7b4b2a0d6c8500350784beb83a6a55e60ea3bea3 (patch)
tree9d36d3bc9b94d613ed6b556a5f534bb9eec6f876 /mm
parent4f9f47745e948eca18bb97c82dbb4d53f2380086 (diff)
mm: accurately calculate zone->managed_pages for highmem zones
Commit "mm: introduce new field 'managed_pages' to struct zone" assumes that all highmem pages will be freed into the buddy system by function mem_init(). But that's not always true, some architectures may reserve some highmem pages during boot. For example PPC may allocate highmem pages for giagant HugeTLB pages, and several architectures have code to check PageReserved flag to exclude highmem pages allocated during boot when freeing highmem pages into the buddy system. So treat highmem pages in the same way as normal pages, that is to: 1) reset zone->managed_pages to zero in mem_init(). 2) recalculate managed_pages when freeing pages into the buddy system. Signed-off-by: Jiang Liu <jiang.liu@huawei.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Tejun Heo <tj@kernel.org> Cc: Joonsoo Kim <js1304@gmail.com> Cc: Yinghai Lu <yinghai@kernel.org> Cc: Mel Gorman <mel@csn.ul.ie> Cc: Minchan Kim <minchan@kernel.org> Cc: Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Cc: "Michael S. Tsirkin" <mst@redhat.com> Cc: <sworddragon2@aol.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Chris Metcalf <cmetcalf@tilera.com> Cc: David Howells <dhowells@redhat.com> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Jeremy Fitzhardinge <jeremy@goop.org> Cc: Jianguo Wu <wujianguo@huawei.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Michel Lespinasse <walken@google.com> Cc: Rik van Riel <riel@redhat.com> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Tang Chen <tangchen@cn.fujitsu.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Wen Congyang <wency@cn.fujitsu.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com> Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/bootmem.c32
-rw-r--r--mm/nobootmem.c30
-rw-r--r--mm/page_alloc.c1
3 files changed, 35 insertions, 28 deletions
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 2b0bcb019ec2..eb792323187b 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -241,20 +241,26 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
241 return count; 241 return count;
242} 242}
243 243
244static void reset_node_lowmem_managed_pages(pg_data_t *pgdat) 244static int reset_managed_pages_done __initdata;
245
246static inline void __init reset_node_managed_pages(pg_data_t *pgdat)
245{ 247{
246 struct zone *z; 248 struct zone *z;
247 249
248 /* 250 if (reset_managed_pages_done)
249 * In free_area_init_core(), highmem zone's managed_pages is set to 251 return;
250 * present_pages, and bootmem allocator doesn't allocate from highmem 252
251 * zones. So there's no need to recalculate managed_pages because all
252 * highmem pages will be managed by the buddy system. Here highmem
253 * zone also includes highmem movable zone.
254 */
255 for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++) 253 for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++)
256 if (!is_highmem(z)) 254 z->managed_pages = 0;
257 z->managed_pages = 0; 255}
256
257void __init reset_all_zones_managed_pages(void)
258{
259 struct pglist_data *pgdat;
260
261 for_each_online_pgdat(pgdat)
262 reset_node_managed_pages(pgdat);
263 reset_managed_pages_done = 1;
258} 264}
259 265
260/** 266/**
@@ -266,7 +272,7 @@ static void reset_node_lowmem_managed_pages(pg_data_t *pgdat)
266unsigned long __init free_all_bootmem_node(pg_data_t *pgdat) 272unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
267{ 273{
268 register_page_bootmem_info_node(pgdat); 274 register_page_bootmem_info_node(pgdat);
269 reset_node_lowmem_managed_pages(pgdat); 275 reset_node_managed_pages(pgdat);
270 return free_all_bootmem_core(pgdat->bdata); 276 return free_all_bootmem_core(pgdat->bdata);
271} 277}
272 278
@@ -279,10 +285,8 @@ unsigned long __init free_all_bootmem(void)
279{ 285{
280 unsigned long total_pages = 0; 286 unsigned long total_pages = 0;
281 bootmem_data_t *bdata; 287 bootmem_data_t *bdata;
282 struct pglist_data *pgdat;
283 288
284 for_each_online_pgdat(pgdat) 289 reset_all_zones_managed_pages();
285 reset_node_lowmem_managed_pages(pgdat);
286 290
287 list_for_each_entry(bdata, &bdata_list, list) 291 list_for_each_entry(bdata, &bdata_list, list)
288 total_pages += free_all_bootmem_core(bdata); 292 total_pages += free_all_bootmem_core(bdata);
diff --git a/mm/nobootmem.c b/mm/nobootmem.c
index bdd3fa2fc73b..0ae8d91365af 100644
--- a/mm/nobootmem.c
+++ b/mm/nobootmem.c
@@ -137,20 +137,25 @@ static unsigned long __init free_low_memory_core_early(void)
137 return count; 137 return count;
138} 138}
139 139
140static void reset_node_lowmem_managed_pages(pg_data_t *pgdat) 140static int reset_managed_pages_done __initdata;
141
142static inline void __init reset_node_managed_pages(pg_data_t *pgdat)
141{ 143{
142 struct zone *z; 144 struct zone *z;
143 145
144 /* 146 if (reset_managed_pages_done)
145 * In free_area_init_core(), highmem zone's managed_pages is set to 147 return;
146 * present_pages, and bootmem allocator doesn't allocate from highmem
147 * zones. So there's no need to recalculate managed_pages because all
148 * highmem pages will be managed by the buddy system. Here highmem
149 * zone also includes highmem movable zone.
150 */
151 for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++) 148 for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++)
152 if (!is_highmem(z)) 149 z->managed_pages = 0;
153 z->managed_pages = 0; 150}
151
152void __init reset_all_zones_managed_pages(void)
153{
154 struct pglist_data *pgdat;
155
156 for_each_online_pgdat(pgdat)
157 reset_node_managed_pages(pgdat);
158 reset_managed_pages_done = 1;
154} 159}
155 160
156/** 161/**
@@ -160,10 +165,7 @@ static void reset_node_lowmem_managed_pages(pg_data_t *pgdat)
160 */ 165 */
161unsigned long __init free_all_bootmem(void) 166unsigned long __init free_all_bootmem(void)
162{ 167{
163 struct pglist_data *pgdat; 168 reset_all_zones_managed_pages();
164
165 for_each_online_pgdat(pgdat)
166 reset_node_lowmem_managed_pages(pgdat);
167 169
168 /* 170 /*
169 * We need to use MAX_NUMNODES instead of NODE_DATA(0)->node_id 171 * We need to use MAX_NUMNODES instead of NODE_DATA(0)->node_id
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index f22542f6dc12..22438eba00b6 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -5232,6 +5232,7 @@ void free_highmem_page(struct page *page)
5232{ 5232{
5233 __free_reserved_page(page); 5233 __free_reserved_page(page);
5234 totalram_pages++; 5234 totalram_pages++;
5235 page_zone(page)->managed_pages++;
5235 totalhigh_pages++; 5236 totalhigh_pages++;
5236} 5237}
5237#endif 5238#endif