diff options
Diffstat (limited to 'mm/memory_hotplug.c')
| -rw-r--r-- | mm/memory_hotplug.c | 70 |
1 files changed, 66 insertions, 4 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index c46887b5a11e..2168489c0bc9 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | #include <linux/pagemap.h> | 11 | #include <linux/pagemap.h> |
| 12 | #include <linux/bootmem.h> | 12 | #include <linux/bootmem.h> |
| 13 | #include <linux/compiler.h> | 13 | #include <linux/compiler.h> |
| 14 | #include <linux/module.h> | 14 | #include <linux/export.h> |
| 15 | #include <linux/pagevec.h> | 15 | #include <linux/pagevec.h> |
| 16 | #include <linux/writeback.h> | 16 | #include <linux/writeback.h> |
| 17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| @@ -34,6 +34,17 @@ | |||
| 34 | 34 | ||
| 35 | #include "internal.h" | 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 | DEFINE_MUTEX(mem_hotplug_mutex); | 48 | DEFINE_MUTEX(mem_hotplug_mutex); |
| 38 | 49 | ||
| 39 | void lock_memory_hotplug(void) | 50 | void lock_memory_hotplug(void) |
| @@ -361,23 +372,74 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn, | |||
| 361 | } | 372 | } |
| 362 | EXPORT_SYMBOL_GPL(__remove_pages); | 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) |
| 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) | ||
| 365 | { | 410 | { |
| 366 | unsigned long pfn = page_to_pfn(page); | 411 | unsigned long pfn = page_to_pfn(page); |
| 367 | 412 | ||
| 368 | totalram_pages++; | ||
| 369 | if (pfn >= num_physpages) | 413 | if (pfn >= num_physpages) |
| 370 | num_physpages = pfn + 1; | 414 | num_physpages = pfn + 1; |
| 415 | } | ||
| 416 | EXPORT_SYMBOL_GPL(__online_page_set_limits); | ||
| 417 | |||
| 418 | void __online_page_increment_counters(struct page *page) | ||
| 419 | { | ||
| 420 | totalram_pages++; | ||
| 371 | 421 | ||
| 372 | #ifdef CONFIG_HIGHMEM | 422 | #ifdef CONFIG_HIGHMEM |
| 373 | if (PageHighMem(page)) | 423 | if (PageHighMem(page)) |
| 374 | totalhigh_pages++; | 424 | totalhigh_pages++; |
| 375 | #endif | 425 | #endif |
| 426 | } | ||
| 427 | EXPORT_SYMBOL_GPL(__online_page_increment_counters); | ||
| 376 | 428 | ||
| 429 | void __online_page_free(struct page *page) | ||
| 430 | { | ||
| 377 | ClearPageReserved(page); | 431 | ClearPageReserved(page); |
| 378 | init_page_count(page); | 432 | init_page_count(page); |
| 379 | __free_page(page); | 433 | __free_page(page); |
| 380 | } | 434 | } |
| 435 | EXPORT_SYMBOL_GPL(__online_page_free); | ||
| 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 | } | ||
| 381 | 443 | ||
| 382 | static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, | 444 | static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, |
| 383 | void *arg) | 445 | void *arg) |
| @@ -388,7 +450,7 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, | |||
| 388 | if (PageReserved(pfn_to_page(start_pfn))) | 450 | if (PageReserved(pfn_to_page(start_pfn))) |
| 389 | for (i = 0; i < nr_pages; i++) { | 451 | for (i = 0; i < nr_pages; i++) { |
| 390 | page = pfn_to_page(start_pfn + i); | 452 | page = pfn_to_page(start_pfn + i); |
| 391 | online_page(page); | 453 | (*online_page_callback)(page); |
| 392 | onlined_pages++; | 454 | onlined_pages++; |
| 393 | } | 455 | } |
| 394 | *(unsigned long *)arg = onlined_pages; | 456 | *(unsigned long *)arg = onlined_pages; |
