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(-)
From: Yasuaki Ishimatsu <redacted>
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.
CC: Thomas Gleixner <redacted>
CC: Ingo Molnar <mingo@kernel.org>
CC: H. Peter Anvin <hpa@zytor.com>
CC: Tejun Heo <tj@kernel.org>
CC: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Dave Hansen <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
---
arch/x86/kernel/e820.c | 2 +-
drivers/firmware/memmap.c | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
Index: linux-3.5-rc6/arch/x86/kernel/e820.c
===================================================================
We free info, but we forget to remove it from the list. It will cause
unexpected problem when we access the list next time.
Signed-off-by: Wen Congyang <redacted>
---
drivers/acpi/acpi_memhotplug.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
From: Yasuaki Ishimatsu <redacted>
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.
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
Signed-off-by: Wen Congyang <redacted>
---
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(-)
@@ -233,7 +233,8 @@ static inline int is_mem_section_removable(unsigned long pfn,externintmem_online_node(intnid);externintadd_memory(intnid,u64start,u64size);externintarch_add_memory(intnid,u64start,u64size);-externintremove_memory(u64start,u64size);+externintoffline_pages(unsignedlongstart_pfn,unsignedlongnr_pages);+externintoffline_memory(u64start,u64size);externintsparse_add_one_section(structzone*zone,unsignedlongstart_pfn,intnr_pages);externvoidsparse_remove_one_section(structzone*zone,structmem_section*ms);
@@ -865,7 +865,7 @@ check_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)returnofflined;}-staticint__refoffline_pages(unsignedlongstart_pfn,+staticint__ref__offline_pages(unsignedlongstart_pfn,unsignedlongend_pfn,unsignedlongtimeout){unsignedlongpfn,nr_pages,expire;
The 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().
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Yasuaki Ishimatsu <redacted>
CC: Vasilis Liaskovitis <redacted>
Signed-off-by: Wen Congyang <redacted>
---
drivers/base/memory.c | 31 +++++++++++++++++++++++++++----
include/linux/memory_hotplug.h | 2 ++
mm/memory_hotplug.c | 37 ++++++++++++++++++++++++++++++++++++-
3 files changed, 65 insertions(+), 5 deletions(-)
@@ -275,13 +275,11 @@ memory_block_action(unsigned long phys_index, unsigned long action)returnret;}-staticintmemory_block_change_state(structmemory_block*mem,+staticint__memory_block_change_state(structmemory_block*mem,unsignedlongto_state,unsignedlongfrom_state_req){intret=0;-mutex_lock(&mem->state_mutex);-if(mem->state!=from_state_req){ret=-EINVAL;gotoout;
@@ -309,10 +307,20 @@ static int memory_block_change_state(struct memory_block *mem,break;}out:-mutex_unlock(&mem->state_mutex);returnret;}+staticintmemory_block_change_state(structmemory_block*mem,+unsignedlongto_state,unsignedlongfrom_state_req)+{+intret;++mutex_lock(&mem->state_mutex);+ret=__memory_block_change_state(mem,to_state,from_state_req);+mutex_unlock(&mem->state_mutex);++returnret;+}staticssize_tstore_mem_state(structdevice*dev,structdevice_attribute*attr,constchar*buf,size_tcount)
@@ -653,6 +661,21 @@ int unregister_memory_section(struct mem_section *section)}/*+*offlineonememoryblock.Ifthememoryblockhasbeenofflined,donothing.+*/+intoffline_memory_block(structmemory_block*mem)+{+intret=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);++returnret;+}++/**Initializethesysfssupportformemorydevices...*/int__initmemory_dev_init(void)
@@ -997,7 +997,42 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)intoffline_memory(u64start,u64size){-return-EINVAL;+structmemory_block*mem=NULL;+structmem_section*section;+unsignedlongstart_pfn,end_pfn;+unsignedlongpfn,section_nr;+intret;++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);+returnret;+}+}++if(mem)+kobject_put(&mem->dev.kobj);++return0;}#elseintoffline_pages(u64start,u64size)
The 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.
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Yasuaki Ishimatsu <redacted>
Signed-off-by: Wen Congyang <redacted>
Reviewed-by: Yasuaki Ishimatsu <redacted>
---
drivers/acpi/acpi_memhotplug.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
@@ -83,6 +83,7 @@ struct acpi_memory_info {structacpi_memory_device{structacpi_device*device;unsignedintstate;/* State of the memory device */+intnid;structlist_headres_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_ERRPREFIX"add_memory failed\n");mem_device->state=MEMORY_INVALID_STATE;
From: Yasuaki Ishimatsu <redacted>
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.
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
Signed-off-by: Wen Congyang <redacted>
---
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(-)
@@ -310,26 +311,42 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)return0;}-staticintacpi_memory_disable_device(structacpi_memory_device*mem_device)+staticint+acpi_memory_device_remove_memory(structacpi_memory_device*mem_device){intresult;structacpi_memory_info*info,*n;+intnode=mem_device->nid;--/*-*AsktheVMtoofflinethismemoryrange.-*Note:Assumethatthisfunctionreturnszeroonsuccess-*/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)returnresult;++result=remove_memory(node,info->start_addr,+info->length);+if(result)+returnresult;}+list_del(&info->list);kfree(info);}+return0;+}++staticintacpi_memory_disable_device(structacpi_memory_device*mem_device)+{+intresult;++/*+*AsktheVMtoofflinethismemoryrange.+*Note:Assumethatthisfunctionreturnszeroonsuccess+*/+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)staticintacpi_memory_device_remove(structacpi_device*device,inttype){structacpi_memory_device*mem_device=NULL;-+intresult;if(!device||!acpi_driver_data(device))return-EINVAL;mem_device=acpi_driver_data(device);++if(type==ACPI_BUS_REMOVAL_EJECT){+/*+*offlineandremovememoryonlywhenthememorydeviceis+*ejected.+*/+result=acpi_memory_device_remove_memory(mem_device);+if(result)+returnresult;+}+kfree(mem_device);return0;
@@ -1034,6 +1034,28 @@ int offline_memory(u64 start, u64 size)return0;}++intremove_memory(intnid,u64start,u64size)+{+intret=-EBUSY;+lock_memory_hotplug();+/*+*Thememorymightbecomeonlinebyothertask,evenifyouoffineit.+*Sowecheckwhetherthecpuhasbeenonlinedornot.+*/+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();+returnret;++}+EXPORT_SYMBOL_GPL(remove_memory);+#elseintoffline_pages(u64start,u64size){
@@ -467,6 +467,19 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages)structmemory_notifyarg;lock_memory_hotplug();+/*+*Ifsystemsupportsmemoryhot-remove,thememorymayhavebeen+*removed.Sowecheckwhetherthememoryhasbeenremovedornot.+*+*Note:WhenCONFIG_SPARSEMEMisdefined,pfns_present()become+*effective.IfCONFIG_SPARSEMEMisnotdefined,pfns_present()+*alwaysreturns0.+*/+ret=pfns_present(pfn,nr_pages);+if(ret){+unlock_memory_hotplug();+returnret;+}arg.start_pfn=pfn;arg.nr_pages=nr_pages;arg.status_change_nid=-1;
The 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.
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Yasuaki Ishimatsu <redacted>
Signed-off-by: Wen Congyang <redacted>
---
drivers/acpi/scan.c | 3 ++-
include/acpi/acpi_bus.h | 1 +
2 files changed, 3 insertions(+), 1 deletions(-)
The memory device has been ejected and powoffed, so we can call
acpi_bus_remove() to remove the memory device from acpi bus.
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Yasuaki Ishimatsu <redacted>
Signed-off-by: Wen Congyang <redacted>
---
drivers/acpi/acpi_memhotplug.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
From: Yasuaki Ishimatsu <redacted>
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.
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Wen Congyang <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
---
drivers/firmware/memmap.c | 78 +++++++++++++++++++++++++++++++++++++++++-
include/linux/firmware-map.h | 6 +++
mm/memory_hotplug.c | 9 ++++-
3 files changed, 90 insertions(+), 3 deletions(-)
@@ -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)++staticvoidrelease_firmware_map_entry(structkobject*kobj)+{+structfirmware_map_entry*entry=to_memmap_entry(kobj);+structpage*page;++page=virt_to_page(entry);+if(PageSlab(page)||PageCompound(page))+kfree(entry);++/* There is no way to free memory allocated from bootmem*/+}+staticstructkobj_typememmap_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,return0;}+/**+*firmware_map_remove_entry()-Doestherealworktoremoveafirmware+*memmapentry.+*@entry:removedentry.+**/+staticinlinevoidfirmware_map_remove_entry(structfirmware_map_entry*entry)+{+list_del(&entry->list);+}+/**Addmemmapentryonsysfs*/
@@ -144,6 +170,31 @@ static int add_sysfs_fw_map_entry(struct firmware_map_entry *entry)return0;}+/*+*Removememmapentryonsysfs+*/+staticinlinevoidremove_sysfs_fw_map_entry(structfirmware_map_entry*entry)+{+kobject_put(&entry->kobj);+}++/*+*Searchmemmapentry+*/++structfirmware_map_entry*__meminit+find_firmware_map_entry(u64start,u64end,constchar*type)+{+structfirmware_map_entry*entry;++list_for_each_entry(entry,&map_entries,list)+if((entry->start==start)&&(entry->end==end)&&+(!strcmp(entry->type,type)))+returnentry;++returnNULL;+}+/***firmware_map_add_hotplug()-Addsafirmwaremappingentrywhenwedo*memoryhotplug.
@@ -196,6 +247,32 @@ int __init firmware_map_add_early(u64 start, u64 end, const char *type)returnfirmware_map_add_entry(start,end,type,entry);}+/**+*firmware_map_remove()-removeafirmwaremappingentry+*@start:Startofthememoryrange.+*@end:Endofthememoryrange.+*@type:Typeofthememoryrange.+*+*removesafirmwaremappingentry.+*+*Returns0onsuccess,or-EINVALifnoentry.+**/+int__meminitfirmware_map_remove(u64start,u64end,constchar*type)+{+structfirmware_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);++return0;+}+/**Sysfsfunctions-------------------------------------------------------------*/
From: Yasuaki Ishimatsu <redacted>
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.
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Wen Congyang <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
---
arch/powerpc/platforms/pseries/hotplug-memory.c | 13 +++++++++----
mm/memory_hotplug.c | 4 ++--
2 files changed, 11 insertions(+), 6 deletions(-)
@@ -77,7 +77,8 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz{unsignedlongstart,start_pfn;structzone*zone;-intret;+inti,ret;+intsections_to_remove;start_pfn=base>>PAGE_SHIFT;
@@ -97,9 +98,13 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz*tosysfs"state"fileandwecan'tremovesysfsentries*whilewritingtoit.Sowehavetodeferittohere.*/-ret=__remove_pages(zone,start_pfn,memblock_size>>PAGE_SHIFT);-if(ret)-returnret;+sections_to_remove=(memblock_size>>PAGE_SHIFT)/PAGES_PER_SECTION;+for(i=0;i<sections_to_remove;i++){+unsignedlongpfn=start_pfn+i*PAGES_PER_SECTION;+ret=__remove_pages(zone,start_pfn,PAGES_PER_SECTION);+if(ret)+returnret;+}/**Updatememoryregionsformemoryremove
@@ -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++){unsignedlongpfn=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;
From: Yasuaki Ishimatsu <redacted>
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()
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Wen Congyang <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
---
drivers/base/memory.c | 11 ++++++++++-
1 files changed, 10 insertions(+), 1 deletions(-)
From: Yasuaki Ishimatsu <redacted>
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().
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Wen Congyang <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
---
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(-)
@@ -76,7 +76,6 @@ unsigned long memory_block_size_bytes(void)staticintpseries_remove_memblock(unsignedlongbase,unsignedintmemblock_size){unsignedlongstart,start_pfn;-structzone*zone;inti,ret;intsections_to_remove;
@@ -87,8 +86,6 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_sizreturn0;}-zone=page_zone(pfn_to_page(start_pfn));-/**Removesectionmappingsandsysfsentriesforthe*sectionofthememoryweareremoving.
@@ -101,7 +98,7 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_sizsections_to_remove=(memblock_size>>PAGE_SHIFT)/PAGES_PER_SECTION;for(i=0;i<sections_to_remove;i++){unsignedlongpfn=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)returnret;}
@@ -90,8 +90,7 @@ extern bool is_pageblock_removable_nolock(struct page *page);/* reasonably generic interface to expand the physical pages in a zone */externint__add_pages(intnid,structzone*zone,unsignedlongstart_pfn,unsignedlongnr_pages);-externint__remove_pages(structzone*zone,unsignedlongstart_pfn,-unsignedlongnr_pages);+externint__remove_pages(unsignedlongstart_pfn,unsignedlongnr_pages);#ifdef CONFIG_NUMAexternintmemory_add_physaddr_to_nid(u64start);
@@ -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++){unsignedlongpfn=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;
We 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).
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Yasuaki Ishimatsu <redacted>
Signed-off-by: Wen Congyang <redacted>
---
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(-)
@@ -85,6 +85,7 @@ extern void __online_page_free(struct page *page);#ifdef CONFIG_MEMORY_HOTREMOVEexternboolis_pageblock_removable_nolock(structpage*page);+externintarch_remove_memory(unsignedlongstart,unsignedlongsize);#endif /* CONFIG_MEMORY_HOTREMOVE *//* reasonably generic interface to expand the physical pages in a zone */
From: Yasuaki Ishimatsu <redacted>
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.
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Wen Congyang <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
---
mm/memory_hotplug.c | 15 +++++++++++----
1 files changed, 11 insertions(+), 4 deletions(-)
From: Yasuaki Ishimatsu <redacted>
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().
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Wen Congyang <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
---
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(-)
From: Yasuaki Ishimatsu <redacted>
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.
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Wen Congyang <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
---
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(-)
@@ -1588,6 +1588,8 @@ int vmemmap_populate(struct page *start_page, unsigned long pages, int node);voidvmemmap_populate_print_last(void);voidregister_page_bootmem_memmap(unsignedlongsection_nr,structpage*map,unsignedlongsize);+voidvmemmap_kfree(structpage*memmpa,unsignedlongnr_pages);+voidvmemmap_free_bootmem(structpage*memmpa,unsignedlongnr_pages);enummf_flags{MF_COUNT_INCREASED=1<<0,
@@ -622,12 +622,13 @@ static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,/* This will make the necessary allocations eventually. */returnsparse_mem_map_populate(pnum,nid);}-staticvoid__kfree_section_memmap(structpage*memmap,unsignedlongnr_pages)+staticvoid__kfree_section_memmap(structpage*page,unsignedlongnr_pages){-return;/* XXX: Not implemented yet */+vmemmap_kfree(page,nr_pages);}staticvoidfree_map_bootmem(structpage*page,unsignedlongnr_pages){+vmemmap_free_bootmem(page,nr_pages);}#elsestaticstructpage*__kmalloc_section_memmap(unsignedlongnr_pages)
From: Yasuaki Ishimatsu <redacted>
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.
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Wen Congyang <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
---
mm/memory_hotplug.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 181 insertions(+), 0 deletions(-)
@@ -300,10 +300,187 @@ static int __meminit __add_section(int nid, struct zone *zone,returnregister_new_memory(nid,__pfn_to_section(phys_start_pfn));}+/* find the smallest valid pfn in the range [start_pfn, end_pfn) */+staticintfind_smallest_section_pfn(unsignedlongstart_pfn,+unsignedlongend_pfn)+{+structmem_section*ms;++for(;start_pfn<end_pfn;start_pfn+=PAGES_PER_SECTION){+ms=__pfn_to_section(start_pfn);++if(unlikely(!valid_section(ms)))+continue;++returnstart_pfn;+}++return0;+}++/* find the biggest valid pfn in the range [start_pfn, end_pfn). */+staticintfind_biggest_section_pfn(unsignedlongstart_pfn,+unsignedlongend_pfn)+{+structmem_section*ms;+unsignedlongpfn;++/* 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;++returnpfn;+}++return0;+}++staticvoidshrink_zone_span(structzone*zone,unsignedlongstart_pfn,+unsignedlongend_pfn)+{+unsignedlongzone_start_pfn=zone->zone_start_pfn;+unsignedlongzone_end_pfn=zone->zone_start_pfn+zone->spanned_pages;+unsignedlongpfn;+structmem_section*ms;++zone_span_writelock(zone);+if(zone_start_pfn==start_pfn){+/*+*Ifthesectionissmallestsectioninthezone,itneed+*shrinkzone->zone_start_pfnandzone->zone_spanned_pages.+*Inthiscase,wefindsecondsmallestvalidmem_section+*forshrinkingzone.+*/+pfn=find_smallest_section_pfn(end_pfn,zone_end_pfn);+if(pfn){+zone->zone_start_pfn=pfn;+zone->spanned_pages=zone_end_pfn-pfn;+}+}elseif(zone_end_pfn==end_pfn){+/*+*Ifthesectionisbiggestsectioninthezone,itneed+*shrinkzone->spanned_pages.+*Inthiscase,wefindsecondbiggestvalidmem_sectionfor+*shrinkingzone.+*/+pfn=find_biggest_section_pfn(zone_start_pfn,start_pfn);+if(pfn)+zone->spanned_pages=pfn-zone_start_pfn+1;+}++/*+*Thesectionisnotbiggestorsmallestmem_sectioninthezone,it+*onlycreatesaholeinthezone.Sointhiscase,weneednot+*changethezone.Butperhaps,thezonehasonlyholedata.Thus+*itcheckthezonehasonlyholeornot.+*/+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);+}++staticvoidshrink_pgdat_span(structpglist_data*pgdat,+unsignedlongstart_pfn,unsignedlongend_pfn)+{+unsignedlongpgdat_start_pfn=pgdat->node_start_pfn;+unsignedlongpgdat_end_pfn=+pgdat->node_start_pfn+pgdat->node_spanned_pages;+unsignedlongpfn;+structmem_section*ms;++if(pgdat_start_pfn==start_pfn){+/*+*Ifthesectionissmallestsectioninthepgdat,itneed+*shrinkpgdat->node_start_pfnandpgdat->node_spanned_pages.+*Inthiscase,wefindsecondsmallestvalidmem_section+*forshrinkingzone.+*/+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;+}+}elseif(pgdat_end_pfn==end_pfn){+/*+*Ifthesectionisbiggestsectioninthepgdat,itneed+*shrinkpgdat->node_spanned_pages.+*Inthiscase,wefindsecondbiggestvalidmem_sectionfor+*shrinkingzone.+*/+pfn=find_biggest_section_pfn(pgdat_start_pfn,start_pfn);+if(pfn)+pgdat->node_spanned_pages=pfn-pgdat_start_pfn+1;+}++/*+*Ifthesectionisnotbiggestorsmallestmem_sectioninthepgdat,+*itonlycreatesaholeinthepgdat.Sointhiscase,weneednot+*changethepgdat.+*Butperhaps,thepgdathasonlyholedata.Thusitcheckthepgdat+*hasonlyholeornot.+*/+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;+}++staticvoid__remove_zone(structzone*zone,unsignedlongstart_pfn)+{+structpglist_data*pgdat=zone->zone_pgdat;+intnr_pages=PAGES_PER_SECTION;+intzone_type;+unsignedlongflags;++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);+}+staticint__remove_section(structzone*zone,structmem_section*ms){unsignedlongflags;structpglist_data*pgdat=zone->zone_pgdat;+unsignedlongstart_pfn;+intscn_nr;intret=-EINVAL;if(!valid_section(ms))
@@ -313,6 +490,10 @@ static int __remove_section(struct zone *zone, struct mem_section *ms)if(ret)returnret;+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);
From: Yasuaki Ishimatsu <redacted>
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()
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
Signed-off-by: Wen Congyang <redacted>
---
drivers/base/node.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
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.
Thank you for merging patches. I'll review next Monday.
Thanks,
Yasuaki Ishimatsu
[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(-)
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
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.
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
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.
Hmm, if the node contains cpu, and the cpu is onlined, can we offline
this node?
Thanks
Wen Congyang
On Fri, Jul 27, 2012 at 06:32:15PM +0800, Wen Congyang wrote:
We 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).
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.
On Fri, Jul 27, 2012 at 06:32:15PM +0800, Wen Congyang wrote:
quoted
We 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).
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
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Yasuaki Ishimatsu <redacted>
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.
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
On Fri, Jul 27, 2012 at 06:32:15PM +0800, Wen Congyang wrote:
quoted
We 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).
=20
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.
=20
Thanks for providing this information.
=20
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
=E2=80=98arch_remove_memory=E2=80=99 include/linux/memory_hotplug.h:88: err=
or: previous
declaration of =E2=80=98arch_remove_memory=E2=80=99 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)
On Fri, Jul 27, 2012 at 06:32:15PM +0800, Wen Congyang wrote:
quoted
We don't call =5F=5Fadd=5Fpages() directly in the function add=5Fmemor=
y()
quoted
quoted
quoted
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.
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
and also other architectures (u64 vs. unsigned long).
=20
arch/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
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=
);
=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
We 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).
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Yasuaki Ishimatsu <redacted>
Signed-off-by: Wen Congyang <redacted>
---
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(-)
@@ -85,6 +85,7 @@ extern void __online_page_free(struct page *page);#ifdef CONFIG_MEMORY_HOTREMOVEexternboolis_pageblock_removable_nolock(structpage*page);+externintarch_remove_memory(unsignedlongstart,unsignedlongsize);#endif /* CONFIG_MEMORY_HOTREMOVE *//* reasonably generic interface to expand the physical pages in a zone */
line 1071? which version does this patch base on? thanks a lot.
/* 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 majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
We 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).
CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <redacted>
CC: Len Brown <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Christoph Lameter <redacted>
Cc: Minchan Kim <redacted>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <redacted>
CC: Yasuaki Ishimatsu <redacted>
Signed-off-by: Wen Congyang <redacted>
---
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(-)
@@ -688,6 +688,22 @@ int arch_add_memory(int nid, u64 start, u64 size)returnret;}++#ifdef CONFIG_MEMORY_HOTREMOVE+intarch_remove_memory(u64start,u64size)+{+unsignedlongstart_pfn=start>>PAGE_SHIFT;+unsignedlongnr_pages=size>>PAGE_SHIFT;+intret;++ret=__remove_pages(start_pfn,nr_pages);+if(ret)+pr_warn("%s: Problem encountered in __remove_pages() as"+" ret=%d\n",__func__,ret);++returnret;+}+#endif#endif
in 3.5 ia64 implementation did not call __remove_pages at 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
@@ -85,6 +85,7 @@ extern void __online_page_free(struct page *page);#ifdef CONFIG_MEMORY_HOTREMOVEexternboolis_pageblock_removable_nolock(structpage*page);+externintarch_remove_memory(unsignedlongstart,unsignedlongsize);#endif /* CONFIG_MEMORY_HOTREMOVE *//* reasonably generic interface to expand the physical pages in a zone */
line 1071? which version does this patch base on? thanks a lot.
quoted
/* 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 majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Yasuaki Ishimatsu <redacted>
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.
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