diff options
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r-- | mm/memory_hotplug.c | 40 |
1 files changed, 32 insertions, 8 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 821dee596377..030ce8a5bb0e 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include <linux/migrate.h> | 26 | #include <linux/migrate.h> |
27 | #include <linux/page-isolation.h> | 27 | #include <linux/page-isolation.h> |
28 | #include <linux/pfn.h> | 28 | #include <linux/pfn.h> |
29 | #include <linux/suspend.h> | ||
30 | #include <linux/mm_inline.h> | ||
29 | 31 | ||
30 | #include <asm/tlbflush.h> | 32 | #include <asm/tlbflush.h> |
31 | 33 | ||
@@ -70,7 +72,9 @@ static void get_page_bootmem(unsigned long info, struct page *page, int type) | |||
70 | atomic_inc(&page->_count); | 72 | atomic_inc(&page->_count); |
71 | } | 73 | } |
72 | 74 | ||
73 | void put_page_bootmem(struct page *page) | 75 | /* reference to __meminit __free_pages_bootmem is valid |
76 | * so use __ref to tell modpost not to generate a warning */ | ||
77 | void __ref put_page_bootmem(struct page *page) | ||
74 | { | 78 | { |
75 | int type; | 79 | int type; |
76 | 80 | ||
@@ -447,7 +451,8 @@ int online_pages(unsigned long pfn, unsigned long nr_pages) | |||
447 | } | 451 | } |
448 | #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ | 452 | #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ |
449 | 453 | ||
450 | static pg_data_t *hotadd_new_pgdat(int nid, u64 start) | 454 | /* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */ |
455 | static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start) | ||
451 | { | 456 | { |
452 | struct pglist_data *pgdat; | 457 | struct pglist_data *pgdat; |
453 | unsigned long zones_size[MAX_NR_ZONES] = {0}; | 458 | unsigned long zones_size[MAX_NR_ZONES] = {0}; |
@@ -484,14 +489,18 @@ int __ref add_memory(int nid, u64 start, u64 size) | |||
484 | struct resource *res; | 489 | struct resource *res; |
485 | int ret; | 490 | int ret; |
486 | 491 | ||
492 | lock_system_sleep(); | ||
493 | |||
487 | res = register_memory_resource(start, size); | 494 | res = register_memory_resource(start, size); |
495 | ret = -EEXIST; | ||
488 | if (!res) | 496 | if (!res) |
489 | return -EEXIST; | 497 | goto out; |
490 | 498 | ||
491 | if (!node_online(nid)) { | 499 | if (!node_online(nid)) { |
492 | pgdat = hotadd_new_pgdat(nid, start); | 500 | pgdat = hotadd_new_pgdat(nid, start); |
501 | ret = -ENOMEM; | ||
493 | if (!pgdat) | 502 | if (!pgdat) |
494 | return -ENOMEM; | 503 | goto out; |
495 | new_pgdat = 1; | 504 | new_pgdat = 1; |
496 | } | 505 | } |
497 | 506 | ||
@@ -514,7 +523,8 @@ int __ref add_memory(int nid, u64 start, u64 size) | |||
514 | BUG_ON(ret); | 523 | BUG_ON(ret); |
515 | } | 524 | } |
516 | 525 | ||
517 | return ret; | 526 | goto out; |
527 | |||
518 | error: | 528 | error: |
519 | /* rollback pgdat allocation and others */ | 529 | /* rollback pgdat allocation and others */ |
520 | if (new_pgdat) | 530 | if (new_pgdat) |
@@ -522,6 +532,8 @@ error: | |||
522 | if (res) | 532 | if (res) |
523 | release_memory_resource(res); | 533 | release_memory_resource(res); |
524 | 534 | ||
535 | out: | ||
536 | unlock_system_sleep(); | ||
525 | return ret; | 537 | return ret; |
526 | } | 538 | } |
527 | EXPORT_SYMBOL_GPL(add_memory); | 539 | EXPORT_SYMBOL_GPL(add_memory); |
@@ -663,6 +675,9 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn) | |||
663 | if (!ret) { /* Success */ | 675 | if (!ret) { /* Success */ |
664 | list_add_tail(&page->lru, &source); | 676 | list_add_tail(&page->lru, &source); |
665 | move_pages--; | 677 | move_pages--; |
678 | inc_zone_page_state(page, NR_ISOLATED_ANON + | ||
679 | page_is_file_cache(page)); | ||
680 | |||
666 | } else { | 681 | } else { |
667 | /* Becasue we don't have big zone->lock. we should | 682 | /* Becasue we don't have big zone->lock. we should |
668 | check this again here. */ | 683 | check this again here. */ |
@@ -685,7 +700,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn) | |||
685 | if (list_empty(&source)) | 700 | if (list_empty(&source)) |
686 | goto out; | 701 | goto out; |
687 | /* this function returns # of failed pages */ | 702 | /* this function returns # of failed pages */ |
688 | ret = migrate_pages(&source, hotremove_migrate_alloc, 0); | 703 | ret = migrate_pages(&source, hotremove_migrate_alloc, 0, 1); |
689 | 704 | ||
690 | out: | 705 | out: |
691 | return ret; | 706 | return ret; |
@@ -738,7 +753,7 @@ check_pages_isolated(unsigned long start_pfn, unsigned long end_pfn) | |||
738 | return offlined; | 753 | return offlined; |
739 | } | 754 | } |
740 | 755 | ||
741 | int offline_pages(unsigned long start_pfn, | 756 | static int offline_pages(unsigned long start_pfn, |
742 | unsigned long end_pfn, unsigned long timeout) | 757 | unsigned long end_pfn, unsigned long timeout) |
743 | { | 758 | { |
744 | unsigned long pfn, nr_pages, expire; | 759 | unsigned long pfn, nr_pages, expire; |
@@ -758,6 +773,8 @@ int offline_pages(unsigned long start_pfn, | |||
758 | if (!test_pages_in_a_zone(start_pfn, end_pfn)) | 773 | if (!test_pages_in_a_zone(start_pfn, end_pfn)) |
759 | return -EINVAL; | 774 | return -EINVAL; |
760 | 775 | ||
776 | lock_system_sleep(); | ||
777 | |||
761 | zone = page_zone(pfn_to_page(start_pfn)); | 778 | zone = page_zone(pfn_to_page(start_pfn)); |
762 | node = zone_to_nid(zone); | 779 | node = zone_to_nid(zone); |
763 | nr_pages = end_pfn - start_pfn; | 780 | nr_pages = end_pfn - start_pfn; |
@@ -765,7 +782,7 @@ int offline_pages(unsigned long start_pfn, | |||
765 | /* set above range as isolated */ | 782 | /* set above range as isolated */ |
766 | ret = start_isolate_page_range(start_pfn, end_pfn); | 783 | ret = start_isolate_page_range(start_pfn, end_pfn); |
767 | if (ret) | 784 | if (ret) |
768 | return ret; | 785 | goto out; |
769 | 786 | ||
770 | arg.start_pfn = start_pfn; | 787 | arg.start_pfn = start_pfn; |
771 | arg.nr_pages = nr_pages; | 788 | arg.nr_pages = nr_pages; |
@@ -838,11 +855,16 @@ repeat: | |||
838 | 855 | ||
839 | setup_per_zone_wmarks(); | 856 | setup_per_zone_wmarks(); |
840 | calculate_zone_inactive_ratio(zone); | 857 | calculate_zone_inactive_ratio(zone); |
858 | if (!node_present_pages(node)) { | ||
859 | node_clear_state(node, N_HIGH_MEMORY); | ||
860 | kswapd_stop(node); | ||
861 | } | ||
841 | 862 | ||
842 | vm_total_pages = nr_free_pagecache_pages(); | 863 | vm_total_pages = nr_free_pagecache_pages(); |
843 | writeback_set_ratelimit(); | 864 | writeback_set_ratelimit(); |
844 | 865 | ||
845 | memory_notify(MEM_OFFLINE, &arg); | 866 | memory_notify(MEM_OFFLINE, &arg); |
867 | unlock_system_sleep(); | ||
846 | return 0; | 868 | return 0; |
847 | 869 | ||
848 | failed_removal: | 870 | failed_removal: |
@@ -852,6 +874,8 @@ failed_removal: | |||
852 | /* pushback to free area */ | 874 | /* pushback to free area */ |
853 | undo_isolate_page_range(start_pfn, end_pfn); | 875 | undo_isolate_page_range(start_pfn, end_pfn); |
854 | 876 | ||
877 | out: | ||
878 | unlock_system_sleep(); | ||
855 | return ret; | 879 | return ret; |
856 | } | 880 | } |
857 | 881 | ||