memory-hotplug: hot-remove physical memory
Subsystems (13)
v5 cover memory-hotplug: hot-remove physical memory
This patch series aims to support physical memory hot-remove.
The patches can free/remove following things:
- acpi_memory_info : [RFC PATCH 4/19]
- /sys/firmware/memmap/X/{end, start, type} : [RFC PATCH 8/19]
- iomem_resource : [RFC PATCH 9/19] - mem_section and related sysfs files : [RFC PATCH 10-11, 13-16/19] - page table of removed memory : [RFC PATCH 12/19] - node and related sysfs files : [RFC PATCH 18-19/19]
If you find lack of function for physical memory hot-remove, please let me know.
change log of v5:
* merge the patchset to clear page table and the patchset to hot remove memory(from ishimatsu) to one big patchset.
[RFC PATCH v5 1/19]
* rename remove_memory() to offline_memory()/offline_pages()
[RFC PATCH v5 2/19]
* new patch: implement offline_memory(). This function offlines pages, update memory block's state, and notify the userspace that the memory block's state is changed.
[RFC PATCH v5 4/19]
* offline and remove memory in acpi_memory_disable_device() too.
[RFC PATCH v5 17/19]
* new patch: add a new function __remove_zone() to revert the things done in the function __add_zone().
[RFC PATCH v5 18/19]
* flush work befor reseting node device.
change log of v4:
* remove "memory-hotplug : unify argument of firmware_map_add_early/hotplug" from the patch series, since the patch is a bugfix. It is being disccussed on other thread. But for testing the patch series, the patch is needed. So I added the patch as [PATCH 0/13].
[RFC PATCH v4 2/13]
* check memory is online or not at remove_memory()
* add memory_add_physaddr_to_nid() to acpi_memory_device_remove() for getting node id
[RFC PATCH v4 3/13]
* create new patch : check memory is online or not at online_pages()
[RFC PATCH v4 4/13]
* add __ref section to remove_memory()
* call firmware_map_remove_entry() before remove_sysfs_fw_map_entry()
[RFC PATCH v4 11/13]
* rewrite register_page_bootmem_memmap() for removing page used as PT/PMD
change log of v3:
* rebase to 3.5.0-rc6
[RFC PATCH v2 2/13]
* remove extra kobject_put()
* The patch was commented by Wen. Wen's comment is "acpi_memory_device_remove() should ignore a return value of remove_memory() since caller does not care the return value". But I did not change it since I think caller should care the return value. And I am trying to fix it as follow:
https://lkml.org/lkml/2012/7/5/624
[RFC PATCH v2 4/13]
* remove a firmware_memmap_entry allocated by kzmalloc()
change log of v2:
[RFC PATCH v2 2/13]
* check whether memory block is offline or not before calling offline_memory()
* check whether section is valid or not in is_memblk_offline()
* call kobject_put() for each memory_block in is_memblk_offline()
[RFC PATCH v2 3/13]
* unify the end argument of firmware_map_add_early/hotplug
[RFC PATCH v2 4/13]
* add release_firmware_map_entry() for freeing firmware_map_entry
[RFC PATCH v2 6/13]
* add release_memory_block() for freeing memory_block
[RFC PATCH v2 11/13]
* fix wrong arguments of free_pages()
Wen Congyang (5):
memory-hotplug: implement offline_memory()
memory-hotplug: store the node id in acpi_memory_device
memory-hotplug: export the function acpi_bus_remove()
memory-hotplug: call acpi_bus_remove() to remove memory device
memory-hotplug: introduce new function arch_remove_memory()
Yasuaki Ishimatsu (14):
memory-hotplug: rename remove_memory() to
offline_memory()/offline_pages()
memory-hotplug: offline and remove memory when removing the memory
device
memory-hotplug: check whether memory is present or not
memory-hotplug: remove /sys/firmware/memmap/X sysfs
memory-hotplug: does not release memory region in PAGES_PER_SECTION
chunks
memory-hotplug: add memory_block_release
memory-hotplug: remove_memory calls __remove_pages
memory-hotplug: check page type in get_page_bootmem
memory-hotplug: move register_page_bootmem_info_node and
put_page_bootmem for sparse-vmemmap
memory-hotplug: implement register_page_bootmem_info_section of
sparse-vmemmap
memory-hotplug: free memmap of sparse-vmemmap
memory_hotplug: clear zone when the memory is removed
memory-hotplug: add node_device_release
memory-hotplug: remove sysfs file of node
arch/ia64/mm/init.c | 16 + arch/powerpc/mm/mem.c | 14 + arch/powerpc/platforms/pseries/hotplug-memory.c | 16 +- arch/s390/mm/init.c | 8 + arch/sh/mm/init.c | 15 + arch/tile/mm/init.c | 8 + arch/x86/include/asm/pgtable_types.h | 1 + arch/x86/mm/init_32.c | 10 + arch/x86/mm/init_64.c | 333 ++++++++++++++++++++++ arch/x86/mm/pageattr.c | 47 ++-- drivers/acpi/acpi_memhotplug.c | 51 +++- drivers/acpi/scan.c | 3 +- drivers/base/memory.c | 90 ++++++- drivers/base/node.c | 8 + drivers/firmware/memmap.c | 78 +++++- include/acpi/acpi_bus.h | 1 + include/linux/firmware-map.h | 6 + include/linux/memory.h | 5 + include/linux/memory_hotplug.h | 25 +- include/linux/mm.h | 5 +- include/linux/mmzone.h | 19 ++ mm/memory_hotplug.c | 337 +++++++++++++++++++++-- mm/sparse.c | 5 +- 23 files changed, 1010 insertions(+), 91 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
cover firmware_map : unify argument of firmware_map_add_early/hotplug
From: Yasuaki Ishimatsu <[email protected]>
There are two ways to create /sys/firmware/memmap/X sysfs:
- firmware_map_add_early
When the system starts, it is calledd from e820_reserve_resources()
- firmware_map_add_hotplug
When the memory is hot plugged, it is called from add_memory()
But these functions are called without unifying value of end argument as below:
- end argument of firmware_map_add_early() : start + size - 1
- end argument of firmware_map_add_hogplug() : start + size
The patch unifies them to "start + size". Even if applying the patch, /sys/firmware/memmap/X/end file content does not change.
--- arch/x86/kernel/e820.c | 2 +- drivers/firmware/memmap.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-)
arch/x86/kernel/e820.c +1 -1
@@ -944,7 +944,7 @@ void __init e820_reserve_resources(void)for (i =0 ; i < e820_saved.nr_map; i++) {struct e820entry *entry = &e820_saved.map[i];firmware_map_add_early (entry->addr, - entry->addr + entry->size -1 , + entry->addr + entry->size,e820_type_to_string (entry->type)); } }
drivers/firmware/memmap.c +4 -4
@@ -98,7 +98,7 @@ static LIST_HEAD(map_entries);/** * firmware_map_add_entry() - Does the real work to add a firmware memmap entry. * @start: Start of the memory range. -* @end: End of the memory range (inclusive). +* @end: End of the memory range. * @type: Type of the memory range. * @entry: Pre-allocated (either kmalloc() or bootmem allocator), uninitialised * entry.
@@ -113,7 +113,7 @@ static int firmware_map_add_entry(u64 stBUG_ON (start > end); entry->start = start; - entry->end = end; + entry->end = end -1 ; entry->type = type;INIT_LIST_HEAD (&entry->list);kobject_init (&entry->kobj, &memmap_ktype);
@@ -148,7 +148,7 @@ static int add_sysfs_fw_map_entry(struct* firmware_map_add_hotplug() - Adds a firmware mapping entry when we do * memory hotplug. * @start: Start of the memory range. -* @end: End of the memory range (inclusive). +* @end: End of the memory range. * @type: Type of the memory range. * * Adds a firmware mapping entry. This function is for memory hotplug, it is
@@ -175,7 +175,7 @@ int __meminit firmware_map_add_hotplug(u/** * firmware_map_add_early() - Adds a firmware mapping entry. * @start: Start of the memory range. -* @end: End of the memory range (inclusive). +* @end: End of the memory range. * @type: Type of the memory range. * * Adds a firmware mapping entry. This function uses the bootmem allocator
PATCH 1/1 remove memory info from list before freeing it
In reply to Wen CongyangWe free info, but we forget to remove it from the list. It will cause unexpected problem when we access the list next time.
--- drivers/acpi/acpi_memhotplug.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
drivers/acpi/acpi_memhotplug.c +1 -0
@@ -323,6 +323,7 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)if (result)return result; } +list_del (&info->list);kfree (info); }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 1/19 memory-hotplug: rename remove_memory() to offline_memory()/offline_pages()
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
remove_memory() only try to offline pages. It is called in two cases:
1. hot remove a memory device
2. echo offline >/sys/devices/system/memory/memoryXX/state
In the 1st case, we should also change memory block's state, and notify the userspace that the memory block's state is changed after offlining pages.
So rename remove_memory() to offline_memory()/offline_pages(). And in the 1st case, offline_memory() will be used. The function offline_memory() is not implemented. In the 2nd case, offline_pages() will be used.
--- drivers/acpi/acpi_memhotplug.c | 2 +- drivers/base/memory.c | 9 +++------ include/linux/memory_hotplug.h | 3 ++- mm/memory_hotplug.c | 22 ++++++++++++++-------- 4 files changed, 20 insertions(+), 16 deletions(-)
drivers/acpi/acpi_memhotplug.c +1 -1
@@ -318,7 +318,7 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)*/ list_for_each_entry_safe (info, n, &mem_device->res_list, list) {if (info->enabled) { - result =remove_memory (info->start_addr, info->length); + result =offline_memory (info->start_addr, info->length);if (result)return result; }
drivers/base/memory.c +3 -6
@@ -248,26 +248,23 @@ static bool pages_correctly_reserved(unsigned long start_pfn,static int memory_block_action (unsigned long phys_index,unsigned long action) { -unsigned long start_pfn, start_paddr; +unsigned long start_pfn;unsigned long nr_pages =PAGES_PER_SECTION * sections_per_block;struct page *first_page;int ret; first_page =pfn_to_page (phys_index <<PFN_SECTION_SHIFT ); + start_pfn =page_to_pfn (first_page);switch (action) {case MEM_ONLINE : - start_pfn =page_to_pfn (first_page); -if (!pages_correctly_reserved (start_pfn, nr_pages))return -EBUSY ; ret =online_pages (start_pfn, nr_pages);break ;case MEM_OFFLINE : - start_paddr =page_to_pfn (first_page) <<PAGE_SHIFT ; - ret =remove_memory (start_paddr, - nr_pages <<PAGE_SHIFT ); + ret =offline_pages (start_pfn, nr_pages);break ;default : WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
include/linux/memory_hotplug.h +2 -1
@@ -233,7 +233,8 @@ static inline int is_mem_section_removable(unsigned long pfn,extern int mem_online_node (int nid);extern int add_memory (int nid,u64 start,u64 size);extern int arch_add_memory (int nid,u64 start,u64 size); -extern int remove_memory (u64 start,u64 size); +extern int offline_pages (unsigned long start_pfn,unsigned long nr_pages); +extern int offline_memory (u64 start,u64 size);extern int sparse_add_one_section (struct zone *zone,unsigned long start_pfn,int nr_pages);extern void sparse_remove_one_section (struct zone *zone,struct mem_section *ms);
mm/memory_hotplug.c +14 -8
@@ -865,7 +865,7 @@ check_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)return offlined; } -static int __ref offline_pages (unsigned long start_pfn, +static int __ref __offline_pages (unsigned long start_pfn,unsigned long end_pfn,unsigned long timeout) {unsigned long pfn, nr_pages, expire;
@@ -990,18 +990,24 @@ out: return ret; } -int remove_memory (u64 start,u64 size) +int offline_pages (unsigned long start_pfn,unsigned long nr_pages) { -unsigned long start_pfn, end_pfn; +return __offline_pages (start_pfn, start_pfn + nr_pages,120 *HZ ); +} - start_pfn =PFN_DOWN (start); - end_pfn = start_pfn +PFN_DOWN (size); -return offline_pages (start_pfn, end_pfn,120 *HZ ); +int offline_memory (u64 start,u64 size) +{ +return -EINVAL ; }#else -int remove_memory (u64 start,u64 size) +int offline_pages (u64 start,u64 size) +{ +return -EINVAL ; +} + +int offline_memory (u64 start,u64 size) {return -EINVAL ; }#endif /* CONFIG_MEMORY_HOTREMOVE */ -EXPORT_SYMBOL_GPL (remove_memory); +EXPORT_SYMBOL_GPL (offline_memory);
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 2/19 memory-hotplug: implement offline_memory()
In reply to Wen CongyangThe function offline_memory() will be called when hot removing a memory device. The memory device may contain more than one memory block. If the memory block has been offlined, __offline_pages() will fail. So we should try to offline one memory block at a time.
If the memory block is offlined in offline_memory(), we also update it's state, and notify the userspace that its state is changed.
The function offline_memory() also check each memory block's state. So there is no need to check the memory block's state before calling offline_memory().
--- drivers/base/memory.c | 31 +++++++++++++++++++++++++++---- include/linux/memory_hotplug.h | 2 ++ mm/memory_hotplug.c | 37 ++++++++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 5 deletions(-)
drivers/base/memory.c +27 -4
@@ -275,13 +275,11 @@ memory_block_action(unsigned long phys_index, unsigned long action)return ret; } -static int memory_block_change_state (struct memory_block *mem, +static int __memory_block_change_state (struct memory_block *mem,unsigned long to_state,unsigned long from_state_req) {int ret =0 ; -mutex_lock (&mem->state_mutex); -if (mem->state != from_state_req) { ret = -EINVAL ; goto out;
@@ -309,10 +307,20 @@ static int memory_block_change_state(struct memory_block *mem,break ; } out: -mutex_unlock (&mem->state_mutex);return ret; } +static int memory_block_change_state (struct memory_block *mem, +unsigned long to_state,unsigned long from_state_req) +{ +int ret; + +mutex_lock (&mem->state_mutex); + ret =__memory_block_change_state (mem, to_state, from_state_req); +mutex_unlock (&mem->state_mutex); + +return ret; +}static ssize_t store_mem_state (struct device *dev,struct device_attribute *attr,const char *buf,size_t count)
@@ -653,6 +661,21 @@ int unregister_memory_section(struct mem_section *section) }/* +* offline one memory block. If the memory block has been offlined, do nothing. +*/ +int offline_memory_block (struct memory_block *mem) +{ +int ret =0 ; + +mutex_lock (&mem->state_mutex); +if (mem->state !=MEM_OFFLINE ) + ret =__memory_block_change_state (mem,MEM_OFFLINE ,MEM_ONLINE ); +mutex_unlock (&mem->state_mutex); + +return ret; +} + +/* * Initialize the sysfs support for memory devices... */ int __init memory_dev_init (void )
include/linux/memory_hotplug.h +2 -0
@@ -10,6 +10,7 @@ struct page;struct zone ;struct pglist_data ;struct mem_section ; +struct memory_block ;#ifdef CONFIG_MEMORY_HOTPLUG
@@ -234,6 +235,7 @@ extern int mem_online_node(int nid);extern int add_memory (int nid,u64 start,u64 size);extern int arch_add_memory (int nid,u64 start,u64 size);extern int offline_pages (unsigned long start_pfn,unsigned long nr_pages); +extern int offline_memory_block (struct memory_block *mem);extern int offline_memory (u64 start,u64 size);extern int sparse_add_one_section (struct zone *zone,unsigned long start_pfn,int nr_pages);
mm/memory_hotplug.c +36 -1
@@ -997,7 +997,42 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)int offline_memory (u64 start,u64 size) { -return -EINVAL ; +struct memory_block *mem =NULL ; +struct mem_section *section; +unsigned long start_pfn, end_pfn; +unsigned long pfn, section_nr; +int ret; + + start_pfn =PFN_DOWN (start); + end_pfn = start_pfn +PFN_DOWN (size); + +for (pfn = start_pfn; pfn < end_pfn; pfn +=PAGES_PER_SECTION ) { + section_nr =pfn_to_section_nr (pfn); +if (!present_section_nr (section_nr)) +continue ; + + section =__nr_to_section (section_nr); +/* same memblock? */ +if (mem) +if ((section_nr >= mem->start_section_nr) && + (section_nr <= mem->end_section_nr)) +continue ; + + mem =find_memory_block_hinted (section, mem); +if (!mem) +continue ; + + ret =offline_memory_block (mem); +if (ret) { +kobject_put (&mem->dev.kobj); +return ret; + } + } + +if (mem) +kobject_put (&mem->dev.kobj); + +return 0 ; }#else int offline_pages (u64 start,u64 size)
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 3/19 memory-hotplug: store the node id in acpi_memory_device
In reply to Wen CongyangThe memory device has only one node id. Store the node id when enable the memory device, and we can reuse it when removing the memory device.
--- drivers/acpi/acpi_memhotplug.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
drivers/acpi/acpi_memhotplug.c +4 -0
@@ -83,6 +83,7 @@ struct acpi_memory_info {struct acpi_memory_device {struct acpi_device * device;unsigned int state;/* State of the memory device */ +int nid;struct list_head res_list; };
@@ -256,6 +257,9 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) info->enabled =1 ; num_enabled++; } + + mem_device->nid = node; +if (!num_enabled) { printk(KERN_ERR PREFIX "add_memory failed\n"); mem_device->state =MEMORY_INVALID_STATE ;
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 4/19 memory-hotplug: offline and remove memory when removing the memory device
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
We should offline and remove memory when removing the memory device. The memory device can be removed by 2 ways:
1. send eject request by SCI
2. echo 1 >/sys/bus/pci/devices/PNP0C80:XX/eject
In the 1st case, acpi_memory_disable_device() will be called. In the 2nd case, acpi_memory_device_remove() will be called. acpi_memory_device_remove() will also be called when we unbind the memory device from the driver acpi_memhotplug. If the type is ACPI_BUS_REMOVAL_EJECT, it means that the user wants to eject the memory device, and we should offline and remove memory in acpi_memory_device_remove().
The function remove_memory() is not implemeted now. It only check whether all memory has been offllined now.
--- drivers/acpi/acpi_memhotplug.c | 42 +++++++++++++++++++++++++++++++++------ drivers/base/memory.c | 39 +++++++++++++++++++++++++++++++++++++ include/linux/memory.h | 5 ++++ include/linux/memory_hotplug.h | 5 ++++ mm/memory_hotplug.c | 22 ++++++++++++++++++++ 5 files changed, 106 insertions(+), 7 deletions(-)
drivers/acpi/acpi_memhotplug.c +35 -7
@@ -29,6 +29,7 @@#include <linux/module.h> #include <linux/init.h> #include <linux/types.h> +#include <linux/memory.h> #include <linux/memory_hotplug.h> #include <linux/slab.h> #include <acpi/acpi_drivers.h>
@@ -310,26 +311,42 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)return 0 ; } -static int acpi_memory_disable_device (struct acpi_memory_device *mem_device) +static int +acpi_memory_device_remove_memory (struct acpi_memory_device *mem_device) {int result;struct acpi_memory_info *info, *n; +int node = mem_device->nid; - -/* -* Ask the VM to offline this memory range. -* Note: Assume that this function returns zero on success -*/ list_for_each_entry_safe (info, n, &mem_device->res_list, list) {if (info->enabled) { result =offline_memory (info->start_addr, info->length);if (result)return result; + + result =remove_memory (node, info->start_addr, + info->length); +if (result) +return result; } +list_del (&info->list);kfree (info); } +return 0 ; +} + +static int acpi_memory_disable_device (struct acpi_memory_device *mem_device) +{ +int result; + +/* +* Ask the VM to offline this memory range. +* Note: Assume that this function returns zero on success +*/ + result =acpi_memory_device_remove_memory (mem_device); +/* Power-off and eject the device */ result =acpi_memory_powerdown_device (mem_device);if (result) {
@@ -478,12 +495,23 @@ static int acpi_memory_device_add(struct acpi_device *device)static int acpi_memory_device_remove (struct acpi_device *device,int type) {struct acpi_memory_device *mem_device =NULL ; - +int result;if (!device || !acpi_driver_data (device))return -EINVAL ; mem_device =acpi_driver_data (device); + +if (type ==ACPI_BUS_REMOVAL_EJECT ) { +/* +* offline and remove memory only when the memory device is +* ejected. +*/ + result =acpi_memory_device_remove_memory (mem_device); +if (result) +return result; + } +kfree (mem_device);return 0 ;
drivers/base/memory.c +39 -0
@@ -70,6 +70,45 @@ void unregister_memory_isolate_notifier(struct notifier_block *nb) }EXPORT_SYMBOL (unregister_memory_isolate_notifier); +bool is_memblk_offline (unsigned long start,unsigned long size) +{ +struct memory_block *mem =NULL ; +struct mem_section *section; +unsigned long start_pfn, end_pfn; +unsigned long pfn, section_nr; + + start_pfn =PFN_DOWN (start); + end_pfn =PFN_UP (start + size); + +for (pfn = start_pfn; pfn < end_pfn; pfn +=PAGES_PER_SECTION ) { + section_nr =pfn_to_section_nr (pfn); +if (!present_section_nr (section_nr)) +continue ; + + section =__nr_to_section (section_nr); +/* same memblock? */ +if (mem) +if ((section_nr >= mem->start_section_nr) && + (section_nr <= mem->end_section_nr)) +continue ; + + mem =find_memory_block_hinted (section, mem); +if (!mem) +continue ; +if (mem->state ==MEM_OFFLINE ) +continue ; + +kobject_put (&mem->dev.kobj); +return false; + } + +if (mem) +kobject_put (&mem->dev.kobj); + +return true; +} +EXPORT_SYMBOL (is_memblk_offline); +/* * register_memory - Setup a sysfs device for a memory block */
include/linux/memory.h +5 -0
@@ -106,6 +106,10 @@ static inline int memory_isolate_notify(unsigned long val, void *v) {return 0 ; } +static inline bool is_memblk_offline (unsigned long start,unsigned long size) +{ +return false; +}#else extern int register_memory_notifier (struct notifier_block *nb);extern void unregister_memory_notifier (struct notifier_block *nb);
@@ -120,6 +124,7 @@ extern int memory_isolate_notify(unsigned long val, void *v);extern struct memory_block *find_memory_block_hinted (struct mem_section *,struct memory_block *);extern struct memory_block *find_memory_block (struct mem_section *); +extern bool is_memblk_offline (unsigned long start,unsigned long size);#define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION<<PAGE_SHIFT)enum mem_add_context {BOOT ,HOTPLUG };#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
include/linux/memory_hotplug.h +5 -0
@@ -222,6 +222,7 @@ static inline void unlock_memory_hotplug(void) {}#ifdef CONFIG_MEMORY_HOTREMOVE extern int is_mem_section_removable (unsigned long pfn,unsigned long nr_pages); +extern int remove_memory (int nid,u64 start,u64 size);#else static inline int is_mem_section_removable(unsigned long pfn,
@@ -229,6 +230,10 @@ static inline int is_mem_section_removable(unsigned long pfn, {return 0 ; } +static inline int remove_memory (int nid,u64 start,u64 size) +{ +return -EBUSY ; +}#endif /* CONFIG_MEMORY_HOTREMOVE */ extern int mem_online_node (int nid);
mm/memory_hotplug.c +22 -0
@@ -1034,6 +1034,28 @@ int offline_memory(u64 start, u64 size) return 0; } + +int remove_memory (int nid,u64 start,u64 size) +{ +int ret = -EBUSY ; +lock_memory_hotplug (); +/* +* The memory might become online by other task, even if you offine it. +* So we check whether the cpu has been onlined or not. +*/ +if (!is_memblk_offline (start, size)) { +pr_warn ("memory removing [mem %#010llx-%#010llx] failed, " +"because the memmory range is online\n" , + start, start + size); + ret = -EAGAIN ; + } + +unlock_memory_hotplug (); +return ret; + +} +EXPORT_SYMBOL_GPL (remove_memory); +#else int offline_pages (u64 start,u64 size) {
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 5/19 memory-hotplug: check whether memory is present or not
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
If system supports memory hot-remove, online_pages() may online removed pages. So online_pages() need to check whether onlining pages are present or not.
--- include/linux/mmzone.h | 19 +++++++++++++++++++ mm/memory_hotplug.c | 13 +++++++++++++ 2 files changed, 32 insertions(+), 0 deletions(-)
include/linux/mmzone.h +19 -0
@@ -1168,6 +1168,25 @@ void sparse_init(void);#define sparse_index_init (_sec, _nid) do {} while (0)#endif /* CONFIG_SPARSEMEM */ +#ifdef CONFIG_SPARSEMEM +static inline int pfns_present (unsigned long pfn,unsigned long nr_pages) +{ +int i; +for (i =0 ; i < nr_pages; i++) { +if (pfn_present (pfn +1 )) +continue ; +else +return -EINVAL ; + } +return 0 ; +} +#else +static inline int pfns_present (unsigned long pfn,unsigned long nr_pages) +{ +return 0 ; +} +#endif /* CONFIG_SPARSEMEM*/ +#ifdef CONFIG_NODES_SPAN_OTHER_NODES bool early_pfn_in_nid (unsigned long pfn,int nid);#else
mm/memory_hotplug.c +13 -0
@@ -467,6 +467,19 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages)struct memory_notify arg;lock_memory_hotplug (); +/* +* If system supports memory hot-remove, the memory may have been +* removed. So we check whether the memory has been removed or not. +* +* Note: When CONFIG_SPARSEMEM is defined, pfns_present() become +* effective. If CONFIG_SPARSEMEM is not defined, pfns_present() +* always returns 0. +*/ + ret =pfns_present (pfn, nr_pages); +if (ret) { +unlock_memory_hotplug (); +return ret; + } arg.start_pfn = pfn; arg.nr_pages = nr_pages; arg.status_change_nid =-1 ;
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC PATCH v5 05/19] memory-hotplug: check whether memory is present or not
include/linux/mmzone.h void sparse_init(void); · line 1176
Quoted 5 lines · Wen Congyang
include/linux/mmzone.h +5
-0+static inline int pfns_present (unsigned long pfn,unsigned long nr_pages) +{ +int i; +for (i =0 ; i < nr_pages; i++) { +if (pfn_present (pfn +1 ))
Typo? I think you meant "pfn + i"
include/linux/mmzone.h void sparse_init(void); · line 1182
Quoted 6 lines
include/linux/mmzone.h +6
-0+continue ; + else + return -EINVAL; + } +return 0 ; +}
-Tony
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC PATCH v5 05/19] memory-hotplug: check whether memory is present or not
At 07/28/2012 04:17 AM, Tony Luck Wrote:
Quoted 8 lines · Wen Congyang
include/linux/mmzone.h void sparse_init(void); · line 1176
Quoted 5 lines
include/linux/mmzone.h +5
-0+static inline int pfns_present (unsigned long pfn,unsigned long nr_pages) +{ +int i; +for (i =0 ; i < nr_pages; i++) { +if (pfn_present (pfn +1 ))Typo? I think you meant "pfn + i"
Typo error.
Thanks for pointing it out.
Wen Congyang
Quoted 10 lines
include/linux/mmzone.h void sparse_init(void); · line 1182
Quoted 7 lines
include/linux/mmzone.h +6
-0+continue ; + else + return -EINVAL; + } +return 0 ; +}-Tony
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 6/19 memory-hotplug: export the function acpi_bus_remove()
In reply to Wen CongyangThe function acpi_bus_remove() can remove a acpi device from acpi device. When a acpi device is removed, we need to call this function to remove the acpi device from acpi bus. So export this function.
--- drivers/acpi/scan.c | 3 ++- include/acpi/acpi_bus.h | 1 + 2 files changed, 3 insertions(+), 1 deletions(-)
drivers/acpi/scan.c +2 -1
@@ -1224,7 +1224,7 @@ static int acpi_device_set_context(struct acpi_device *device)return -ENODEV ; } -static int acpi_bus_remove (struct acpi_device *dev,int rmdevice) +int acpi_bus_remove (struct acpi_device *dev,int rmdevice) {if (!dev)return -EINVAL ;
@@ -1246,6 +1246,7 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)return 0 ; } +EXPORT_SYMBOL (acpi_bus_remove); static int acpi_add_single_object(struct acpi_device **child, acpi_handle handle, int type,
include/acpi/acpi_bus.h +1 -0
@@ -360,6 +360,7 @@ bool acpi_bus_power_manageable(acpi_handle handle);bool acpi_bus_can_wakeup (acpi_handle handle);int acpi_power_resource_register_device (struct device *dev,acpi_handle handle);void acpi_power_resource_unregister_device (struct device *dev,acpi_handle handle); +int acpi_bus_remove (struct acpi_device *dev,int rmdevice);#ifdef CONFIG_ACPI_PROC_EVENT int acpi_bus_generate_proc_event (struct acpi_device *device,u8 type,int data);int acpi_bus_generate_proc_event4 (const char *class,const char *bid,u8 type,int data);
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 7/19 memory-hotplug: call acpi_bus_remove() to remove memory device
In reply to Wen CongyangThe memory device has been ejected and powoffed, so we can call acpi_bus_remove() to remove the memory device from acpi bus.
--- drivers/acpi/acpi_memhotplug.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
drivers/acpi/acpi_memhotplug.c +2 -1
@@ -423,8 +423,9 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) }/* -* TBD: Invoke acpi_bus_remove to cleanup data structures +* Invoke acpi_bus_remove() to remove memory device */ +acpi_bus_remove (device,1 );/* _EJ0 succeeded; _OST is not necessary */ return ;
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 8/19 memory-hotplug: remove /sys/firmware/memmap/X sysfs
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
When (hot)adding memory into system, /sys/firmware/memmap/X/{end, start, type} sysfs files are created. But there is no code to remove these files. The patch implements the function to remove them.
Note : The code does not free firmware_map_entry since there is no way to free
memory which is allocated by bootmem.
--- drivers/firmware/memmap.c | 78 +++++++++++++++++++++++++++++++++++++++++- include/linux/firmware-map.h | 6 +++ mm/memory_hotplug.c | 9 ++++- 3 files changed, 90 insertions(+), 3 deletions(-)
drivers/firmware/memmap.c +77 -1
@@ -21,6 +21,7 @@#include <linux/types.h> #include <linux/bootmem.h> #include <linux/slab.h> +#include <linux/mm.h> /* * Data types ------------------------------------------------------------------
@@ -79,7 +80,22 @@ static const struct sysfs_ops memmap_attr_ops = { .show = memmap_attr_show, }; +#define to_memmap_entry (obj) container_of(obj, struct firmware_map_entry, kobj) + +static void release_firmware_map_entry (struct kobject *kobj) +{ +struct firmware_map_entry *entry =to_memmap_entry (kobj); +struct page *page; + + page =virt_to_page (entry); +if (PageSlab (page) ||PageCompound (page)) +kfree (entry); + +/* There is no way to free memory allocated from bootmem*/ +} +static struct kobj_type memmap_ktype = { + .release = release_firmware_map_entry, .sysfs_ops = &memmap_attr_ops, .default_attrs = def_attrs, };
@@ -123,6 +139,16 @@ static int firmware_map_add_entry(u64 start, u64 end,return 0 ; } +/** +* firmware_map_remove_entry() - Does the real work to remove a firmware +* memmap entry. +* @entry: removed entry. +**/ +static inline void firmware_map_remove_entry (struct firmware_map_entry *entry) +{ +list_del (&entry->list); +} +/* * Add memmap entry on sysfs */
@@ -144,6 +170,31 @@ static int add_sysfs_fw_map_entry(struct firmware_map_entry *entry)return 0 ; } +/* +* Remove memmap entry on sysfs +*/ +static inline void remove_sysfs_fw_map_entry (struct firmware_map_entry *entry) +{ +kobject_put (&entry->kobj); +} + +/* +* Search memmap entry +*/ + +struct firmware_map_entry *__meminit +find_firmware_map_entry (u64 start,u64 end,const char *type) +{ +struct firmware_map_entry *entry; + +list_for_each_entry (entry, &map_entries, list) +if ((entry->start == start) && (entry->end == end) && + (!strcmp (entry->type, type))) +return entry; + +return NULL ; +} +/** * firmware_map_add_hotplug() - Adds a firmware mapping entry when we do * memory hotplug.
@@ -196,6 +247,32 @@ int __init firmware_map_add_early(u64 start, u64 end, const char *type)return firmware_map_add_entry (start, end, type, entry); } +/** +* firmware_map_remove() - remove a firmware mapping entry +* @start: Start of the memory range. +* @end: End of the memory range. +* @type: Type of the memory range. +* +* removes a firmware mapping entry. +* +* Returns 0 on success, or -EINVAL if no entry. +**/ +int __meminit firmware_map_remove (u64 start,u64 end,const char *type) +{ +struct firmware_map_entry *entry; + + entry =find_firmware_map_entry (start, end -1 , type); +if (!entry) +return -EINVAL ; + +firmware_map_remove_entry (entry); + +/* remove the memmap entry */ +remove_sysfs_fw_map_entry (entry); + +return 0 ; +} +/* * Sysfs functions ------------------------------------------------------------- */
@@ -218,7 +295,6 @@ static ssize_t type_show(struct firmware_map_entry *entry, char *buf) }#define to_memmap_attr (_attr) container_of(_attr, struct memmap_attribute, attr) -#define to_memmap_entry (obj) container_of(obj, struct firmware_map_entry, kobj)static ssize_t memmap_attr_show (struct kobject *kobj,struct attribute *attr,char *buf)
include/linux/firmware-map.h +6 -0
@@ -25,6 +25,7 @@int firmware_map_add_early (u64 start,u64 end,const char *type);int firmware_map_add_hotplug (u64 start,u64 end,const char *type); +int firmware_map_remove (u64 start,u64 end,const char *type);#else /* CONFIG_FIRMWARE_MEMMAP */
@@ -38,6 +39,11 @@ static inline int firmware_map_add_hotplug(u64 start, u64 end, const char *type)return 0 ; } +static inline int firmware_map_remove (u64 start,u64 end,const char *type) +{ +return 0 ; +} +#endif /* CONFIG_FIRMWARE_MEMMAP */ #endif /* _LINUX_FIRMWARE_MAP_H */
mm/memory_hotplug.c +7 -2
@@ -1048,9 +1048,9 @@ int offline_memory(u64 start, u64 size)return 0 ; } -int remove_memory (int nid,u64 start,u64 size) +int __ref remove_memory (int nid,u64 start,u64 size) { -int ret = -EBUSY ; +int ret =0 ;lock_memory_hotplug ();/* * The memory might become online by other task, even if you offine it.
@@ -1061,8 +1061,13 @@ int remove_memory(int nid, u64 start, u64 size)"because the memmory range is online\n" , start, start + size); ret = -EAGAIN ; + goto out; } +/* remove memmap entry */ +firmware_map_remove (start, start + size,"System RAM" ); + +out:unlock_memory_hotplug ();return ret;
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 9/19 memory-hotplug: does not release memory region in PAGES_PER_SECTION chunks
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
Since applying a patch(de7f0cba96786c), release_mem_region() has been changed as called in PAGES_PER_SECTION chunks because register_memory_resource() is called in PAGES_PER_SECTION chunks by add_memory(). But it seems firmware dependency. If CRS are written in the PAGES_PER_SECTION chunks in ACPI DSDT Table, register_memory_resource() is called in PAGES_PER_SECTION chunks. But if CRS are written in the DIMM unit in ACPI DSDT Table, register_memory_resource() is called in DIMM unit. So release_mem_region() should not be called in PAGES_PER_SECTION chunks. The patch fixes it.
--- arch/powerpc/platforms/pseries/hotplug-memory.c | 13 +++++++++---- mm/memory_hotplug.c | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-)
arch/powerpc/platforms/pseries/hotplug-memory.c +9 -4
@@ -77,7 +77,8 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz {unsigned long start, start_pfn;struct zone *zone; -int ret; +int i, ret; +int sections_to_remove; start_pfn = base >>PAGE_SHIFT ;
@@ -97,9 +98,13 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz* to sysfs "state" file and we can't remove sysfs entries * while writing to it. So we have to defer it to here. */ - ret =__remove_pages (zone, start_pfn, memblock_size >>PAGE_SHIFT ); -if (ret) -return ret; + sections_to_remove = (memblock_size >>PAGE_SHIFT ) /PAGES_PER_SECTION ; +for (i =0 ; i < sections_to_remove; i++) { +unsigned long pfn = start_pfn + i *PAGES_PER_SECTION ; + ret =__remove_pages (zone, start_pfn,PAGES_PER_SECTION ); +if (ret) +return ret; + }/* * Update memory regions for memory remove
mm/memory_hotplug.c +2 -2
@@ -358,11 +358,11 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,BUG_ON (phys_start_pfn & ~PAGE_SECTION_MASK );BUG_ON (nr_pages %PAGES_PER_SECTION ); +release_mem_region (phys_start_pfn <<PAGE_SHIFT , nr_pages *PAGE_SIZE ); + sections_to_remove = nr_pages /PAGES_PER_SECTION ;for (i =0 ; i < sections_to_remove; i++) {unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION ; -release_mem_region (pfn <<PAGE_SHIFT , -PAGES_PER_SECTION <<PAGE_SHIFT ); ret =__remove_section (zone,__pfn_to_section (pfn));if (ret)break ;
Signature · 1 line
1.7.1
RFC PATCH v5 10/19 memory-hotplug: add memory_block_release
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
When calling remove_memory_block(), the function shows following message at device_release().
Device 'memory528' does not have a release() function, it is broken and must be fixed.
remove_memory_block() calls kfree(mem). I think it shouled be called from device_release(). So the patch implements memory_block_release()
--- drivers/base/memory.c | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-)
drivers/base/memory.c +10 -1
@@ -109,6 +109,15 @@ bool is_memblk_offline(unsigned long start, unsigned long size) }EXPORT_SYMBOL (is_memblk_offline); +#define to_memory_block (device) container_of(device, struct memory_block, dev) + +static void release_memory_block (struct device *dev) +{ +struct memory_block *mem =to_memory_block (dev); + +kfree (mem); +} +/* * register_memory - Setup a sysfs device for a memory block */
@@ -119,6 +128,7 @@ int register_memory(struct memory_block *memory) memory->dev.bus = &memory_subsys; memory->dev.id = memory->start_section_nr / sections_per_block; + memory->dev.release = release_memory_block; error =device_register (&memory->dev);return error;
@@ -674,7 +684,6 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,mem_remove_simple_file (mem, phys_device);mem_remove_simple_file (mem, removable);unregister_memory (mem); -kfree (mem); }else kobject_put (&mem->dev.kobj);
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 11/19 memory-hotplug: remove_memory calls __remove_pages
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
The patch adds __remove_pages() to remove_memory(). Then the range of phys_start_pfn argument and nr_pages argument in __remove_pagse() may have different zone. So zone argument is removed from __remove_pages() and __remove_pages() caluculates zone in each section.
When CONFIG_SPARSEMEM_VMEMMAP is defined, there is no way to remove a memmap. So __remove_section only calls unregister_memory_section().
--- arch/powerpc/platforms/pseries/hotplug-memory.c | 5 +---- include/linux/memory_hotplug.h | 3 +-- mm/memory_hotplug.c | 18 +++++++++++------- 3 files changed, 13 insertions(+), 13 deletions(-)
arch/powerpc/platforms/pseries/hotplug-memory.c +1 -4
@@ -76,7 +76,6 @@ unsigned long memory_block_size_bytes(void)static int pseries_remove_memblock (unsigned long base,unsigned int memblock_size) {unsigned long start, start_pfn; -struct zone *zone;int i, ret;int sections_to_remove;
@@ -87,8 +86,6 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_sizreturn 0 ; } - zone =page_zone (pfn_to_page (start_pfn)); -/* * Remove section mappings and sysfs entries for the * section of the memory we are removing.
@@ -101,7 +98,7 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz sections_to_remove = (memblock_size >>PAGE_SHIFT ) /PAGES_PER_SECTION ;for (i =0 ; i < sections_to_remove; i++) {unsigned long pfn = start_pfn + i *PAGES_PER_SECTION ; - ret =__remove_pages (zone, start_pfn,PAGES_PER_SECTION ); + ret =__remove_pages (start_pfn,PAGES_PER_SECTION );if (ret)return ret; }
include/linux/memory_hotplug.h +1 -2
@@ -90,8 +90,7 @@ extern bool is_pageblock_removable_nolock(struct page *page);/* reasonably generic interface to expand the physical pages in a zone */ extern int __add_pages (int nid,struct zone *zone,unsigned long start_pfn,unsigned long nr_pages); -extern int __remove_pages (struct zone *zone,unsigned long start_pfn, -unsigned long nr_pages); +extern int __remove_pages (unsigned long start_pfn,unsigned long nr_pages);#ifdef CONFIG_NUMA extern int memory_add_physaddr_to_nid (u64 start);
mm/memory_hotplug.c +11 -7
@@ -275,11 +275,14 @@ static int __meminit __add_section(int nid, struct zone *zone,#ifdef CONFIG_SPARSEMEM_VMEMMAP static int __remove_section (struct zone *zone,struct mem_section *ms) { -/* -* XXX: Freeing memmap with vmemmap is not implement yet. -* This should be removed later. -*/ -return -EBUSY ; +int ret = -EINVAL ; + +if (!valid_section (ms)) +return ret; + + ret =unregister_memory_section (ms); + +return ret; }#else static int __remove_section (struct zone *zone,struct mem_section *ms)
@@ -346,11 +349,11 @@ EXPORT_SYMBOL_GPL(__add_pages);* sure that pages are marked reserved and zones are adjust properly by * calling offline_pages(). */ -int __remove_pages (struct zone *zone,unsigned long phys_start_pfn, -unsigned long nr_pages) +int __remove_pages (unsigned long phys_start_pfn,unsigned long nr_pages) {unsigned long i, ret =0 ;int sections_to_remove; +struct zone *zone;/* * We can only remove entire sections
@@ -363,6 +366,7 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn, sections_to_remove = nr_pages /PAGES_PER_SECTION ;for (i =0 ; i < sections_to_remove; i++) {unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION ; + zone =page_zone (pfn_to_page (pfn)); ret =__remove_section (zone,__pfn_to_section (pfn));if (ret)break ;
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 12/19 memory-hotplug: introduce new function arch_remove_memory()
In reply to Wen CongyangWe don't call __add_pages() directly in the function add_memory() because some other architecture related things need to be done before or after calling __add_pages(). So we should introduce a new function arch_remove_memory() to revert the things done in arch_add_memory().
Note: the function for s390 is not implemented(I don't know how to implement it for s390).
--- arch/ia64/mm/init.c | 16 ++++ arch/powerpc/mm/mem.c | 14 +++ arch/s390/mm/init.c | 8 ++ arch/sh/mm/init.c | 15 +++ arch/tile/mm/init.c | 8 ++ arch/x86/include/asm/pgtable_types.h | 1 + arch/x86/mm/init_32.c | 10 ++ arch/x86/mm/init_64.c | 160 ++++++++++++++++++++++++++++++++++ arch/x86/mm/pageattr.c | 47 +++++----- include/linux/memory_hotplug.h | 1 + mm/memory_hotplug.c | 1 + 11 files changed, 259 insertions(+), 22 deletions(-)
arch/ia64/mm/init.c +16 -0
@@ -688,6 +688,22 @@ int arch_add_memory(int nid, u64 start, u64 size) return ret; } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; +int ret; + + ret =__remove_pages (start_pfn, nr_pages); +if (ret) +pr_warn ("%s: Problem encountered in __remove_pages() as" +" ret=%d\n" , __func__, ret); + +return ret; +} +#endif #endif /*
arch/powerpc/mm/mem.c +14 -0
@@ -133,6 +133,20 @@ int arch_add_memory(int nid, u64 start, u64 size) return __add_pages(nid, zone, start_pfn, nr_pages); } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; + + start = (unsigned long )__va (start); +if (remove_section_mapping (start, start + size)) +return -EINVAL ; + +return __remove_pages (start_pfn, nr_pages); +} +#endif #endif /* CONFIG_MEMORY_HOTPLUG */ /*
arch/s390/mm/init.c +8 -0
@@ -257,4 +257,12 @@ int arch_add_memory(int nid, u64 start, u64 size)vmem_remove_mapping (start, size); return rc; } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +/* TODO */ +return -EBUSY ; +} +#endif #endif /* CONFIG_MEMORY_HOTPLUG */
arch/sh/mm/init.c +15 -0
@@ -558,4 +558,19 @@ int memory_add_physaddr_to_nid(u64 addr)EXPORT_SYMBOL_GPL (memory_add_physaddr_to_nid);#endif +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; +int ret; + + ret =__remove_pages (start_pfn, nr_pages); +if (unlikely (ret)) +pr_warn ("%s: Failed, __remove_pages() == %d\n" , __func__, + ret); + +return ret; +} +#endif #endif /* CONFIG_MEMORY_HOTPLUG */
arch/tile/mm/init.c +8 -0
@@ -935,6 +935,14 @@ int remove_memory(u64 start, u64 size) {return -EINVAL ; } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +/* TODO */ +return -EBUSY ; +} +#endif #endif struct kmem_cache *pgd_cache;
arch/x86/include/asm/pgtable_types.h +1 -0
@@ -334,6 +334,7 @@ static inline void update_page_count(int level, unsigned long pages) { }* as a pte too. */ extern pte_t *lookup_address (unsigned long address,unsigned int *level); +extern int __split_large_page (pte_t *kpte,unsigned long address,pte_t *pbase);#endif /* !__ASSEMBLY__ */
arch/x86/mm/init_32.c +10 -0
@@ -842,6 +842,16 @@ int arch_add_memory(int nid, u64 start, u64 size) return __add_pages(nid, zone, start_pfn, nr_pages); } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (unsigned long start,unsigned long size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; + +return __remove_pages (start_pfn, nr_pages); +} +#endif #endif /*
arch/x86/mm/init_64.c +160 -0
166 lines not on this page · raw message
arch/x86/mm/pageattr.c +25 -22
73 lines not on this page · raw message
include/linux/memory_hotplug.h +1 -0
@@ -85,6 +85,7 @@ extern void __online_page_free(struct page *page);#ifdef CONFIG_MEMORY_HOTREMOVE extern bool is_pageblock_removable_nolock (struct page *page); +extern int arch_remove_memory (unsigned long start,unsigned long size);#endif /* CONFIG_MEMORY_HOTREMOVE */ /* reasonably generic interface to expand the physical pages in a zone */
mm/memory_hotplug.c +1 -0
@@ -1071,6 +1071,7 @@ int __ref remove_memory(int nid, u64 start, u64 size)/* remove memmap entry */ firmware_map_remove (start, start + size,"System RAM" ); +arch_remove_memory (start, size); out:unlock_memory_hotplug ();return ret;
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC PATCH v5 12/19] memory-hotplug: introduce new function arch_remove_memory()
Quoted 8 lines · Wen Congyang
We don't call
__add_pages()directly in the functionadd_memory()because some other architecture related things need to be done before or after calling__add_pages(). So we should introduce a new functionarch_remove_memory()to revert the things done inarch_add_memory().Note: the function for s390 is not implemented(I don't know how to implement it for s390).
There is no hardware or firmware interface which could trigger a hot memory remove on s390. So there is nothing that needs to be implemented.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC PATCH v5 12/19] memory-hotplug: introduce new function arch_remove_memory()
At 07/30/2012 06:23 PM, Heiko Carstens Wrote:
Quoted 7 lines · Wen Congyang
Quoted 6 lines
We don't call
__add_pages()directly in the functionadd_memory()because some other architecture related things need to be done before or after calling__add_pages(). So we should introduce a new functionarch_remove_memory()to revert the things done inarch_add_memory().
Quoted 6 lines
Quoted 2 lines
Note: the function for s390 is not implemented(I don't know how to implement it for s390).
There is no hardware or firmware interface which could trigger a hot memory remove on s390. So there is nothing that needs to be implemented.
Thanks for providing this information.
According to this, arch_remove_memory() for s390 can just return -EBUSY.
Thanks
Wen Congyang
Quoted 6 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC PATCH v5 12/19] memory-hotplug: introduce new function arch_remove_memory()
Quoted 11 lines · On Mon, 30 Jul 2012 18:35:37 +0800 Wen Congyang <[email protected]> wrote:
At 07/30/2012 06:23 PM, Heiko Carstens Wrote:
Quoted 10 lines · Wen Congyang
Quoted 8 lines
We don't call
__add_pages()directly in the functionadd_memory()because some other architecture related things need to be done before or after calling__add_pages(). So we should introduce a new functionarch_remove_memory()to revert the things done inarch_add_memory().Note: the function for s390 is not implemented(I don't know how to implement it for s390).
Quoted 8 lines
Quoted 3 lines
There is no hardware or firmware interface which could trigger a hot memory remove on s390. So there is nothing that needs to be implemented.
Thanks for providing this information.
According to this,
arch_remove_memory()for s390 can just return-EBUSY.
Yes, but there is a prototype mismatch for arch_remove_memory() on s390 and also other architectures (u64 vs. unsigned long).
arch/s390/mm/init.c:262: error: conflicting types for ‘arch_remove_memory’ include/linux/memory_hotplug.h:88: error: previous declaration of ‘arch_remove_memory’ was here
In memory_hotplug.h you have:
extern int arch_remove_memory(unsigned long start, unsigned long size);
On all archs other than x86 you have:
int arch_remove_memory(u64 start, u64 size)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC PATCH v5 12/19] memory-hotplug: introduce new function arch_remove_memory()
At 07/31/2012 08:40 PM, Gerald Schaefer Wrote:
Quoted 6 lines
On Mon, 30 Jul 2012 18:35:37 +0800
Wen Congyang <[email protected]> wrote:
=20Quoted 3 lines
At 07/30/2012 06:23 PM, Heiko Carstens Wrote:
Quoted 2 lines · Wen Congyang
Quoted 1 line
We don't call =5F=5Fadd=5Fpages() directly in the function add=5Fmemor=
y()
Quoted 12 lines
Quoted 12 lines
Quoted 11 lines
Quoted 7 lines
because some other architecture related things need to be done before or after calling =5F=5Fadd=5Fpages(). So we should introduce a new function arch=5Fremove=5Fmemory() to revert the things done in arch=5Fadd=5Fmemory().
Note: the function for s390 is not implemented(I don't know how to implement it for s390).
There is no hardware or firmware interface which could trigger a hot memory remove on s390. So there is nothing that needs to be implemented.
Quoted 6 lines
Quoted 4 lines
Thanks for providing this information.
According to this, arch=5Fremove=5Fmemory() for s390 can just return
-EBUSY.=20
Yes, but there is a prototype mismatch for arch=5Fremove=5Fmemory() on s3=
90
Quoted 4 lines
and also other architectures (u64 vs. unsigned long).
=20arch/s390/mm/init.c:262: error: conflicting types for =E2=80=98arch=5Fremove=5Fmemory=E2=80=99 include/linux/memory=5Fhotplug.h=
:88: error: previous
Quoted 4 lines
declaration of =E2=80=98arch=5Fremove=5Fmemory=E2=80=99 was here =20
In memory=5Fhotplug.h you have:
extern int arch=5Fremove=5Fmemory(unsigned long start, unsigned long size=
);
Quoted 3 lines
=20
On all archs other than x86 you have:
int arch=5Fremove=5Fmemory(u64 start, u64 size)
Thanks for pointing it out. I will fix it.
Wen Congyang
Quoted 7 lines
=20
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
=20
=
Re: [RFC PATCH v5 12/19] memory-hotplug: introduce new function arch_remove_memory()
In reply to Wen Congyang2012/7/27 Wen Congyang <[email protected]>:
Quoted 50 lines
We don't call
__add_pages()directly in the functionadd_memory()because some other architecture related things need to be done before or after calling__add_pages(). So we should introduce a new functionarch_remove_memory()to revert the things done inarch_add_memory().Note: the function for s390 is not implemented(I don't know how to implement it for s390).
CC David Rientjes <[email protected]>CC Jiang Liu <[email protected]>CC Len Brown <[email protected]>CC Benjamin Herrenschmidt <[email protected]>CC Paul Mackerras <[email protected]>CC Christoph Lameter <[email protected]>Cc Minchan Kim <[email protected]>CC Andrew Morton <[email protected]>CC KOSAKI Motohiro <[email protected]>CC Yasuaki Ishimatsu <[email protected]>Signed-off-by Wen Congyang <[email protected]>--- arch/ia64/mm/init.c | 16 ++++ arch/powerpc/mm/mem.c | 14 +++ arch/s390/mm/init.c | 8 ++ arch/sh/mm/init.c | 15 +++ arch/tile/mm/init.c | 8 ++ arch/x86/include/asm/pgtable_types.h | 1 + arch/x86/mm/init_32.c | 10 ++ arch/x86/mm/init_64.c | 160 ++++++++++++++++++++++++++++++++++ arch/x86/mm/pageattr.c | 47 +++++----- include/linux/memory_hotplug.h | 1 + mm/memory_hotplug.c | 1 + 11 files changed, 259 insertions(+), 22 deletions(-)arch/ia64/mm/init.c +8
-0@@ -688,6 +688,22 @@ int arch_add_memory(int nid, u64 start, u64 size)return ret; } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; +int ret; +
arch/ia64/mm/init.c int arch_add_memory(int nid, u64 start, u64 size) · line 708
Quoted 10 lines
arch/ia64/mm/init.c +8
-0+ ret =__remove_pages (start_pfn, nr_pages); +if (ret) +pr_warn ("%s: Problem encountered in __remove_pages() as" +" ret=%d\n" , __func__, ret); + +return ret; +} +#endif #endif
in 3.5 ia64 implementation did not call __remove_pages at all. so why?
mm/memory_hotplug.c int __ref remove_memory(int nid, u64 start, u64 size)
Quoted 387 lines
arch/ia64/mm/init.c +0
-0/* arch/powerpc/mm/mem.c +14
-0@@ -133,6 +133,20 @@ int arch_add_memory(int nid, u64 start, u64 size) return __add_pages(nid, zone, start_pfn, nr_pages); } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; + + start = (unsigned long )__va (start); +if (remove_section_mapping (start, start + size)) +return -EINVAL ; + +return __remove_pages (start_pfn, nr_pages); +} +#endif #endif /* CONFIG_MEMORY_HOTPLUG */ /* arch/s390/mm/init.c +8
-0@@ -257,4 +257,12 @@ int arch_add_memory(int nid, u64 start, u64 size)vmem_remove_mapping (start, size); return rc; } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +/* TODO */ +return -EBUSY ; +} +#endif #endif /* CONFIG_MEMORY_HOTPLUG */ arch/sh/mm/init.c +15
-0@@ -558,4 +558,19 @@ int memory_add_physaddr_to_nid(u64 addr)EXPORT_SYMBOL_GPL (memory_add_physaddr_to_nid);#endif +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; +int ret; + + ret =__remove_pages (start_pfn, nr_pages); +if (unlikely (ret)) +pr_warn ("%s: Failed, __remove_pages() = %d\n" , __func__, + ret); + +return ret; +} +#endif #endif /* CONFIG_MEMORY_HOTPLUG */ arch/tile/mm/init.c +8
-0@@ -935,6 +935,14 @@ int remove_memory(u64 start, u64 size) {return -EINVAL ; } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +/* TODO */ +return -EBUSY ; +} +#endif #endif struct kmem_cache *pgd_cache;arch/x86/include/asm/pgtable_types.h +1
-0@@ -334,6 +334,7 @@ static inline void update_page_count(int level, unsigned long pages) { }* as a pte too. */ extern pte_t *lookup_address (unsigned long address,unsigned int *level); +extern int __split_large_page (pte_t *kpte,unsigned long address,pte_t *pbase);#endif /* !__ASSEMBLY__ */ arch/x86/mm/init_32.c +10
-0@@ -842,6 +842,16 @@ int arch_add_memory(int nid, u64 start, u64 size) return __add_pages(nid, zone, start_pfn, nr_pages); } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (unsigned long start,unsigned long size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; + +return __remove_pages (start_pfn, nr_pages); +} +#endif #endif /* arch/x86/mm/init_64.c +160
-0@@ -675,6 +675,166 @@ int arch_add_memory(int nid, u64 start, u64 size) }EXPORT_SYMBOL_GPL (arch_add_memory); +static void __meminit +phys_pte_remove (pte_t *pte_page,unsigned long addr,unsigned long end) +{ +unsigned pages =0 ; +int i =pte_index (addr); + +pte_t *pte = pte_page +pte_index (addr); + +for (; i <PTRS_PER_PTE ; i++, addr +=PAGE_SIZE , pte++) { + +if (addr >= end) +break ; + +if (!pte_present (*pte)) +continue ; + + pages++; +set_pte (pte,__pte (0 )); + } + +update_page_count (PG_LEVEL_4K , -pages); +} + +static void __meminit +phys_pmd_remove (pmd_t *pmd_page,unsigned long addr,unsigned long end) +{ +unsigned long pages =0 , next; +int i =pmd_index (addr); + +for (; i <PTRS_PER_PMD ; i++, addr = next) { +unsigned long pte_phys; +pmd_t *pmd = pmd_page +pmd_index (addr); +pte_t *pte; + +if (addr >= end) +break ; + + next = (addr &PMD_MASK ) +PMD_SIZE ; + +if (!pmd_present (*pmd)) +continue ; + +if (pmd_large (*pmd)) { +if ((addr & ~PMD_MASK ) =0 && next <= end) { +set_pmd (pmd,__pmd (0 )); + pages++; +continue ; + } + +/* +* We use 2M page, but we need to remove part of them, +* so split 2M page to 4K page. +*/ + pte =alloc_low_page (&pte_phys); +__split_large_page ((pte_t *)pmd, addr, pte); + +spin_lock (&init_mm.page_table_lock); +pmd_populate_kernel (&init_mm, pmd,__va (pte_phys)); +spin_unlock (&init_mm.page_table_lock); + } + +spin_lock (&init_mm.page_table_lock); + pte =map_low_page ((pte_t *)pmd_page_vaddr (*pmd)); +phys_pte_remove (pte, addr, end); +unmap_low_page (pte); +spin_unlock (&init_mm.page_table_lock); + } +update_page_count (PG_LEVEL_2M , -pages); +} + +static void __meminit +phys_pud_remove (pud_t *pud_page,unsigned long addr,unsigned long end) +{ +unsigned long pages =0 , next; +int i =pud_index (addr); + +for (; i <PTRS_PER_PUD ; i++, addr = next) { +unsigned long pmd_phys; +pud_t *pud = pud_page +pud_index (addr); +pmd_t *pmd; + +if (addr >= end) +break ; + + next = (addr &PUD_MASK ) +PUD_SIZE ; + +if (!pud_present (*pud)) +continue ; + +if (pud_large (*pud)) { +if ((addr & ~PUD_MASK ) =0 && next <= end) { +set_pud (pud,__pud (0 )); + pages++; +continue ; + } + +/* +* We use 1G page, but we need to remove part of them, +* so split 1G page to 2M page. +*/ + pmd =alloc_low_page (&pmd_phys); +__split_large_page ((pte_t *)pud, addr, (pte_t *)pmd); + +spin_lock (&init_mm.page_table_lock); +pud_populate (&init_mm, pud,__va (pmd_phys)); +spin_unlock (&init_mm.page_table_lock); + } + + pmd =map_low_page (pmd_offset (pud,0 )); +phys_pmd_remove (pmd, addr, end); +unmap_low_page (pmd); +__flush_tlb_all (); + } +__flush_tlb_all (); + +update_page_count (PG_LEVEL_1G , -pages); +} + +void __meminit +kernel_physical_mapping_remove (unsigned long start,unsigned long end) +{ +unsigned long next; + + start = (unsigned long )__va (start); + end = (unsigned long )__va (end); + +for (; start < end; start = next) { +pgd_t *pgd =pgd_offset_k (start); +pud_t *pud; + + next = (start +PGDIR_SIZE ) &PGDIR_MASK ; +if (next > end) + next = end; + +if (!pgd_present (*pgd)) +continue ; + + pud =map_low_page ((pud_t *)pgd_page_vaddr (*pgd)); +phys_pud_remove (pud,__pa (start),__pa (end)); +unmap_low_page (pud); + } + +__flush_tlb_all (); +} + +#ifdef CONFIG_MEMORY_HOTREMOVE +int __ref arch_remove_memory (unsigned long start,unsigned long size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; +int ret; + + ret =__remove_pages (start_pfn, nr_pages); +WARN_ON_ONCE (ret); + +kernel_physical_mapping_remove (start, start + size); + +return ret; +} +#endif #endif /* CONFIG_MEMORY_HOTPLUG */ static struct kcore_list kcore_vsyscall;arch/x86/mm/pageattr.c +25
-22@@ -501,21 +501,13 @@ out_unlock:return do_split; } -static int split_large_page (pte_t *kpte,unsigned long address) +int __split_large_page (pte_t *kpte,unsigned long address,pte_t *pbase) {unsigned long pfn, pfninc =1 ;unsigned int i, level; -pte_t *pbase, *tmp; +pte_t *tmp;pgprot_t ref_prot; -struct page *base; - -if (!debug_pagealloc) -spin_unlock (&cpa_lock); - base =alloc_pages (GFP_KERNEL | __GFP_NOTRACK,0 ); -if (!debug_pagealloc) -spin_lock (&cpa_lock); -if (!base) -return -ENOMEM ; +struct page *base =virt_to_page (pbase);spin_lock (&pgd_lock);/* @@ -523,10 +515,11 @@ static int split_large_page(pte_t *kpte, unsigned long address)* up for us already: */ tmp =lookup_address (address, &level); -if (tmp != kpte) - goto out_unlock; +if (tmp != kpte) { +spin_unlock (&pgd_lock); +return 1 ; + } - pbase = (pte_t *)page_address (base);paravirt_alloc_pte (&init_mm,page_to_pfn (base)); ref_prot =pte_pgprot (pte_clrhuge (*kpte));/* @@ -579,17 +572,27 @@ static int split_large_page(pte_t *kpte, unsigned long address)* going on. */ __flush_tlb_all (); +spin_unlock (&pgd_lock); - base =NULL ; +return 0 ; +} -out_unlock: -/* -* If we dropped out via the lookup_address check under -* pgd_lock then stick the page back into the pool: -*/ -if (base) +static int split_large_page (pte_t *kpte,unsigned long address) +{ +pte_t *pbase; +struct page *base; + +if (!debug_pagealloc) +spin_unlock (&cpa_lock); + base =alloc_pages (GFP_KERNEL | __GFP_NOTRACK,0 ); +if (!debug_pagealloc) +spin_lock (&cpa_lock); +if (!base) +return -ENOMEM ; + + pbase = (pte_t *)page_address (base); +if (__split_large_page (kpte, address, pbase))__free_page (base); -spin_unlock (&pgd_lock);return 0 ; }include/linux/memory_hotplug.h +1
-0@@ -85,6 +85,7 @@ extern void __online_page_free(struct page *page);#ifdef CONFIG_MEMORY_HOTREMOVE extern bool is_pageblock_removable_nolock (struct page *page); +extern int arch_remove_memory (unsigned long start,unsigned long size);#endif /* CONFIG_MEMORY_HOTREMOVE */ /* reasonably generic interface to expand the physical pages in a zone */ mm/memory_hotplug.c +0
-0@@ -1071,6 +1071,7 @@ int __ref remove_memory(int nid, u64 start, u64 size)
line 1071? which version does this patch base on? thanks a lot.
Quoted 15 lines
mm/memory_hotplug.c +1
-1/* remove memmap entry */ firmware_map_remove (start, start + size,"System RAM" ); +arch_remove_memory (start, size); out:unlock_memory_hotplug ();return ret; --1.7.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC PATCH v5 12/19] memory-hotplug: introduce new function arch_remove_memory()
At 08/01/2012 10:44 AM, jencce zhou Wrote:
Quoted 55 lines
2012/7/27 Wen Congyang <[email protected]>:
Quoted 54 lines
We don't call
__add_pages()directly in the functionadd_memory()because some other architecture related things need to be done before or after calling__add_pages(). So we should introduce a new functionarch_remove_memory()to revert the things done inarch_add_memory().Note: the function for s390 is not implemented(I don't know how to implement it for s390).
CC David Rientjes <[email protected]>CC Jiang Liu <[email protected]>CC Len Brown <[email protected]>CC Benjamin Herrenschmidt <[email protected]>CC Paul Mackerras <[email protected]>CC Christoph Lameter <[email protected]>Cc Minchan Kim <[email protected]>CC Andrew Morton <[email protected]>CC KOSAKI Motohiro <[email protected]>CC Yasuaki Ishimatsu <[email protected]>Signed-off-by Wen Congyang <[email protected]>--- arch/ia64/mm/init.c | 16 ++++ arch/powerpc/mm/mem.c | 14 +++ arch/s390/mm/init.c | 8 ++ arch/sh/mm/init.c | 15 +++ arch/tile/mm/init.c | 8 ++ arch/x86/include/asm/pgtable_types.h | 1 + arch/x86/mm/init_32.c | 10 ++ arch/x86/mm/init_64.c | 160 ++++++++++++++++++++++++++++++++++ arch/x86/mm/pageattr.c | 47 +++++----- include/linux/memory_hotplug.h | 1 + mm/memory_hotplug.c | 1 + 11 files changed, 259 insertions(+), 22 deletions(-)arch/ia64/mm/init.c +12
-0@@ -688,6 +688,22 @@ int arch_add_memory(int nid, u64 start, u64 size)return ret; } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; +int ret; + + ret =__remove_pages (start_pfn, nr_pages); +if (ret) +pr_warn ("%s: Problem encountered in __remove_pages() as" +" ret=%d\n" , __func__, ret);
Quoted 8 lines
arch/ia64/mm/init.c int arch_add_memory(int nid, u64 start, u64 size) · line 708
Quoted 6 lines
arch/ia64/mm/init.c +4
-0+ +return ret; +} +#endif #endif in 3.5 ia64 implementation did not call
__remove_pagesat all. so why?
This function only reverts the things done in arch_add_memory(), and it will be called when a memory device is removed.
When adding a memory device, __add_pages() is called in arch_add_memory(), so call __remove_pages() in arch_remove_memory().
Thanks
Wen Congyang
Quoted 383 lines
Quoted 383 lines
arch/ia64/mm/init.c +0
-0/* arch/powerpc/mm/mem.c +14
-0@@ -133,6 +133,20 @@ int arch_add_memory(int nid, u64 start, u64 size) return __add_pages(nid, zone, start_pfn, nr_pages); } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; + + start = (unsigned long )__va (start); +if (remove_section_mapping (start, start + size)) +return -EINVAL ; + +return __remove_pages (start_pfn, nr_pages); +} +#endif #endif /* CONFIG_MEMORY_HOTPLUG */ /* arch/s390/mm/init.c +8
-0@@ -257,4 +257,12 @@ int arch_add_memory(int nid, u64 start, u64 size)vmem_remove_mapping (start, size); return rc; } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +/* TODO */ +return -EBUSY ; +} +#endif #endif /* CONFIG_MEMORY_HOTPLUG */ arch/sh/mm/init.c +15
-0@@ -558,4 +558,19 @@ int memory_add_physaddr_to_nid(u64 addr)EXPORT_SYMBOL_GPL (memory_add_physaddr_to_nid);#endif +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; +int ret; + + ret =__remove_pages (start_pfn, nr_pages); +if (unlikely (ret)) +pr_warn ("%s: Failed, __remove_pages() == %d\n" , __func__, + ret); + +return ret; +} +#endif #endif /* CONFIG_MEMORY_HOTPLUG */ arch/tile/mm/init.c +8
-0@@ -935,6 +935,14 @@ int remove_memory(u64 start, u64 size) {return -EINVAL ; } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (u64 start,u64 size) +{ +/* TODO */ +return -EBUSY ; +} +#endif #endif struct kmem_cache *pgd_cache;arch/x86/include/asm/pgtable_types.h +1
-0@@ -334,6 +334,7 @@ static inline void update_page_count(int level, unsigned long pages) { }* as a pte too. */ extern pte_t *lookup_address (unsigned long address,unsigned int *level); +extern int __split_large_page (pte_t *kpte,unsigned long address,pte_t *pbase);#endif /* !__ASSEMBLY__ */ arch/x86/mm/init_32.c +10
-0@@ -842,6 +842,16 @@ int arch_add_memory(int nid, u64 start, u64 size) return __add_pages(nid, zone, start_pfn, nr_pages); } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory (unsigned long start,unsigned long size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; + +return __remove_pages (start_pfn, nr_pages); +} +#endif #endif /* arch/x86/mm/init_64.c +160
-0@@ -675,6 +675,166 @@ int arch_add_memory(int nid, u64 start, u64 size) }EXPORT_SYMBOL_GPL (arch_add_memory); +static void __meminit +phys_pte_remove (pte_t *pte_page,unsigned long addr,unsigned long end) +{ +unsigned pages =0 ; +int i =pte_index (addr); + +pte_t *pte = pte_page +pte_index (addr); + +for (; i <PTRS_PER_PTE ; i++, addr +=PAGE_SIZE , pte++) { + +if (addr >= end) +break ; + +if (!pte_present (*pte)) +continue ; + + pages++; +set_pte (pte,__pte (0 )); + } + +update_page_count (PG_LEVEL_4K , -pages); +} + +static void __meminit +phys_pmd_remove (pmd_t *pmd_page,unsigned long addr,unsigned long end) +{ +unsigned long pages =0 , next; +int i =pmd_index (addr); + +for (; i <PTRS_PER_PMD ; i++, addr = next) { +unsigned long pte_phys; +pmd_t *pmd = pmd_page +pmd_index (addr); +pte_t *pte; + +if (addr >= end) +break ; + + next = (addr &PMD_MASK ) +PMD_SIZE ; + +if (!pmd_present (*pmd)) +continue ; + +if (pmd_large (*pmd)) { +if ((addr & ~PMD_MASK ) ==0 && next <= end) { +set_pmd (pmd,__pmd (0 )); + pages++; +continue ; + } + +/* +* We use 2M page, but we need to remove part of them, +* so split 2M page to 4K page. +*/ + pte =alloc_low_page (&pte_phys); +__split_large_page ((pte_t *)pmd, addr, pte); + +spin_lock (&init_mm.page_table_lock); +pmd_populate_kernel (&init_mm, pmd,__va (pte_phys)); +spin_unlock (&init_mm.page_table_lock); + } + +spin_lock (&init_mm.page_table_lock); + pte =map_low_page ((pte_t *)pmd_page_vaddr (*pmd)); +phys_pte_remove (pte, addr, end); +unmap_low_page (pte); +spin_unlock (&init_mm.page_table_lock); + } +update_page_count (PG_LEVEL_2M , -pages); +} + +static void __meminit +phys_pud_remove (pud_t *pud_page,unsigned long addr,unsigned long end) +{ +unsigned long pages =0 , next; +int i =pud_index (addr); + +for (; i <PTRS_PER_PUD ; i++, addr = next) { +unsigned long pmd_phys; +pud_t *pud = pud_page +pud_index (addr); +pmd_t *pmd; + +if (addr >= end) +break ; + + next = (addr &PUD_MASK ) +PUD_SIZE ; + +if (!pud_present (*pud)) +continue ; + +if (pud_large (*pud)) { +if ((addr & ~PUD_MASK ) ==0 && next <= end) { +set_pud (pud,__pud (0 )); + pages++; +continue ; + } + +/* +* We use 1G page, but we need to remove part of them, +* so split 1G page to 2M page. +*/ + pmd =alloc_low_page (&pmd_phys); +__split_large_page ((pte_t *)pud, addr, (pte_t *)pmd); + +spin_lock (&init_mm.page_table_lock); +pud_populate (&init_mm, pud,__va (pmd_phys)); +spin_unlock (&init_mm.page_table_lock); + } + + pmd =map_low_page (pmd_offset (pud,0 )); +phys_pmd_remove (pmd, addr, end); +unmap_low_page (pmd); +__flush_tlb_all (); + } +__flush_tlb_all (); + +update_page_count (PG_LEVEL_1G , -pages); +} + +void __meminit +kernel_physical_mapping_remove (unsigned long start,unsigned long end) +{ +unsigned long next; + + start = (unsigned long )__va (start); + end = (unsigned long )__va (end); + +for (; start < end; start = next) { +pgd_t *pgd =pgd_offset_k (start); +pud_t *pud; + + next = (start +PGDIR_SIZE ) &PGDIR_MASK ; +if (next > end) + next = end; + +if (!pgd_present (*pgd)) +continue ; + + pud =map_low_page ((pud_t *)pgd_page_vaddr (*pgd)); +phys_pud_remove (pud,__pa (start),__pa (end)); +unmap_low_page (pud); + } + +__flush_tlb_all (); +} + +#ifdef CONFIG_MEMORY_HOTREMOVE +int __ref arch_remove_memory (unsigned long start,unsigned long size) +{ +unsigned long start_pfn = start >>PAGE_SHIFT ; +unsigned long nr_pages = size >>PAGE_SHIFT ; +int ret; + + ret =__remove_pages (start_pfn, nr_pages); +WARN_ON_ONCE (ret); + +kernel_physical_mapping_remove (start, start + size); + +return ret; +} +#endif #endif /* CONFIG_MEMORY_HOTPLUG */ static struct kcore_list kcore_vsyscall;arch/x86/mm/pageattr.c +25
-22@@ -501,21 +501,13 @@ out_unlock:return do_split; } -static int split_large_page (pte_t *kpte,unsigned long address) +int __split_large_page (pte_t *kpte,unsigned long address,pte_t *pbase) {unsigned long pfn, pfninc =1 ;unsigned int i, level; -pte_t *pbase, *tmp; +pte_t *tmp;pgprot_t ref_prot; -struct page *base; - -if (!debug_pagealloc) -spin_unlock (&cpa_lock); - base =alloc_pages (GFP_KERNEL | __GFP_NOTRACK,0 ); -if (!debug_pagealloc) -spin_lock (&cpa_lock); -if (!base) -return -ENOMEM ; +struct page *base =virt_to_page (pbase);spin_lock (&pgd_lock);/* @@ -523,10 +515,11 @@ static int split_large_page(pte_t *kpte, unsigned long address)* up for us already: */ tmp =lookup_address (address, &level); -if (tmp != kpte) - goto out_unlock; +if (tmp != kpte) { +spin_unlock (&pgd_lock); +return 1 ; + } - pbase = (pte_t *)page_address (base);paravirt_alloc_pte (&init_mm,page_to_pfn (base)); ref_prot =pte_pgprot (pte_clrhuge (*kpte));/* @@ -579,17 +572,27 @@ static int split_large_page(pte_t *kpte, unsigned long address)* going on. */ __flush_tlb_all (); +spin_unlock (&pgd_lock); - base =NULL ; +return 0 ; +} -out_unlock: -/* -* If we dropped out via the lookup_address check under -* pgd_lock then stick the page back into the pool: -*/ -if (base) +static int split_large_page (pte_t *kpte,unsigned long address) +{ +pte_t *pbase; +struct page *base; + +if (!debug_pagealloc) +spin_unlock (&cpa_lock); + base =alloc_pages (GFP_KERNEL | __GFP_NOTRACK,0 ); +if (!debug_pagealloc) +spin_lock (&cpa_lock); +if (!base) +return -ENOMEM ; + + pbase = (pte_t *)page_address (base); +if (__split_large_page (kpte, address, pbase))__free_page (base); -spin_unlock (&pgd_lock);return 0 ; }include/linux/memory_hotplug.h +1
-0@@ -85,6 +85,7 @@ extern void __online_page_free(struct page *page);#ifdef CONFIG_MEMORY_HOTREMOVE extern bool is_pageblock_removable_nolock (struct page *page); +extern int arch_remove_memory (unsigned long start,unsigned long size);#endif /* CONFIG_MEMORY_HOTREMOVE */
Quoted 26 lines
mm/memory_hotplug.c int __ref remove_memory(int nid, u64 start, u64 size)
Quoted 6 lines
include/linux/memory_hotplug.h +0
-0/* reasonably generic interface to expand the physical pages in a zone */ mm/memory_hotplug.c +0
-0@@ -1071,6 +1071,7 @@ int __ref remove_memory(int nid, u64 start, u64 size)line 1071? which version does this patch base on? thanks a lot.
Quoted 15 lines
mm/memory_hotplug.c +1
-1/* remove memmap entry */ firmware_map_remove (start, start + size,"System RAM" ); +arch_remove_memory (start, size); out:unlock_memory_hotplug ();return ret; --1.7.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 13/19 memory-hotplug: check page type in get_page_bootmem
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
There is a possibility that get_page_bootmem() is called to the same page many times. So when get_page_bootmem is called to the same page, the function only increments page->_count.
--- mm/memory_hotplug.c | 15 +++++++++++---- 1 files changed, 11 insertions(+), 4 deletions(-)
mm/memory_hotplug.c +11 -4
@@ -95,10 +95,17 @@ static void release_memory_resource(struct resource *res)static void get_page_bootmem (unsigned long info,struct page *page,unsigned long type) { - page->lru.next = (struct list_head *) type; -SetPagePrivate (page); -set_page_private (page, info); -atomic_inc (&page->_count); +unsigned long page_type; + + page_type = (unsigned long ) page->lru.next; +if (type <MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE || + type >MEMORY_HOTPLUG_MAX_BOOTMEM_TYPE ){ + page->lru.next = (struct list_head *) type; +SetPagePrivate (page); +set_page_private (page, info); +atomic_inc (&page->_count); + }else +atomic_inc (&page->_count); }/* reference to __meminit __free_pages_bootmem is valid
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 14/19 memory-hotplug: move register_page_bootmem_info_node and put_page_bootmem for sparse-vmemmap
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
For implementing register_page_bootmem_info_node of sparse-vmemmap, register_page_bootmem_info_node and put_page_bootmem are moved to memory_hotplug.c
--- include/linux/memory_hotplug.h | 9 --------- mm/memory_hotplug.c | 8 ++++++-- 2 files changed, 6 insertions(+), 11 deletions(-)
include/linux/memory_hotplug.h +0 -9
@@ -162,17 +162,8 @@ static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat)#endif /* CONFIG_NUMA */ #endif /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */ -#ifdef CONFIG_SPARSEMEM_VMEMMAP -static inline void register_page_bootmem_info_node (struct pglist_data *pgdat) -{ -} -static inline void put_page_bootmem (struct page *page) -{ -} -#else extern void register_page_bootmem_info_node (struct pglist_data *pgdat);extern void put_page_bootmem (struct page *page); -#endif /* * Lock for memory hotplug guarantees 1) all callbacks for memory hotplug
mm/memory_hotplug.c +6 -2
@@ -91,7 +91,6 @@ static void release_memory_resource(struct resource *res) }#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE -#ifndef CONFIG_SPARSEMEM_VMEMMAPstatic void get_page_bootmem (unsigned long info,struct page *page,unsigned long type) {
@@ -127,6 +126,7 @@ void __ref put_page_bootmem(struct page *page) } +#ifndef CONFIG_SPARSEMEM_VMEMMAP static void register_page_bootmem_info_section (unsigned long start_pfn) {unsigned long *usemap, mapsize, section_nr, i;
@@ -163,6 +163,11 @@ static void register_page_bootmem_info_section(unsigned long start_pfn) get_page_bootmem(section_nr, page, MIX_SECTION_INFO); } +#else +static inline void register_page_bootmem_info_section (unsigned long start_pfn) +{ +} +#endif void register_page_bootmem_info_node (struct pglist_data *pgdat) {
@@ -198,7 +203,6 @@ void register_page_bootmem_info_node(struct pglist_data *pgdat)register_page_bootmem_info_section (pfn); } -#endif /* !CONFIG_SPARSEMEM_VMEMMAP */ static void grow_zone_span (struct zone *zone,unsigned long start_pfn,unsigned long end_pfn)
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 15/19 memory-hotplug: implement register_page_bootmem_info_section of sparse-vmemmap
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
For removing memmap region of sparse-vmemmap which is allocated bootmem, memmap region of sparse-vmemmap needs to be registered by get_page_bootmem(). So the patch searches pages of virtual mapping and registers the pages by get_page_bootmem().
--- arch/x86/mm/init_64.c | 52 ++++++++++++++++++++++++++++++++++++++++ include/linux/memory_hotplug.h | 2 + include/linux/mm.h | 3 +- mm/memory_hotplug.c | 23 +++++++++++++++-- 4 files changed, 76 insertions(+), 4 deletions(-)
arch/x86/mm/init_64.c +52 -0
@@ -1138,6 +1138,58 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)return 0 ; } +void register_page_bootmem_memmap (unsigned long section_nr, +struct page *start_page,unsigned long size) +{ +unsigned long addr = (unsigned long )start_page; +unsigned long end = (unsigned long )(start_page + size); +unsigned long next; +pgd_t *pgd; +pud_t *pud; +pmd_t *pmd; + +for (; addr < end; addr = next) { +pte_t *pte =NULL ; + + pgd =pgd_offset_k (addr); +if (pgd_none (*pgd)) { + next = (addr +PAGE_SIZE ) &PAGE_MASK ; +continue ; + } +get_page_bootmem (section_nr,pgd_page (*pgd),MIX_SECTION_INFO ); + + pud =pud_offset (pgd, addr); +if (pud_none (*pud)) { + next = (addr +PAGE_SIZE ) &PAGE_MASK ; +continue ; + } +get_page_bootmem (section_nr,pud_page (*pud),MIX_SECTION_INFO ); + +if (!cpu_has_pse) { + next = (addr +PAGE_SIZE ) &PAGE_MASK ; + pmd =pmd_offset (pud, addr); +if (pmd_none (*pmd)) +continue ; +get_page_bootmem (section_nr,pmd_page (*pmd), +MIX_SECTION_INFO ); + + pte =pte_offset_kernel (pmd, addr); +if (pte_none (*pte)) +continue ; +get_page_bootmem (section_nr,pte_page (*pte), +SECTION_INFO ); + }else { + next =pmd_addr_end (addr, end); + + pmd =pmd_offset (pud, addr); +if (pmd_none (*pmd)) +continue ; +get_page_bootmem (section_nr,pmd_page (*pmd), +SECTION_INFO ); + } + } +} +void __meminit vmemmap_populate_print_last (void ) {if (p_start) {
include/linux/memory_hotplug.h +2 -0
@@ -164,6 +164,8 @@ static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat)extern void register_page_bootmem_info_node (struct pglist_data *pgdat);extern void put_page_bootmem (struct page *page); +extern void get_page_bootmem (unsigned long ingo,struct page *page, +unsigned long type);/* * Lock for memory hotplug guarantees 1) all callbacks for memory hotplug
include/linux/mm.h +2 -1
@@ -1586,7 +1586,8 @@ int vmemmap_populate_basepages(struct page *start_page, unsigned long pages, int node);int vmemmap_populate (struct page *start_page,unsigned long pages,int node);void vmemmap_populate_print_last (void ); - +void register_page_bootmem_memmap (unsigned long section_nr,struct page *map, +unsigned long size);enum mf_flags {MF_COUNT_INCREASED =1 <<0 ,
mm/memory_hotplug.c +20 -3
@@ -91,8 +91,8 @@ static void release_memory_resource(struct resource *res) }#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE -static void get_page_bootmem (unsigned long info,struct page *page, -unsigned long type) +void get_page_bootmem (unsigned long info,struct page *page, +unsigned long type) {unsigned long page_type;
@@ -164,8 +164,25 @@ static void register_page_bootmem_info_section(unsigned long start_pfn) }#else -static inline void register_page_bootmem_info_section (unsigned long start_pfn) +static void register_page_bootmem_info_section (unsigned long start_pfn) { +unsigned long mapsize, section_nr; +struct mem_section *ms; +struct page *page, *memmap; + +if (!pfn_valid (start_pfn)) +return ; + + section_nr =pfn_to_section_nr (start_pfn); + ms =__nr_to_section (section_nr); + + memmap =sparse_decode_mem_map (ms->section_mem_map, section_nr); + + page =virt_to_page (memmap); + mapsize =sizeof (struct page ) *PAGES_PER_SECTION ; + mapsize =PAGE_ALIGN (mapsize) >>PAGE_SHIFT ; + +register_page_bootmem_memmap (section_nr, memmap,PAGES_PER_SECTION ); }#endif
Signature · 1 line
1.7.1
RFC PATCH v5 16/19 memory-hotplug: free memmap of sparse-vmemmap
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
All pages of virtual mapping in removed memory cannot be freed, since some pages used as PGD/PUD includes not only removed memory but also other memory. So the patch checks whether page can be freed or not.
How to check whether page can be freed or not?
1. When removing memory, the page structs of the revmoved memory are filled with 0FD.
2. All page structs are filled with 0xFD on PT/PMD, PT/PMD can be cleared. In this case, the page used as PT/PMD can be freed.
Applying patch, __remove_section() of CONFIG_SPARSEMEM_VMEMMAP is integrated into one. So __remove_section() of CONFIG_SPARSEMEM_VMEMMAP is deleted.
--- arch/x86/mm/init_64.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/mm.h | 2 + mm/memory_hotplug.c | 17 +------ mm/sparse.c | 5 +- 4 files changed, 128 insertions(+), 17 deletions(-)
arch/x86/mm/init_64.c +121 -0
@@ -1138,6 +1138,127 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)return 0 ; } +#define PAGE_INUSE 0xFD + +unsigned long find_and_clear_pte_page (unsigned long addr,unsigned long end, +struct page **pp,int *page_size) +{ +pgd_t *pgd; +pud_t *pud; +pmd_t *pmd; +pte_t *pte; +void *page_addr; +unsigned long next; + + *pp =NULL ; + + pgd =pgd_offset_k (addr); +if (pgd_none (*pgd)) +return pgd_addr_end (addr, end); + + pud =pud_offset (pgd, addr); +if (pud_none (*pud)) +return pud_addr_end (addr, end); + +if (!cpu_has_pse) { + next = (addr +PAGE_SIZE ) &PAGE_MASK ; + pmd =pmd_offset (pud, addr); +if (pmd_none (*pmd)) +return next; + + pte =pte_offset_kernel (pmd, addr); +if (pte_none (*pte)) +return next; + + *page_size =PAGE_SIZE ; + *pp =pte_page (*pte); + }else { + next =pmd_addr_end (addr, end); + + pmd =pmd_offset (pud, addr); +if (pmd_none (*pmd)) +return next; + + *page_size =PMD_SIZE ; + *pp =pmd_page (*pmd); + } + +/* +* Removed page structs are filled with 0xFD. +*/ +memset ((void *)addr,PAGE_INUSE , next - addr); + + page_addr =page_address (*pp); + +/* +* Check the page is filled with 0xFD or not. +* memchr_inv() returns the address. In this case, we cannot +* clear PTE/PUD entry, since the page is used by other. +* So we cannot also free the page. +* +* memchr_inv() returns NULL. In this case, we can clear +* PTE/PUD entry, since the page is not used by other. +* So we can also free the page. +*/ +if (memchr_inv (page_addr,PAGE_INUSE , *page_size)) { + *pp =NULL ; +return next; + } + +if (!cpu_has_pse) +pte_clear (&init_mm, addr, pte); +else +pmd_clear (pmd); + +return next; +} + +void vmemmap_kfree (struct page *memmap,unsigned long nr_pages) +{ +unsigned long addr = (unsigned long )memmap; +unsigned long end = (unsigned long )(memmap + nr_pages); +unsigned long next; +struct page *page; +int page_size; + +for (; addr < end; addr = next) { + page =NULL ; + page_size =0 ; + next =find_and_clear_pte_page (addr, end, &page, &page_size); +if (!page) +continue ; + +free_pages ((unsigned long )page_address (page), +get_order (page_size)); +__flush_tlb_one (addr); + } + +} + +void vmemmap_free_bootmem (struct page *memmap,unsigned long nr_pages) +{ +unsigned long addr = (unsigned long )memmap; +unsigned long end = (unsigned long )(memmap + nr_pages); +unsigned long next; +struct page *page; +int page_size; +unsigned long magic; + +for (; addr < end; addr = next) { + page =NULL ; + page_size =0 ; + next =find_and_clear_pte_page (addr, end, &page, &page_size); +if (!page) +continue ; + + magic = (unsigned long ) page->lru.next; +if (magic ==SECTION_INFO ) +put_page_bootmem (page); +flush_tlb_kernel_range (addr, end); + } + +} +void register_page_bootmem_memmap (unsigned long section_nr,struct page *start_page,unsigned long size) {
include/linux/mm.h +2 -0
@@ -1588,6 +1588,8 @@ int vmemmap_populate(struct page *start_page, unsigned long pages, int node);void vmemmap_populate_print_last (void );void register_page_bootmem_memmap (unsigned long section_nr,struct page *map,unsigned long size); +void vmemmap_kfree (struct page *memmpa,unsigned long nr_pages); +void vmemmap_free_bootmem (struct page *memmpa,unsigned long nr_pages);enum mf_flags {MF_COUNT_INCREASED =1 <<0 ,
mm/memory_hotplug.c +2 -15
@@ -300,19 +300,6 @@ static int __meminit __add_section(int nid, struct zone *zone,return register_new_memory (nid,__pfn_to_section (phys_start_pfn)); } -#ifdef CONFIG_SPARSEMEM_VMEMMAP -static int __remove_section (struct zone *zone,struct mem_section *ms) -{ -int ret = -EINVAL ; - -if (!valid_section (ms)) -return ret; - - ret =unregister_memory_section (ms); - -return ret; -} -#else static int __remove_section (struct zone *zone,struct mem_section *ms) {unsigned long flags;
@@ -329,9 +316,9 @@ static int __remove_section(struct zone *zone, struct mem_section *ms)pgdat_resize_lock (pgdat, &flags);sparse_remove_one_section (zone, ms);pgdat_resize_unlock (pgdat, &flags); - return 0; + +return ret; } -#endif /* * Reasonably generic function for adding memory. It is
mm/sparse.c +3 -2
@@ -622,12 +622,13 @@ static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,/* This will make the necessary allocations eventually. */ return sparse_mem_map_populate(pnum, nid); } -static void __kfree_section_memmap (struct page *memmap,unsigned long nr_pages) +static void __kfree_section_memmap (struct page *page,unsigned long nr_pages) { -return ;/* XXX: Not implemented yet */ +vmemmap_kfree (page, nr_pages); }static void free_map_bootmem (struct page *page,unsigned long nr_pages) { +vmemmap_free_bootmem (page, nr_pages); }#else static struct page *__kmalloc_section_memmap (unsigned long nr_pages)
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC PATCH v5 16/19] memory-hotplug: free memmap of sparse-vmemmap
Quoted 12 lines · On Fri, 27 Jul 2012 18:34:38 +0800 Wen Congyang <[email protected]> wrote:
From: Yasuaki Ishimatsu <[email protected]>
All pages of virtual mapping in removed memory cannot be freed, since some pages used as PGD/PUD includes not only removed memory but also other memory. So the patch checks whether page can be freed or not.
How to check whether page can be freed or not?
1. When removing memory, the page structs of the revmoved memory are
filled with 0FD.
2. All page structs are filled with0xFDon PT/PMD, PT/PMD can be
cleared. In this case, the page used as PT/PMD can be freed.
Quoted 3 lines
Applying patch,
__remove_section()ofCONFIG_SPARSEMEM_VMEMMAPis integrated into one. So__remove_section()ofCONFIG_SPARSEMEM_VMEMMAPis deleted.
There should also be generic or dummy versions of the functions vmemmap_free_bootmem(), vmemmap_kfree() and register_page_bootmem_memmap(). It doesn't compile on other archtitectures than x86 as it is now:
mm/built-in.o: In function `sparse_remove_one_section':
(.text+0x49fa6): undefined reference to vmemmap_free_bootmem' mm/built-in.o: In function sparse_remove_one_section':
(.text+0x49fcc): undefined reference to vmemmap_kfree' mm/built-in.o: In function register_page_bootmem_info_node':
(.text+0x57c06): undefined reference to register_page_bootmem_memmap' mm/built-in.o: In function sparse_add_one_section':
(.meminit.text+0x2506): undefined reference to vmemmap_kfree' mm/built-in.o: In function sparse_add_one_section':
(.meminit.text+0x2528): undefined reference to `vmemmap_kfree'
make: *** [vmlinux] Error 1
Re: [RFC PATCH v5 16/19] memory-hotplug: free memmap of sparse-vmemmap
At 07/31/2012 08:22 PM, Gerald Schaefer Wrote:
Quoted 24 lines
Quoted 12 lines · On Fri, 27 Jul 2012 18:34:38 +0800 Wen Congyang <[email protected]> wrote:
From: Yasuaki Ishimatsu <[email protected]>
All pages of virtual mapping in removed memory cannot be freed, since some pages used as PGD/PUD includes not only removed memory but also other memory. So the patch checks whether page can be freed or not.
How to check whether page can be freed or not?
1. When removing memory, the page structs of the revmoved memory are
filled with 0FD.
2. All page structs are filled with0xFDon PT/PMD, PT/PMD can be
cleared. In this case, the page used as PT/PMD can be freed.Quoted 3 lines
Applying patch,
__remove_section()ofCONFIG_SPARSEMEM_VMEMMAPis integrated into one. So__remove_section()ofCONFIG_SPARSEMEM_VMEMMAPis deleted.There should also be generic or dummy versions of the functions
vmemmap_free_bootmem(),vmemmap_kfree()andregister_page_bootmem_memmap(). It doesn't compile on other archtitectures than x86 as it is now:
Quoted 13 lines
mm/built-in.o: In function `sparse_remove_one_section':
(.text+0x49fa6): undefined reference tovmemmap_free_bootmem' mm/built-in.o: In functionsparse_remove_one_section':
(.text+0x49fcc): undefined reference tovmemmap_kfree' mm/built-in.o: In functionregister_page_bootmem_info_node':
(.text+0x57c06): undefined reference toregister_page_bootmem_memmap' mm/built-in.o: In functionsparse_add_one_section':
(.meminit.text+0x2506): undefined reference tovmemmap_kfree' mm/built-in.o: In functionsparse_add_one_section':
(.meminit.text+0x2528): undefined reference to `vmemmap_kfree'
make: *** [vmlinux] Error 1
Thanks for testing. I will fix it.
Wen Congyang
RFC PATCH v5 17/19 memory_hotplug: clear zone when the memory is removed
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
When a memory is added, we update zone's and pgdat's start_pfn and spanned_pages in the function __add_zone(). So we should revert these when the memory is removed. Add a new function __remove_zone() to do this.
--- mm/memory_hotplug.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 181 insertions(+), 0 deletions(-)
mm/memory_hotplug.c +181 -0
@@ -300,10 +300,187 @@ static int __meminit __add_section(int nid, struct zone *zone,return register_new_memory (nid,__pfn_to_section (phys_start_pfn)); } +/* find the smallest valid pfn in the range [start_pfn, end_pfn) */ +static int find_smallest_section_pfn (unsigned long start_pfn, +unsigned long end_pfn) +{ +struct mem_section *ms; + +for (; start_pfn < end_pfn; start_pfn +=PAGES_PER_SECTION ) { + ms =__pfn_to_section (start_pfn); + +if (unlikely (!valid_section (ms))) +continue ; + +return start_pfn; + } + +return 0 ; +} + +/* find the biggest valid pfn in the range [start_pfn, end_pfn). */ +static int find_biggest_section_pfn (unsigned long start_pfn, +unsigned long end_pfn) +{ +struct mem_section *ms; +unsigned long pfn; + +/* pfn is the end pfn of a memory section. */ + pfn = end_pfn -1 ; +for (; pfn >= start_pfn; pfn -=PAGES_PER_SECTION ) { + ms =__pfn_to_section (pfn); + +if (unlikely (!valid_section (ms))) +continue ; + +return pfn; + } + +return 0 ; +} + +static void shrink_zone_span (struct zone *zone,unsigned long start_pfn, +unsigned long end_pfn) +{ +unsigned long zone_start_pfn = zone->zone_start_pfn; +unsigned long zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages; +unsigned long pfn; +struct mem_section *ms; + +zone_span_writelock (zone); +if (zone_start_pfn == start_pfn) { +/* +* If the section is smallest section in the zone, it need +* shrink zone->zone_start_pfn and zone->zone_spanned_pages. +* In this case, we find second smallest valid mem_section +* for shrinking zone. +*/ + pfn =find_smallest_section_pfn (end_pfn, zone_end_pfn); +if (pfn) { + zone->zone_start_pfn = pfn; + zone->spanned_pages = zone_end_pfn - pfn; + } + }else if (zone_end_pfn == end_pfn) { +/* +* If the section is biggest section in the zone, it need +* shrink zone->spanned_pages. +* In this case, we find second biggest valid mem_section for +* shrinking zone. +*/ + pfn =find_biggest_section_pfn (zone_start_pfn, start_pfn); +if (pfn) + zone->spanned_pages = pfn - zone_start_pfn +1 ; + } + +/* +* The section is not biggest or smallest mem_section in the zone, it +* only creates a hole in the zone. So in this case, we need not +* change the zone. But perhaps, the zone has only hole data. Thus +* it check the zone has only hole or not. +*/ + pfn = zone_start_pfn; +for (; pfn < zone_end_pfn; pfn +=PAGES_PER_SECTION ) { + ms =__pfn_to_section (pfn); + +if (unlikely (!valid_section (ms))) +continue ; + +/* If the section is current section, it continues the loop */ +if (start_pfn == pfn) +continue ; + +/* If we find valid section, we have nothing to do */ +zone_span_writeunlock (zone); +return ; + } + +/* The zone has no valid section */ + zone->zone_start_pfn =0 ; + zone->spanned_pages =0 ; +zone_span_writeunlock (zone); +} + +static void shrink_pgdat_span (struct pglist_data *pgdat, +unsigned long start_pfn,unsigned long end_pfn) +{ +unsigned long pgdat_start_pfn = pgdat->node_start_pfn; +unsigned long pgdat_end_pfn = + pgdat->node_start_pfn + pgdat->node_spanned_pages; +unsigned long pfn; +struct mem_section *ms; + +if (pgdat_start_pfn == start_pfn) { +/* +* If the section is smallest section in the pgdat, it need +* shrink pgdat->node_start_pfn and pgdat->node_spanned_pages. +* In this case, we find second smallest valid mem_section +* for shrinking zone. +*/ + pfn =find_smallest_section_pfn (end_pfn, pgdat_end_pfn); +if (pfn) { + pgdat->node_start_pfn = pfn; + pgdat->node_spanned_pages = pgdat_end_pfn - pfn; + } + }else if (pgdat_end_pfn == end_pfn) { +/* +* If the section is biggest section in the pgdat, it need +* shrink pgdat->node_spanned_pages. +* In this case, we find second biggest valid mem_section for +* shrinking zone. +*/ + pfn =find_biggest_section_pfn (pgdat_start_pfn, start_pfn); +if (pfn) + pgdat->node_spanned_pages = pfn - pgdat_start_pfn +1 ; + } + +/* +* If the section is not biggest or smallest mem_section in the pgdat, +* it only creates a hole in the pgdat. So in this case, we need not +* change the pgdat. +* But perhaps, the pgdat has only hole data. Thus it check the pgdat +* has only hole or not. +*/ + pfn = pgdat_start_pfn; +for (; pfn < pgdat_end_pfn; pfn +=PAGES_PER_SECTION ) { + ms =__pfn_to_section (pfn); + +if (unlikely (!valid_section (ms))) +continue ; + +/* If the section is current section, it continues the loop */ +if (start_pfn == pfn) +continue ; + +/* If we find valid section, we have nothing to do */ +return ; + } + +/* The pgdat has no valid section */ + pgdat->node_start_pfn =0 ; + pgdat->node_spanned_pages =0 ; +} + +static void __remove_zone (struct zone *zone,unsigned long start_pfn) +{ +struct pglist_data *pgdat = zone->zone_pgdat; +int nr_pages =PAGES_PER_SECTION ; +int zone_type; +unsigned long flags; + + zone_type = zone - pgdat->node_zones; + +pgdat_resize_lock (zone->zone_pgdat, &flags); +shrink_zone_span (zone, start_pfn, start_pfn + nr_pages); +shrink_pgdat_span (pgdat, start_pfn, start_pfn + nr_pages); +pgdat_resize_unlock (zone->zone_pgdat, &flags); +} +static int __remove_section (struct zone *zone,struct mem_section *ms) {unsigned long flags;struct pglist_data *pgdat = zone->zone_pgdat; +unsigned long start_pfn; +int scn_nr;int ret = -EINVAL ;if (!valid_section (ms))
@@ -313,6 +490,10 @@ static int __remove_section(struct zone *zone, struct mem_section *ms)if (ret)return ret; + scn_nr =__section_nr (ms); + start_pfn =section_nr_to_pfn (scn_nr); +__remove_zone (zone, start_pfn); +pgdat_resize_lock (pgdat, &flags);sparse_remove_one_section (zone, ms);pgdat_resize_unlock (pgdat, &flags);
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v5 18/19 memory-hotplug: add node_device_release
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
When calling unregister_node(), the function shows following message at device_release().
Device 'node2' does not have a release() function, it is broken and must be fixed.
So the patch implements node_device_release()
--- drivers/base/node.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-)
drivers/base/node.c +8 -0
@@ -252,6 +252,13 @@ static inline void hugetlb_register_node(struct node *node) {}static inline void hugetlb_unregister_node (struct node *node) {}#endif +static void node_device_release (struct device *dev) +{ +struct node *node_dev =to_node (dev); + +flush_work (&node_dev->node_work); +memset (node_dev,0 ,sizeof (struct node )); +}/* * register_node - Setup a sysfs device for a node.
@@ -265,6 +272,7 @@ int register_node(struct node *node, int num, struct node *parent) node->dev.id = num; node->dev.bus = &node_subsys; + node->dev.release = node_device_release; error =device_register (&node->dev);if (!error){
Signature · 1 line
1.7.1
RFC PATCH v5 19/19 memory-hotplug: remove sysfs file of node
In reply to Wen CongyangFrom: Yasuaki Ishimatsu <[email protected]>
The patch adds node_set_offline() and unregister_one_node() to remove_memory() for removing sysfs file of node.
--- mm/memory_hotplug.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
mm/memory_hotplug.c +5 -0
@@ -1267,6 +1267,11 @@ int __ref remove_memory(int nid, u64 start, u64 size)/* remove memmap entry */ firmware_map_remove (start, start + size,"System RAM" ); +if (!node_present_pages (nid)) { +node_set_offline (nid); +unregister_one_node (nid); + } +arch_remove_memory (start, size); out:unlock_memory_hotplug ();
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC PATCH v5 19/19] memory-hotplug: remove sysfs file of node
Hi Wen,
Quoted 25 lines · Wen Congyang
From: Yasuaki Ishimatsu <[email protected]>
The patch adds
node_set_offline()andunregister_one_node()toremove_memory()for removing sysfs file of node.CC David Rientjes <[email protected]>CC Jiang Liu <[email protected]>CC Len Brown <[email protected]>CC Benjamin Herrenschmidt <[email protected]>CC Paul Mackerras <[email protected]>CC Christoph Lameter <[email protected]>Cc Minchan Kim <[email protected]>CC Andrew Morton <[email protected]>CC KOSAKI Motohiro <[email protected]>CC Wen Congyang <[email protected]>Signed-off-by Yasuaki Ishimatsu <[email protected]>--- mm/memory_hotplug.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)mm/memory_hotplug.c +0
-0
mm/memory_hotplug.c int __ref remove_memory(int nid, u64 start, u64 size) · line 1270
Quoted 4 lines
mm/memory_hotplug.c +1
-0@@ -1267,6 +1267,11 @@ int __ref remove_memory(int nid, u64 start, u64 size)/* remove memmap entry */ firmware_map_remove (start, start + size,"System RAM" ); +if (!node_present_pages (nid)) {
Applying [PATCH v5 17/19], pgdat->node_spanned_pages can become 0 when all memory of the pgdat is removed. When pgdat->node_spanned_pages is 0, it means the pgdat has no memory. So I think node_spanned_pages() is better.
Thanks,
Yasuaki Ishimatsu
mm/memory_hotplug.c int __ref remove_memory(int nid, u64 start, u64 size) · line 1277
Quoted 8 lines
mm/memory_hotplug.c +4
-0+node_set_offline (nid); +unregister_one_node (nid); + } +arch_remove_memory (start, size); out:unlock_memory_hotplug ();
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC PATCH v5 19/19] memory-hotplug: remove sysfs file of node
At 07/27/2012 06:45 PM, Yasuaki Ishimatsu Wrote:
Quoted 33 lines
Hi Wen,
Quoted 30 lines · Wen Congyang
From: Yasuaki Ishimatsu <[email protected]>
The patch adds
node_set_offline()andunregister_one_node()toremove_memory()
for removing sysfs file of node.CC David Rientjes <[email protected]>CC Jiang Liu <[email protected]>CC Len Brown <[email protected]>CC Benjamin Herrenschmidt <[email protected]>CC Paul Mackerras <[email protected]>CC Christoph Lameter <[email protected]>Cc Minchan Kim <[email protected]>CC Andrew Morton <[email protected]>CC KOSAKI Motohiro <[email protected]>CC Wen Congyang <[email protected]>Signed-off-by Yasuaki Ishimatsu <[email protected]>--- mm/memory_hotplug.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)mm/memory_hotplug.c +0
-0@@ -1267,6 +1267,11 @@ int __ref remove_memory(int nid, u64 start, u64 size) /* remove memmap entry */ firmware_map_remove(start, start + size, "System RAM");
Quoted 6 lines
mm/memory_hotplug.c int __ref remove_memory(int nid, u64 start, u64 size) · line 1270
Quoted 1 line
mm/memory_hotplug.c +1
-0+if (!node_present_pages (nid)) {Applying [PATCH v5 17/19],
pgdat->node_spanned_pagescan become 0 when all memory of the pgdat is removed. Whenpgdat->node_spanned_pagesis 0, it means the pgdat has no memory. So I thinknode_spanned_pages()is better.
node_spanned_pages = present_pages + hole_pages
So present_pages is always less or equal than spanned_pages, and I think checking present pages is better.
Thanks
Wen Congyang
Quoted 15 lines
Thanks,
Yasuaki IshimatsuQuoted 8 lines
mm/memory_hotplug.c +4
-0+node_set_offline (nid); +unregister_one_node (nid); + } +arch_remove_memory (start, size); out:unlock_memory_hotplug();
Re: [RFC PATCH v5 19/19] memory-hotplug: remove sysfs file of node
In reply to Yasuaki IshimatsuAt 07/27/2012 06:45 PM, Yasuaki Ishimatsu Wrote:
Quoted 33 lines
Hi Wen,
Quoted 30 lines · Wen Congyang
From: Yasuaki Ishimatsu <[email protected]>
The patch adds
node_set_offline()andunregister_one_node()toremove_memory()
for removing sysfs file of node.CC David Rientjes <[email protected]>CC Jiang Liu <[email protected]>CC Len Brown <[email protected]>CC Benjamin Herrenschmidt <[email protected]>CC Paul Mackerras <[email protected]>CC Christoph Lameter <[email protected]>Cc Minchan Kim <[email protected]>CC Andrew Morton <[email protected]>CC KOSAKI Motohiro <[email protected]>CC Wen Congyang <[email protected]>Signed-off-by Yasuaki Ishimatsu <[email protected]>--- mm/memory_hotplug.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)mm/memory_hotplug.c +0
-0@@ -1267,6 +1267,11 @@ int __ref remove_memory(int nid, u64 start, u64 size) /* remove memmap entry */ firmware_map_remove(start, start + size, "System RAM");
Quoted 6 lines
mm/memory_hotplug.c int __ref remove_memory(int nid, u64 start, u64 size) · line 1270
Quoted 1 line
mm/memory_hotplug.c +1
-0+if (!node_present_pages (nid)) {Applying [PATCH v5 17/19],
pgdat->node_spanned_pagescan become 0 when all memory of the pgdat is removed. Whenpgdat->node_spanned_pagesis 0, it means the pgdat has no memory. So I thinknode_spanned_pages()is better.
Hmm, if the node contains cpu, and the cpu is onlined, can we offline this node?
Thanks
Wen Congyang
Quoted 15 lines
Thanks,
Yasuaki IshimatsuQuoted 8 lines
mm/memory_hotplug.c +4
-0+node_set_offline (nid); +unregister_one_node (nid); + } +arch_remove_memory (start, size); out:unlock_memory_hotplug();
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Hi Wen,
Quoted 11 lines · Wen Congyang
This patch series aims to support physical memory hot-remove.
The patches can free/remove following things:
-
acpi_memory_info: [RFC PATCH 4/19]
-/sys/firmware/memmap/X/{end, start, type} : [RFC PATCH 8/19]- iomem_resource : [RFC PATCH 9/19] - mem_section and related sysfs files : [RFC PATCH 10-11, 13-16/19] - page table of removed memory : [RFC PATCH 12/19] - node and related sysfs files : [RFC PATCH 18-19/19]
Quoted 6 lines
If you find lack of function for physical memory hot-remove, please let me know.
change log of v5:
* merge the patchset to clear page table and the patchset to hot remove memory(from ishimatsu) to one big patchset.
Thank you for merging patches. I'll review next Monday.
Thanks,
Yasuaki Ishimatsu
Quoted 119 lines
[RFC PATCH v5 1/19]
* renameremove_memory()to offline_memory()/offline_pages()[RFC PATCH v5 2/19]
* new patch: implementoffline_memory(). This function offlines pages, update memory block's state, and notify the userspace that the memory block's state is changed.[RFC PATCH v5 4/19]
* offline and remove memory inacpi_memory_disable_device()too.[RFC PATCH v5 17/19]
* new patch: add a new function__remove_zone()to revert the things done in the function__add_zone().[RFC PATCH v5 18/19]
* flush work befor reseting node device.change log of v4:
* remove "memory-hotplug : unify argument of firmware_map_add_early/hotplug" from the patch series, since the patch is a bugfix. It is being disccussed on other thread. But for testing the patch series, the patch is needed. So I added the patch as [PATCH 0/13].[RFC PATCH v4 2/13]
* check memory is online or not atremove_memory()
* addmemory_add_physaddr_to_nid()toacpi_memory_device_remove()for getting node id[RFC PATCH v4 3/13]
* create new patch : check memory is online or not atonline_pages()[RFC PATCH v4 4/13]
* add__refsection toremove_memory()
* callfirmware_map_remove_entry()beforeremove_sysfs_fw_map_entry()[RFC PATCH v4 11/13]
* rewriteregister_page_bootmem_memmap()for removing page used as PT/PMDchange log of v3:
* rebase to 3.5.0-rc6[RFC PATCH v2 2/13]
* remove extrakobject_put()* The patch was commented by Wen. Wen's comment is "
acpi_memory_device_remove()should ignore a return value ofremove_memory()since caller does not care the return value". But I did not change it since I think caller should care the return value. And I am trying to fix it as follow:https://lkml.org/lkml/2012/7/5/624
[RFC PATCH v2 4/13]
* remove afirmware_memmap_entryallocated bykzmalloc()change log of v2:
[RFC PATCH v2 2/13]
* check whether memory block is offline or not before callingoffline_memory()
* check whether section is valid or not inis_memblk_offline()
* callkobject_put()for eachmemory_blockinis_memblk_offline()[RFC PATCH v2 3/13]
* unify the end argument of firmware_map_add_early/hotplug[RFC PATCH v2 4/13]
* addrelease_firmware_map_entry()for freeingfirmware_map_entry[RFC PATCH v2 6/13]
* addrelease_memory_block()for freeingmemory_block[RFC PATCH v2 11/13]
* fix wrong arguments offree_pages()Wen Congyang (5):
memory-hotplug: implementoffline_memory()
memory-hotplug: store the node id inacpi_memory_device
memory-hotplug: export the functionacpi_bus_remove()
memory-hotplug: callacpi_bus_remove()to remove memory device
memory-hotplug: introduce new functionarch_remove_memory()Yasuaki Ishimatsu (14):
memory-hotplug: renameremove_memory()to
offline_memory()/offline_pages()
memory-hotplug: offline and remove memory when removing the memory
device
memory-hotplug: check whether memory is present or not
memory-hotplug: remove/sys/firmware/memmap/Xsysfs
memory-hotplug: does not release memory region inPAGES_PER_SECTION
chunks
memory-hotplug: addmemory_block_release
memory-hotplug:remove_memorycalls__remove_pages
memory-hotplug: check page type inget_page_bootmem
memory-hotplug: moveregister_page_bootmem_info_nodeand
put_page_bootmemfor sparse-vmemmap
memory-hotplug: implementregister_page_bootmem_info_sectionof
sparse-vmemmap
memory-hotplug: free memmap of sparse-vmemmap
memory_hotplug: clear zone when the memory is removed
memory-hotplug: addnode_device_release
memory-hotplug: remove sysfs file of nodearch/ia64/mm/init.c | 16 + arch/powerpc/mm/mem.c | 14 + arch/powerpc/platforms/pseries/hotplug-memory.c | 16 +- arch/s390/mm/init.c | 8 + arch/sh/mm/init.c | 15 + arch/tile/mm/init.c | 8 + arch/x86/include/asm/pgtable_types.h | 1 + arch/x86/mm/init_32.c | 10 + arch/x86/mm/init_64.c | 333 ++++++++++++++++++++++ arch/x86/mm/pageattr.c | 47 ++-- drivers/acpi/acpi_memhotplug.c | 51 +++- drivers/acpi/scan.c | 3 +- drivers/base/memory.c | 90 ++++++- drivers/base/node.c | 8 + drivers/firmware/memmap.c | 78 +++++- include/acpi/acpi_bus.h | 1 +
Quoted 9 lines
include/linux/firmware-map.h | 6 + include/linux/memory.h | 5 + include/linux/memory_hotplug.h | 25 +- include/linux/mm.h | 5 +- include/linux/mmzone.h | 19 ++ mm/memory_hotplug.c | 337 +++++++++++++++++++++-- mm/sparse.c | 5 +- 23 files changed, 1010 insertions(+), 91 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>