diff options
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r-- | mm/memory_hotplug.c | 113 |
1 files changed, 98 insertions, 15 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index c3e66ae411fd..518baa896e83 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -106,6 +106,7 @@ static void get_page_bootmem(unsigned long info, struct page *page, | |||
106 | void __ref put_page_bootmem(struct page *page) | 106 | void __ref put_page_bootmem(struct page *page) |
107 | { | 107 | { |
108 | unsigned long type; | 108 | unsigned long type; |
109 | static DEFINE_MUTEX(ppb_lock); | ||
109 | 110 | ||
110 | type = (unsigned long) page->lru.next; | 111 | type = (unsigned long) page->lru.next; |
111 | BUG_ON(type < MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE || | 112 | BUG_ON(type < MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE || |
@@ -115,7 +116,14 @@ void __ref put_page_bootmem(struct page *page) | |||
115 | ClearPagePrivate(page); | 116 | ClearPagePrivate(page); |
116 | set_page_private(page, 0); | 117 | set_page_private(page, 0); |
117 | INIT_LIST_HEAD(&page->lru); | 118 | INIT_LIST_HEAD(&page->lru); |
119 | |||
120 | /* | ||
121 | * Please refer to comment for __free_pages_bootmem() | ||
122 | * for why we serialize here. | ||
123 | */ | ||
124 | mutex_lock(&ppb_lock); | ||
118 | __free_pages_bootmem(page, 0); | 125 | __free_pages_bootmem(page, 0); |
126 | mutex_unlock(&ppb_lock); | ||
119 | } | 127 | } |
120 | 128 | ||
121 | } | 129 | } |
@@ -581,11 +589,19 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, | |||
581 | return 0; | 589 | return 0; |
582 | } | 590 | } |
583 | 591 | ||
592 | #ifdef CONFIG_MOVABLE_NODE | ||
593 | /* when CONFIG_MOVABLE_NODE, we allow online node don't have normal memory */ | ||
594 | static bool can_online_high_movable(struct zone *zone) | ||
595 | { | ||
596 | return true; | ||
597 | } | ||
598 | #else /* #ifdef CONFIG_MOVABLE_NODE */ | ||
584 | /* ensure every online node has NORMAL memory */ | 599 | /* ensure every online node has NORMAL memory */ |
585 | static bool can_online_high_movable(struct zone *zone) | 600 | static bool can_online_high_movable(struct zone *zone) |
586 | { | 601 | { |
587 | return node_state(zone_to_nid(zone), N_NORMAL_MEMORY); | 602 | return node_state(zone_to_nid(zone), N_NORMAL_MEMORY); |
588 | } | 603 | } |
604 | #endif /* #ifdef CONFIG_MOVABLE_NODE */ | ||
589 | 605 | ||
590 | /* check which state of node_states will be changed when online memory */ | 606 | /* check which state of node_states will be changed when online memory */ |
591 | static void node_states_check_changes_online(unsigned long nr_pages, | 607 | static void node_states_check_changes_online(unsigned long nr_pages, |
@@ -595,13 +611,15 @@ static void node_states_check_changes_online(unsigned long nr_pages, | |||
595 | enum zone_type zone_last = ZONE_NORMAL; | 611 | enum zone_type zone_last = ZONE_NORMAL; |
596 | 612 | ||
597 | /* | 613 | /* |
598 | * If we have HIGHMEM, node_states[N_NORMAL_MEMORY] contains nodes | 614 | * If we have HIGHMEM or movable node, node_states[N_NORMAL_MEMORY] |
599 | * which have 0...ZONE_NORMAL, set zone_last to ZONE_NORMAL. | 615 | * contains nodes which have zones of 0...ZONE_NORMAL, |
616 | * set zone_last to ZONE_NORMAL. | ||
600 | * | 617 | * |
601 | * If we don't have HIGHMEM, node_states[N_NORMAL_MEMORY] contains nodes | 618 | * If we don't have HIGHMEM nor movable node, |
602 | * which have 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE. | 619 | * node_states[N_NORMAL_MEMORY] contains nodes which have zones of |
620 | * 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE. | ||
603 | */ | 621 | */ |
604 | if (N_HIGH_MEMORY == N_NORMAL_MEMORY) | 622 | if (N_MEMORY == N_NORMAL_MEMORY) |
605 | zone_last = ZONE_MOVABLE; | 623 | zone_last = ZONE_MOVABLE; |
606 | 624 | ||
607 | /* | 625 | /* |
@@ -615,12 +633,34 @@ static void node_states_check_changes_online(unsigned long nr_pages, | |||
615 | else | 633 | else |
616 | arg->status_change_nid_normal = -1; | 634 | arg->status_change_nid_normal = -1; |
617 | 635 | ||
636 | #ifdef CONFIG_HIGHMEM | ||
637 | /* | ||
638 | * If we have movable node, node_states[N_HIGH_MEMORY] | ||
639 | * contains nodes which have zones of 0...ZONE_HIGHMEM, | ||
640 | * set zone_last to ZONE_HIGHMEM. | ||
641 | * | ||
642 | * If we don't have movable node, node_states[N_NORMAL_MEMORY] | ||
643 | * contains nodes which have zones of 0...ZONE_MOVABLE, | ||
644 | * set zone_last to ZONE_MOVABLE. | ||
645 | */ | ||
646 | zone_last = ZONE_HIGHMEM; | ||
647 | if (N_MEMORY == N_HIGH_MEMORY) | ||
648 | zone_last = ZONE_MOVABLE; | ||
649 | |||
650 | if (zone_idx(zone) <= zone_last && !node_state(nid, N_HIGH_MEMORY)) | ||
651 | arg->status_change_nid_high = nid; | ||
652 | else | ||
653 | arg->status_change_nid_high = -1; | ||
654 | #else | ||
655 | arg->status_change_nid_high = arg->status_change_nid_normal; | ||
656 | #endif | ||
657 | |||
618 | /* | 658 | /* |
619 | * if the node don't have memory befor online, we will need to | 659 | * if the node don't have memory befor online, we will need to |
620 | * set the node to node_states[N_HIGH_MEMORY] after the memory | 660 | * set the node to node_states[N_MEMORY] after the memory |
621 | * is online. | 661 | * is online. |
622 | */ | 662 | */ |
623 | if (!node_state(nid, N_HIGH_MEMORY)) | 663 | if (!node_state(nid, N_MEMORY)) |
624 | arg->status_change_nid = nid; | 664 | arg->status_change_nid = nid; |
625 | else | 665 | else |
626 | arg->status_change_nid = -1; | 666 | arg->status_change_nid = -1; |
@@ -631,7 +671,10 @@ static void node_states_set_node(int node, struct memory_notify *arg) | |||
631 | if (arg->status_change_nid_normal >= 0) | 671 | if (arg->status_change_nid_normal >= 0) |
632 | node_set_state(node, N_NORMAL_MEMORY); | 672 | node_set_state(node, N_NORMAL_MEMORY); |
633 | 673 | ||
634 | node_set_state(node, N_HIGH_MEMORY); | 674 | if (arg->status_change_nid_high >= 0) |
675 | node_set_state(node, N_HIGH_MEMORY); | ||
676 | |||
677 | node_set_state(node, N_MEMORY); | ||
635 | } | 678 | } |
636 | 679 | ||
637 | 680 | ||
@@ -713,6 +756,7 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ | |||
713 | return ret; | 756 | return ret; |
714 | } | 757 | } |
715 | 758 | ||
759 | zone->managed_pages += onlined_pages; | ||
716 | zone->present_pages += onlined_pages; | 760 | zone->present_pages += onlined_pages; |
717 | zone->zone_pgdat->node_present_pages += onlined_pages; | 761 | zone->zone_pgdat->node_present_pages += onlined_pages; |
718 | if (onlined_pages) { | 762 | if (onlined_pages) { |
@@ -1066,6 +1110,13 @@ check_pages_isolated(unsigned long start_pfn, unsigned long end_pfn) | |||
1066 | return offlined; | 1110 | return offlined; |
1067 | } | 1111 | } |
1068 | 1112 | ||
1113 | #ifdef CONFIG_MOVABLE_NODE | ||
1114 | /* when CONFIG_MOVABLE_NODE, we allow online node don't have normal memory */ | ||
1115 | static bool can_offline_normal(struct zone *zone, unsigned long nr_pages) | ||
1116 | { | ||
1117 | return true; | ||
1118 | } | ||
1119 | #else /* #ifdef CONFIG_MOVABLE_NODE */ | ||
1069 | /* ensure the node has NORMAL memory if it is still online */ | 1120 | /* ensure the node has NORMAL memory if it is still online */ |
1070 | static bool can_offline_normal(struct zone *zone, unsigned long nr_pages) | 1121 | static bool can_offline_normal(struct zone *zone, unsigned long nr_pages) |
1071 | { | 1122 | { |
@@ -1089,6 +1140,7 @@ static bool can_offline_normal(struct zone *zone, unsigned long nr_pages) | |||
1089 | */ | 1140 | */ |
1090 | return present_pages == 0; | 1141 | return present_pages == 0; |
1091 | } | 1142 | } |
1143 | #endif /* #ifdef CONFIG_MOVABLE_NODE */ | ||
1092 | 1144 | ||
1093 | /* check which state of node_states will be changed when offline memory */ | 1145 | /* check which state of node_states will be changed when offline memory */ |
1094 | static void node_states_check_changes_offline(unsigned long nr_pages, | 1146 | static void node_states_check_changes_offline(unsigned long nr_pages, |
@@ -1099,13 +1151,15 @@ static void node_states_check_changes_offline(unsigned long nr_pages, | |||
1099 | enum zone_type zt, zone_last = ZONE_NORMAL; | 1151 | enum zone_type zt, zone_last = ZONE_NORMAL; |
1100 | 1152 | ||
1101 | /* | 1153 | /* |
1102 | * If we have HIGHMEM, node_states[N_NORMAL_MEMORY] contains nodes | 1154 | * If we have HIGHMEM or movable node, node_states[N_NORMAL_MEMORY] |
1103 | * which have 0...ZONE_NORMAL, set zone_last to ZONE_NORMAL. | 1155 | * contains nodes which have zones of 0...ZONE_NORMAL, |
1156 | * set zone_last to ZONE_NORMAL. | ||
1104 | * | 1157 | * |
1105 | * If we don't have HIGHMEM, node_states[N_NORMAL_MEMORY] contains nodes | 1158 | * If we don't have HIGHMEM nor movable node, |
1106 | * which have 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE. | 1159 | * node_states[N_NORMAL_MEMORY] contains nodes which have zones of |
1160 | * 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE. | ||
1107 | */ | 1161 | */ |
1108 | if (N_HIGH_MEMORY == N_NORMAL_MEMORY) | 1162 | if (N_MEMORY == N_NORMAL_MEMORY) |
1109 | zone_last = ZONE_MOVABLE; | 1163 | zone_last = ZONE_MOVABLE; |
1110 | 1164 | ||
1111 | /* | 1165 | /* |
@@ -1122,6 +1176,30 @@ static void node_states_check_changes_offline(unsigned long nr_pages, | |||
1122 | else | 1176 | else |
1123 | arg->status_change_nid_normal = -1; | 1177 | arg->status_change_nid_normal = -1; |
1124 | 1178 | ||
1179 | #ifdef CONFIG_HIGHMEM | ||
1180 | /* | ||
1181 | * If we have movable node, node_states[N_HIGH_MEMORY] | ||
1182 | * contains nodes which have zones of 0...ZONE_HIGHMEM, | ||
1183 | * set zone_last to ZONE_HIGHMEM. | ||
1184 | * | ||
1185 | * If we don't have movable node, node_states[N_NORMAL_MEMORY] | ||
1186 | * contains nodes which have zones of 0...ZONE_MOVABLE, | ||
1187 | * set zone_last to ZONE_MOVABLE. | ||
1188 | */ | ||
1189 | zone_last = ZONE_HIGHMEM; | ||
1190 | if (N_MEMORY == N_HIGH_MEMORY) | ||
1191 | zone_last = ZONE_MOVABLE; | ||
1192 | |||
1193 | for (; zt <= zone_last; zt++) | ||
1194 | present_pages += pgdat->node_zones[zt].present_pages; | ||
1195 | if (zone_idx(zone) <= zone_last && nr_pages >= present_pages) | ||
1196 | arg->status_change_nid_high = zone_to_nid(zone); | ||
1197 | else | ||
1198 | arg->status_change_nid_high = -1; | ||
1199 | #else | ||
1200 | arg->status_change_nid_high = arg->status_change_nid_normal; | ||
1201 | #endif | ||
1202 | |||
1125 | /* | 1203 | /* |
1126 | * node_states[N_HIGH_MEMORY] contains nodes which have 0...ZONE_MOVABLE | 1204 | * node_states[N_HIGH_MEMORY] contains nodes which have 0...ZONE_MOVABLE |
1127 | */ | 1205 | */ |
@@ -1146,9 +1224,13 @@ static void node_states_clear_node(int node, struct memory_notify *arg) | |||
1146 | if (arg->status_change_nid_normal >= 0) | 1224 | if (arg->status_change_nid_normal >= 0) |
1147 | node_clear_state(node, N_NORMAL_MEMORY); | 1225 | node_clear_state(node, N_NORMAL_MEMORY); |
1148 | 1226 | ||
1149 | if ((N_HIGH_MEMORY != N_NORMAL_MEMORY) && | 1227 | if ((N_MEMORY != N_NORMAL_MEMORY) && |
1150 | (arg->status_change_nid >= 0)) | 1228 | (arg->status_change_nid_high >= 0)) |
1151 | node_clear_state(node, N_HIGH_MEMORY); | 1229 | node_clear_state(node, N_HIGH_MEMORY); |
1230 | |||
1231 | if ((N_MEMORY != N_HIGH_MEMORY) && | ||
1232 | (arg->status_change_nid >= 0)) | ||
1233 | node_clear_state(node, N_MEMORY); | ||
1152 | } | 1234 | } |
1153 | 1235 | ||
1154 | static int __ref __offline_pages(unsigned long start_pfn, | 1236 | static int __ref __offline_pages(unsigned long start_pfn, |
@@ -1248,6 +1330,7 @@ repeat: | |||
1248 | /* reset pagetype flags and makes migrate type to be MOVABLE */ | 1330 | /* reset pagetype flags and makes migrate type to be MOVABLE */ |
1249 | undo_isolate_page_range(start_pfn, end_pfn, MIGRATE_MOVABLE); | 1331 | undo_isolate_page_range(start_pfn, end_pfn, MIGRATE_MOVABLE); |
1250 | /* removal success */ | 1332 | /* removal success */ |
1333 | zone->managed_pages -= offlined_pages; | ||
1251 | zone->present_pages -= offlined_pages; | 1334 | zone->present_pages -= offlined_pages; |
1252 | zone->zone_pgdat->node_present_pages -= offlined_pages; | 1335 | zone->zone_pgdat->node_present_pages -= offlined_pages; |
1253 | totalram_pages -= offlined_pages; | 1336 | totalram_pages -= offlined_pages; |