diff options
Diffstat (limited to 'mm/page_alloc.c')
| -rw-r--r-- | mm/page_alloc.c | 56 | 
1 files changed, 42 insertions, 14 deletions
| diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 4f59fa29eda8..0ea758b898fd 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -69,6 +69,7 @@  /* prevent >1 _updater_ of zone percpu pageset ->high and ->batch fields */  static DEFINE_MUTEX(pcp_batch_high_lock); +#define MIN_PERCPU_PAGELIST_FRACTION	(8)  #ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID  DEFINE_PER_CPU(int, numa_node); @@ -815,9 +816,21 @@ void __init init_cma_reserved_pageblock(struct page *page)  		set_page_count(p, 0);  	} while (++p, --i); -	set_page_refcounted(page);  	set_pageblock_migratetype(page, MIGRATE_CMA); -	__free_pages(page, pageblock_order); + +	if (pageblock_order >= MAX_ORDER) { +		i = pageblock_nr_pages; +		p = page; +		do { +			set_page_refcounted(p); +			__free_pages(p, MAX_ORDER - 1); +			p += MAX_ORDER_NR_PAGES; +		} while (i -= MAX_ORDER_NR_PAGES); +	} else { +		set_page_refcounted(page); +		__free_pages(page, pageblock_order); +	} +  	adjust_managed_page_count(page, pageblock_nr_pages);  }  #endif @@ -4145,7 +4158,7 @@ static void __meminit zone_init_free_lists(struct zone *zone)  	memmap_init_zone((size), (nid), (zone), (start_pfn), MEMMAP_EARLY)  #endif -static int __meminit zone_batchsize(struct zone *zone) +static int zone_batchsize(struct zone *zone)  {  #ifdef CONFIG_MMU  	int batch; @@ -4261,8 +4274,8 @@ static void pageset_set_high(struct per_cpu_pageset *p,  	pageset_update(&p->pcp, high, batch);  } -static void __meminit pageset_set_high_and_batch(struct zone *zone, -		struct per_cpu_pageset *pcp) +static void pageset_set_high_and_batch(struct zone *zone, +				       struct per_cpu_pageset *pcp)  {  	if (percpu_pagelist_fraction)  		pageset_set_high(pcp, @@ -5881,23 +5894,38 @@ int percpu_pagelist_fraction_sysctl_handler(struct ctl_table *table, int write,  	void __user *buffer, size_t *length, loff_t *ppos)  {  	struct zone *zone; -	unsigned int cpu; +	int old_percpu_pagelist_fraction;  	int ret; +	mutex_lock(&pcp_batch_high_lock); +	old_percpu_pagelist_fraction = percpu_pagelist_fraction; +  	ret = proc_dointvec_minmax(table, write, buffer, length, ppos); -	if (!write || (ret < 0)) -		return ret; +	if (!write || ret < 0) +		goto out; + +	/* Sanity checking to avoid pcp imbalance */ +	if (percpu_pagelist_fraction && +	    percpu_pagelist_fraction < MIN_PERCPU_PAGELIST_FRACTION) { +		percpu_pagelist_fraction = old_percpu_pagelist_fraction; +		ret = -EINVAL; +		goto out; +	} + +	/* No change? */ +	if (percpu_pagelist_fraction == old_percpu_pagelist_fraction) +		goto out; -	mutex_lock(&pcp_batch_high_lock);  	for_each_populated_zone(zone) { -		unsigned long  high; -		high = zone->managed_pages / percpu_pagelist_fraction; +		unsigned int cpu; +  		for_each_possible_cpu(cpu) -			pageset_set_high(per_cpu_ptr(zone->pageset, cpu), -					 high); +			pageset_set_high_and_batch(zone, +					per_cpu_ptr(zone->pageset, cpu));  	} +out:  	mutex_unlock(&pcp_batch_high_lock); -	return 0; +	return ret;  }  int hashdist = HASHDIST_DEFAULT; |