Commit d3975580 authored by Andrew Morton's avatar Andrew Morton Committed by Russell King

[PATCH] distinguish between address span of a zone and the number

From David Mosberger

The patch below fixes a bug in nr_free_zone_pages() which shows when a
zone has hole.  The problem is due to the fact that "struct zone"
didn't keep track of the amount of real memory in a zone.  Because of
this, nr_free_zone_pages() simply assumed that a zone consists entirely
of real memory.  On machines with large holes, this has catastrophic
effects on VM performance, because the VM system ends up thinking that
there is plenty of memory left over in a zone, when in fact it may be
completely full.

The patch below fixes the problem by replacing the "size" member in
"struct zone" with "spanned_pages" and "present_pages" and updating
page_alloc.c.
parent 9d66d9e9
...@@ -120,7 +120,8 @@ struct zone { ...@@ -120,7 +120,8 @@ struct zone {
* rarely used fields: * rarely used fields:
*/ */
char *name; char *name;
unsigned long size; unsigned long spanned_pages; /* total size, including holes */
unsigned long present_pages; /* amount of memory (excluding holes) */
} ____cacheline_maxaligned_in_smp; } ____cacheline_maxaligned_in_smp;
#define ZONE_DMA 0 #define ZONE_DMA 0
......
...@@ -48,7 +48,7 @@ static int zone_balance_max[MAX_NR_ZONES] __initdata = { 255 , 255, 255, }; ...@@ -48,7 +48,7 @@ static int zone_balance_max[MAX_NR_ZONES] __initdata = { 255 , 255, 255, };
*/ */
static inline int bad_range(struct zone *zone, struct page *page) static inline int bad_range(struct zone *zone, struct page *page)
{ {
if (page_to_pfn(page) >= zone->zone_start_pfn + zone->size) if (page_to_pfn(page) >= zone->zone_start_pfn + zone->spanned_pages)
return 1; return 1;
if (page_to_pfn(page) < zone->zone_start_pfn) if (page_to_pfn(page) < zone->zone_start_pfn)
return 1; return 1;
...@@ -509,7 +509,7 @@ static unsigned int nr_free_zone_pages(int offset) ...@@ -509,7 +509,7 @@ static unsigned int nr_free_zone_pages(int offset)
struct zone *zone; struct zone *zone;
for (zone = *zonep++; zone; zone = *zonep++) { for (zone = *zonep++; zone; zone = *zonep++) {
unsigned long size = zone->size; unsigned long size = zone->present_pages;
unsigned long high = zone->pages_high; unsigned long high = zone->pages_high;
if (size > high) if (size > high)
sum += size - high; sum += size - high;
...@@ -681,7 +681,7 @@ void show_free_areas(void) ...@@ -681,7 +681,7 @@ void show_free_areas(void)
struct zone *zone = &pgdat->node_zones[type]; struct zone *zone = &pgdat->node_zones[type];
unsigned long nr, flags, order, total = 0; unsigned long nr, flags, order, total = 0;
if (!zone->size) if (!zone->present_pages)
continue; continue;
spin_lock_irqsave(&zone->lock, flags); spin_lock_irqsave(&zone->lock, flags);
...@@ -710,7 +710,7 @@ static int __init build_zonelists_node(pg_data_t *pgdat, struct zonelist *zoneli ...@@ -710,7 +710,7 @@ static int __init build_zonelists_node(pg_data_t *pgdat, struct zonelist *zoneli
BUG(); BUG();
case ZONE_HIGHMEM: case ZONE_HIGHMEM:
zone = pgdat->node_zones + ZONE_HIGHMEM; zone = pgdat->node_zones + ZONE_HIGHMEM;
if (zone->size) { if (zone->present_pages) {
#ifndef CONFIG_HIGHMEM #ifndef CONFIG_HIGHMEM
BUG(); BUG();
#endif #endif
...@@ -718,11 +718,11 @@ static int __init build_zonelists_node(pg_data_t *pgdat, struct zonelist *zoneli ...@@ -718,11 +718,11 @@ static int __init build_zonelists_node(pg_data_t *pgdat, struct zonelist *zoneli
} }
case ZONE_NORMAL: case ZONE_NORMAL:
zone = pgdat->node_zones + ZONE_NORMAL; zone = pgdat->node_zones + ZONE_NORMAL;
if (zone->size) if (zone->present_pages)
zonelist->zones[j++] = zone; zonelist->zones[j++] = zone;
case ZONE_DMA: case ZONE_DMA:
zone = pgdat->node_zones + ZONE_DMA; zone = pgdat->node_zones + ZONE_DMA;
if (zone->size) if (zone->present_pages)
zonelist->zones[j++] = zone; zonelist->zones[j++] = zone;
} }
...@@ -866,7 +866,8 @@ void __init free_area_init_core(pg_data_t *pgdat, ...@@ -866,7 +866,8 @@ void __init free_area_init_core(pg_data_t *pgdat,
realsize -= zholes_size[j]; realsize -= zholes_size[j];
printk(" %s zone: %lu pages\n", zone_names[j], realsize); printk(" %s zone: %lu pages\n", zone_names[j], realsize);
zone->size = size; zone->spanned_pages = size;
zone->present_pages = realsize;
zone->name = zone_names[j]; zone->name = zone_names[j];
spin_lock_init(&zone->lock); spin_lock_init(&zone->lock);
spin_lock_init(&zone->lru_lock); spin_lock_init(&zone->lru_lock);
...@@ -1034,7 +1035,7 @@ static int frag_show(struct seq_file *m, void *arg) ...@@ -1034,7 +1035,7 @@ static int frag_show(struct seq_file *m, void *arg)
int order; int order;
for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) { for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
if (!zone->size) if (!zone->present_pages)
continue; continue;
spin_lock_irqsave(&zone->lock, flags); spin_lock_irqsave(&zone->lock, flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment