diff options
| -rw-r--r-- | drivers/base/memory.c | 31 | ||||
| -rw-r--r-- | include/linux/memory_hotplug.h | 2 | ||||
| -rw-r--r-- | mm/memory_hotplug.c | 33 |
3 files changed, 61 insertions, 5 deletions
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 44e7de6ce694..86c88216a503 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
| @@ -275,13 +275,11 @@ memory_block_action(unsigned long phys_index, unsigned long action) | |||
| 275 | return ret; | 275 | return ret; |
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | static int memory_block_change_state(struct memory_block *mem, | 278 | static int __memory_block_change_state(struct memory_block *mem, |
| 279 | unsigned long to_state, unsigned long from_state_req) | 279 | unsigned long to_state, unsigned long from_state_req) |
| 280 | { | 280 | { |
| 281 | int ret = 0; | 281 | int ret = 0; |
| 282 | 282 | ||
| 283 | mutex_lock(&mem->state_mutex); | ||
| 284 | |||
| 285 | if (mem->state != from_state_req) { | 283 | if (mem->state != from_state_req) { |
| 286 | ret = -EINVAL; | 284 | ret = -EINVAL; |
| 287 | goto out; | 285 | goto out; |
| @@ -309,10 +307,20 @@ static int memory_block_change_state(struct memory_block *mem, | |||
| 309 | break; | 307 | break; |
| 310 | } | 308 | } |
| 311 | out: | 309 | out: |
| 312 | mutex_unlock(&mem->state_mutex); | ||
| 313 | return ret; | 310 | return ret; |
| 314 | } | 311 | } |
| 315 | 312 | ||
| 313 | static int memory_block_change_state(struct memory_block *mem, | ||
| 314 | unsigned long to_state, unsigned long from_state_req) | ||
| 315 | { | ||
| 316 | int ret; | ||
| 317 | |||
| 318 | mutex_lock(&mem->state_mutex); | ||
| 319 | ret = __memory_block_change_state(mem, to_state, from_state_req); | ||
| 320 | mutex_unlock(&mem->state_mutex); | ||
| 321 | |||
| 322 | return ret; | ||
| 323 | } | ||
| 316 | static ssize_t | 324 | static ssize_t |
| 317 | store_mem_state(struct device *dev, | 325 | store_mem_state(struct device *dev, |
| 318 | struct device_attribute *attr, const char *buf, size_t count) | 326 | struct device_attribute *attr, const char *buf, size_t count) |
| @@ -653,6 +661,21 @@ int unregister_memory_section(struct mem_section *section) | |||
| 653 | } | 661 | } |
| 654 | 662 | ||
| 655 | /* | 663 | /* |
| 664 | * offline one memory block. If the memory block has been offlined, do nothing. | ||
| 665 | */ | ||
| 666 | int offline_memory_block(struct memory_block *mem) | ||
| 667 | { | ||
| 668 | int ret = 0; | ||
| 669 | |||
| 670 | mutex_lock(&mem->state_mutex); | ||
| 671 | if (mem->state != MEM_OFFLINE) | ||
| 672 | ret = __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE); | ||
| 673 | mutex_unlock(&mem->state_mutex); | ||
| 674 | |||
| 675 | return ret; | ||
| 676 | } | ||
| 677 | |||
| 678 | /* | ||
| 656 | * Initialize the sysfs support for memory devices... | 679 | * Initialize the sysfs support for memory devices... |
| 657 | */ | 680 | */ |
| 658 | int __init memory_dev_init(void) | 681 | int __init memory_dev_init(void) |
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index e64fe80eba96..95573ec4ee6c 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h | |||
| @@ -10,6 +10,7 @@ struct page; | |||
| 10 | struct zone; | 10 | struct zone; |
| 11 | struct pglist_data; | 11 | struct pglist_data; |
| 12 | struct mem_section; | 12 | struct mem_section; |
| 13 | struct memory_block; | ||
| 13 | 14 | ||
| 14 | #ifdef CONFIG_MEMORY_HOTPLUG | 15 | #ifdef CONFIG_MEMORY_HOTPLUG |
| 15 | 16 | ||
| @@ -234,6 +235,7 @@ extern int mem_online_node(int nid); | |||
| 234 | extern int add_memory(int nid, u64 start, u64 size); | 235 | extern int add_memory(int nid, u64 start, u64 size); |
| 235 | extern int arch_add_memory(int nid, u64 start, u64 size); | 236 | extern int arch_add_memory(int nid, u64 start, u64 size); |
| 236 | extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); | 237 | extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); |
| 238 | extern int offline_memory_block(struct memory_block *mem); | ||
| 237 | extern int remove_memory(u64 start, u64 size); | 239 | extern int remove_memory(u64 start, u64 size); |
| 238 | extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, | 240 | extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, |
| 239 | int nr_pages); | 241 | int nr_pages); |
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index dfc0a6134c7c..7d0797475a47 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
| @@ -1014,11 +1014,42 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages) | |||
| 1014 | 1014 | ||
| 1015 | int remove_memory(u64 start, u64 size) | 1015 | int remove_memory(u64 start, u64 size) |
| 1016 | { | 1016 | { |
| 1017 | struct memory_block *mem = NULL; | ||
| 1018 | struct mem_section *section; | ||
| 1017 | unsigned long start_pfn, end_pfn; | 1019 | unsigned long start_pfn, end_pfn; |
| 1020 | unsigned long pfn, section_nr; | ||
| 1021 | int ret; | ||
| 1018 | 1022 | ||
| 1019 | start_pfn = PFN_DOWN(start); | 1023 | start_pfn = PFN_DOWN(start); |
| 1020 | end_pfn = start_pfn + PFN_DOWN(size); | 1024 | end_pfn = start_pfn + PFN_DOWN(size); |
| 1021 | return __offline_pages(start_pfn, end_pfn, 120 * HZ); | 1025 | |
| 1026 | for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { | ||
| 1027 | section_nr = pfn_to_section_nr(pfn); | ||
| 1028 | if (!present_section_nr(section_nr)) | ||
| 1029 | continue; | ||
| 1030 | |||
| 1031 | section = __nr_to_section(section_nr); | ||
| 1032 | /* same memblock? */ | ||
| 1033 | if (mem) | ||
| 1034 | if ((section_nr >= mem->start_section_nr) && | ||
| 1035 | (section_nr <= mem->end_section_nr)) | ||
| 1036 | continue; | ||
| 1037 | |||
| 1038 | mem = find_memory_block_hinted(section, mem); | ||
| 1039 | if (!mem) | ||
| 1040 | continue; | ||
| 1041 | |||
| 1042 | ret = offline_memory_block(mem); | ||
| 1043 | if (ret) { | ||
| 1044 | kobject_put(&mem->dev.kobj); | ||
| 1045 | return ret; | ||
| 1046 | } | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | if (mem) | ||
| 1050 | kobject_put(&mem->dev.kobj); | ||
| 1051 | |||
| 1052 | return 0; | ||
| 1022 | } | 1053 | } |
| 1023 | #else | 1054 | #else |
| 1024 | int offline_pages(unsigned long start_pfn, unsigned long nr_pages) | 1055 | int offline_pages(unsigned long start_pfn, unsigned long nr_pages) |
