diff options
Diffstat (limited to 'mm/memory_hotplug.c')
| -rw-r--r-- | mm/memory_hotplug.c | 68 | 
1 files changed, 65 insertions, 3 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index c46887b5a11e..6e7d8b21dbfa 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -34,6 +34,17 @@  #include "internal.h" +/* + * online_page_callback contains pointer to current page onlining function. + * Initially it is generic_online_page(). If it is required it could be + * changed by calling set_online_page_callback() for callback registration + * and restore_online_page_callback() for generic callback restore. + */ + +static void generic_online_page(struct page *page); + +static online_page_callback_t online_page_callback = generic_online_page; +  DEFINE_MUTEX(mem_hotplug_mutex);  void lock_memory_hotplug(void) @@ -361,23 +372,74 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,  }  EXPORT_SYMBOL_GPL(__remove_pages); -void online_page(struct page *page) +int set_online_page_callback(online_page_callback_t callback) +{ +	int rc = -EINVAL; + +	lock_memory_hotplug(); + +	if (online_page_callback == generic_online_page) { +		online_page_callback = callback; +		rc = 0; +	} + +	unlock_memory_hotplug(); + +	return rc; +} +EXPORT_SYMBOL_GPL(set_online_page_callback); + +int restore_online_page_callback(online_page_callback_t callback) +{ +	int rc = -EINVAL; + +	lock_memory_hotplug(); + +	if (online_page_callback == callback) { +		online_page_callback = generic_online_page; +		rc = 0; +	} + +	unlock_memory_hotplug(); + +	return rc; +} +EXPORT_SYMBOL_GPL(restore_online_page_callback); + +void __online_page_set_limits(struct page *page)  {  	unsigned long pfn = page_to_pfn(page); -	totalram_pages++;  	if (pfn >= num_physpages)  		num_physpages = pfn + 1; +} +EXPORT_SYMBOL_GPL(__online_page_set_limits); + +void __online_page_increment_counters(struct page *page) +{ +	totalram_pages++;  #ifdef CONFIG_HIGHMEM  	if (PageHighMem(page))  		totalhigh_pages++;  #endif +} +EXPORT_SYMBOL_GPL(__online_page_increment_counters); +void __online_page_free(struct page *page) +{  	ClearPageReserved(page);  	init_page_count(page);  	__free_page(page);  } +EXPORT_SYMBOL_GPL(__online_page_free); + +static void generic_online_page(struct page *page) +{ +	__online_page_set_limits(page); +	__online_page_increment_counters(page); +	__online_page_free(page); +}  static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,  			void *arg) @@ -388,7 +450,7 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,  	if (PageReserved(pfn_to_page(start_pfn)))  		for (i = 0; i < nr_pages; i++) {  			page = pfn_to_page(start_pfn + i); -			online_page(page); +			(*online_page_callback)(page);  			onlined_pages++;  		}  	*(unsigned long *)arg = onlined_pages;  |