Commit 9d0ad8ca43ce8023bb834a409c2258bd7197fb05

Authored by Daniel Kiper
Committed by Linus Torvalds
1 parent ef22f6a70c

mm: extend memory hotplug API to allow memory hotplug in virtual machines

This patch contains online_page_callback and apropriate functions for
registering/unregistering online page callbacks.  It allows to do some
machine specific tasks during online page stage which is required to
implement memory hotplug in virtual machines.  Currently this patch is
required by latest memory hotplug support for Xen balloon driver patch
which will be posted soon.

Additionally, originial online_page() function was splited into
following functions doing "atomic" operations:

  - __online_page_set_limits() - set new limits for memory management code,
  - __online_page_increment_counters() - increment totalram_pages and totalhigh_pages,
  - __online_page_free() - free page to allocator.

It was done to:
  - not duplicate existing code,
  - ease hotplug code devolpment by usage of well defined interface,
  - avoid stupid bugs which are unavoidable when the same code
    (by design) is developed in many places.

[akpm@linux-foundation.org: use explicit indirect-call syntax]
Signed-off-by: Daniel Kiper <dkiper@net-space.pl>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Ian Campbell <ian.campbell@citrix.com>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 2 changed files with 74 additions and 5 deletions Side-by-side Diff

include/linux/memory_hotplug.h
... ... @@ -68,11 +68,18 @@
68 68 extern int zone_grow_free_lists(struct zone *zone, unsigned long new_nr_pages);
69 69 extern int zone_grow_waitqueues(struct zone *zone, unsigned long nr_pages);
70 70 extern int add_one_highpage(struct page *page, int pfn, int bad_ppro);
71   -/* need some defines for these for archs that don't support it */
72   -extern void online_page(struct page *page);
73 71 /* VM interface that may be used by firmware interface */
74 72 extern int online_pages(unsigned long, unsigned long);
75 73 extern void __offline_isolated_pages(unsigned long, unsigned long);
  74 +
  75 +typedef void (*online_page_callback_t)(struct page *page);
  76 +
  77 +extern int set_online_page_callback(online_page_callback_t callback);
  78 +extern int restore_online_page_callback(online_page_callback_t callback);
  79 +
  80 +extern void __online_page_set_limits(struct page *page);
  81 +extern void __online_page_increment_counters(struct page *page);
  82 +extern void __online_page_free(struct page *page);
76 83  
77 84 #ifdef CONFIG_MEMORY_HOTREMOVE
78 85 extern bool is_pageblock_removable_nolock(struct page *page);
... ... @@ -34,6 +34,17 @@
34 34  
35 35 #include "internal.h"
36 36  
  37 +/*
  38 + * online_page_callback contains pointer to current page onlining function.
  39 + * Initially it is generic_online_page(). If it is required it could be
  40 + * changed by calling set_online_page_callback() for callback registration
  41 + * and restore_online_page_callback() for generic callback restore.
  42 + */
  43 +
  44 +static void generic_online_page(struct page *page);
  45 +
  46 +static online_page_callback_t online_page_callback = generic_online_page;
  47 +
37 48 DEFINE_MUTEX(mem_hotplug_mutex);
38 49  
39 50 void lock_memory_hotplug(void)
40 51  
41 52  
42 53  
43 54  
44 55  
45 56  
46 57  
47 58  
... ... @@ -361,24 +372,75 @@
361 372 }
362 373 EXPORT_SYMBOL_GPL(__remove_pages);
363 374  
364   -void online_page(struct page *page)
  375 +int set_online_page_callback(online_page_callback_t callback)
365 376 {
  377 + int rc = -EINVAL;
  378 +
  379 + lock_memory_hotplug();
  380 +
  381 + if (online_page_callback == generic_online_page) {
  382 + online_page_callback = callback;
  383 + rc = 0;
  384 + }
  385 +
  386 + unlock_memory_hotplug();
  387 +
  388 + return rc;
  389 +}
  390 +EXPORT_SYMBOL_GPL(set_online_page_callback);
  391 +
  392 +int restore_online_page_callback(online_page_callback_t callback)
  393 +{
  394 + int rc = -EINVAL;
  395 +
  396 + lock_memory_hotplug();
  397 +
  398 + if (online_page_callback == callback) {
  399 + online_page_callback = generic_online_page;
  400 + rc = 0;
  401 + }
  402 +
  403 + unlock_memory_hotplug();
  404 +
  405 + return rc;
  406 +}
  407 +EXPORT_SYMBOL_GPL(restore_online_page_callback);
  408 +
  409 +void __online_page_set_limits(struct page *page)
  410 +{
366 411 unsigned long pfn = page_to_pfn(page);
367 412  
368   - totalram_pages++;
369 413 if (pfn >= num_physpages)
370 414 num_physpages = pfn + 1;
  415 +}
  416 +EXPORT_SYMBOL_GPL(__online_page_set_limits);
371 417  
  418 +void __online_page_increment_counters(struct page *page)
  419 +{
  420 + totalram_pages++;
  421 +
372 422 #ifdef CONFIG_HIGHMEM
373 423 if (PageHighMem(page))
374 424 totalhigh_pages++;
375 425 #endif
  426 +}
  427 +EXPORT_SYMBOL_GPL(__online_page_increment_counters);
376 428  
  429 +void __online_page_free(struct page *page)
  430 +{
377 431 ClearPageReserved(page);
378 432 init_page_count(page);
379 433 __free_page(page);
380 434 }
  435 +EXPORT_SYMBOL_GPL(__online_page_free);
381 436  
  437 +static void generic_online_page(struct page *page)
  438 +{
  439 + __online_page_set_limits(page);
  440 + __online_page_increment_counters(page);
  441 + __online_page_free(page);
  442 +}
  443 +
382 444 static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
383 445 void *arg)
384 446 {
... ... @@ -388,7 +450,7 @@
388 450 if (PageReserved(pfn_to_page(start_pfn)))
389 451 for (i = 0; i < nr_pages; i++) {
390 452 page = pfn_to_page(start_pfn + i);
391   - online_page(page);
  453 + (*online_page_callback)(page);
392 454 onlined_pages++;
393 455 }
394 456 *(unsigned long *)arg = onlined_pages;