diff options
Diffstat (limited to 'mm/page_cgroup.c')
| -rw-r--r-- | mm/page_cgroup.c | 63 | 
1 files changed, 41 insertions, 22 deletions
diff --git a/mm/page_cgroup.c b/mm/page_cgroup.c index f59d797dc5a..ab27ff75051 100644 --- a/mm/page_cgroup.c +++ b/mm/page_cgroup.c @@ -21,7 +21,7 @@ static unsigned long total_usage;  #if !defined(CONFIG_SPARSEMEM) -void __init pgdat_page_cgroup_init(struct pglist_data *pgdat) +void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat)  {  	pgdat->node_page_cgroup = NULL;  } @@ -49,6 +49,9 @@ static int __init alloc_node_page_cgroup(int nid)  	start_pfn = NODE_DATA(nid)->node_start_pfn;  	nr_pages = NODE_DATA(nid)->node_spanned_pages; +	if (!nr_pages) +		return 0; +  	table_size = sizeof(struct page_cgroup) * nr_pages;  	base = __alloc_bootmem_node_nopanic(NODE_DATA(nid), @@ -97,7 +100,8 @@ struct page_cgroup *lookup_page_cgroup(struct page *page)  	return section->page_cgroup + pfn;  } -int __meminit init_section_page_cgroup(unsigned long pfn) +/* __alloc_bootmem...() is protected by !slab_available() */ +int __init_refok init_section_page_cgroup(unsigned long pfn)  {  	struct mem_section *section;  	struct page_cgroup *base, *pc; @@ -106,19 +110,29 @@ int __meminit init_section_page_cgroup(unsigned long pfn)  	section = __pfn_to_section(pfn); -	if (section->page_cgroup) -		return 0; - -	nid = page_to_nid(pfn_to_page(pfn)); - -	table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION; -	if (slab_is_available()) { -		base = kmalloc_node(table_size, GFP_KERNEL, nid); -		if (!base) -			base = vmalloc_node(table_size, nid); -	} else { -		base = __alloc_bootmem_node_nopanic(NODE_DATA(nid), table_size, +	if (!section->page_cgroup) { +		nid = page_to_nid(pfn_to_page(pfn)); +		table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION; +		if (slab_is_available()) { +			base = kmalloc_node(table_size, GFP_KERNEL, nid); +			if (!base) +				base = vmalloc_node(table_size, nid); +		} else { +			base = __alloc_bootmem_node_nopanic(NODE_DATA(nid), +				table_size,  				PAGE_SIZE, __pa(MAX_DMA_ADDRESS)); +		} +	} else { +		/* + 		 * We don't have to allocate page_cgroup again, but +		 * address of memmap may be changed. So, we have to initialize +		 * again. +		 */ +		base = section->page_cgroup + pfn; +		table_size = 0; +		/* check address of memmap is changed or not. */ +		if (base->page == pfn_to_page(pfn)) +			return 0;  	}  	if (!base) { @@ -158,14 +172,14 @@ void __free_page_cgroup(unsigned long pfn)  	}  } -int online_page_cgroup(unsigned long start_pfn, +int __meminit online_page_cgroup(unsigned long start_pfn,  			unsigned long nr_pages,  			int nid)  {  	unsigned long start, end, pfn;  	int fail = 0; -	start = start_pfn & (PAGES_PER_SECTION - 1); +	start = start_pfn & ~(PAGES_PER_SECTION - 1);  	end = ALIGN(start_pfn + nr_pages, PAGES_PER_SECTION);  	for (pfn = start; !fail && pfn < end; pfn += PAGES_PER_SECTION) { @@ -183,12 +197,12 @@ int online_page_cgroup(unsigned long start_pfn,  	return -ENOMEM;  } -int offline_page_cgroup(unsigned long start_pfn, +int __meminit offline_page_cgroup(unsigned long start_pfn,  		unsigned long nr_pages, int nid)  {  	unsigned long start, end, pfn; -	start = start_pfn & (PAGES_PER_SECTION - 1); +	start = start_pfn & ~(PAGES_PER_SECTION - 1);  	end = ALIGN(start_pfn + nr_pages, PAGES_PER_SECTION);  	for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) @@ -197,7 +211,7 @@ int offline_page_cgroup(unsigned long start_pfn,  } -static int page_cgroup_callback(struct notifier_block *self, +static int __meminit page_cgroup_callback(struct notifier_block *self,  			       unsigned long action, void *arg)  {  	struct memory_notify *mn = arg; @@ -207,18 +221,23 @@ static int page_cgroup_callback(struct notifier_block *self,  		ret = online_page_cgroup(mn->start_pfn,  				   mn->nr_pages, mn->status_change_nid);  		break; -	case MEM_CANCEL_ONLINE:  	case MEM_OFFLINE:  		offline_page_cgroup(mn->start_pfn,  				mn->nr_pages, mn->status_change_nid);  		break; +	case MEM_CANCEL_ONLINE:  	case MEM_GOING_OFFLINE:  		break;  	case MEM_ONLINE:  	case MEM_CANCEL_OFFLINE:  		break;  	} -	ret = notifier_from_errno(ret); + +	if (ret) +		ret = notifier_from_errno(ret); +	else +		ret = NOTIFY_OK; +  	return ret;  } @@ -248,7 +267,7 @@ void __init page_cgroup_init(void)  	" want\n");  } -void __init pgdat_page_cgroup_init(struct pglist_data *pgdat) +void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat)  {  	return;  }  |