Here is the physical memory hot-remove patch-set based on 3.8rc-2.
This patch-set aims to implement physical memory hot-removing.
The patches can free/remove the following things:
- /sys/firmware/memmap/X/{end, start, type} : [PATCH 4/15]
- memmap of sparse-vmemmap : [PATCH 6,7,8,10/15]
- page table of removed memory : [RFC PATCH 7,8,10/15]
- node and related sysfs files : [RFC PATCH 13-15/15]
Existing problem:
If CONFIG_MEMCG is selected, we will allocate memory to store page cgroup
when we online pages.
For example: there is a memory device on node 1. The address range
is [1G, 1.5G). You will find 4 new directories memory8, memory9, memory10,
and memory11 under the directory /sys/devices/system/memory/.
If CONFIG_MEMCG is selected, when we online memory8, the memory stored page
cgroup is not provided by this memory device. But when we online memory9, the
memory stored page cgroup may be provided by memory8. So we can't offline
memory8 now. We should offline the memory in the reversed order.
When the memory device is hotremoved, we will auto offline memory provided
by this memory device. But we don't know which memory is onlined first, so
offlining memory may fail.
In patch1, we provide a solution which is not good enough:
Iterate twice to offline the memory.
1st iterate: offline every non primary memory block.
2nd iterate: offline primary (i.e. first added) memory block.
And a new idea from Wen Congyang [off-list ref] is:
allocate the memory from the memory block they are describing.
But we are not sure if it is OK to do so because there is not existing API
to do so, and we need to move page_cgroup memory allocation from MEM_GOING_ONLINE
to MEM_ONLINE. And also, it may interfere the hugepage.
How to test this patchset?
1. apply this patchset and build the kernel. MEMORY_HOTPLUG, MEMORY_HOTREMOVE,
ACPI_HOTPLUG_MEMORY must be selected.
2. load the module acpi_memhotplug
3. hotplug the memory device(it depends on your hardware)
You will see the memory device under the directory /sys/bus/acpi/devices/.
Its name is PNP0C80:XX.
4. online/offline pages provided by this memory device
You can write online/offline to /sys/devices/system/memory/memoryX/state to
online/offline pages provided by this memory device
5. hotremove the memory device
You can hotremove the memory device by the hardware, or writing 1 to
/sys/bus/acpi/devices/PNP0C80:XX/eject.
Note: if the memory provided by the memory device is used by the kernel, it
can't be offlined. It is not a bug.
Changelogs from v5 to v6:
Patch3: Add some more comments to explain memory hot-remove.
Patch4: Remove bootmem member in struct firmware_map_entry.
Patch6: Repeatedly register bootmem pages when using hugepage.
Patch8: Repeatedly free bootmem pages when using hugepage.
Patch14: Don't free pgdat when offlining a node, just reset it to 0.
Patch15: New patch, pgdat is not freed in patch14, so don't allocate a new
one when online a node.
Changelogs from v4 to v5:
Patch7: new patch, move pgdat_resize_lock into sparse_remove_one_section() to
avoid disabling irq because we need flush tlb when free pagetables.
Patch8: new patch, pick up some common APIs that are used to free direct mapping
and vmemmap pagetables.
Patch9: free direct mapping pagetables on x86_64 arch.
Patch10: free vmemmap pagetables.
Patch11: since freeing memmap with vmemmap has been implemented, the config
macro CONFIG_SPARSEMEM_VMEMMAP when defining __remove_section() is
no longer needed.
Patch13: no need to modify acpi_memory_disable_device() since it was removed,
and add nid parameter when calling remove_memory().
Changelogs from v3 to v4:
Patch7: remove unused codes.
Patch8: fix nr_pages that is passed to free_map_bootmem()
Changelogs from v2 to v3:
Patch9: call sync_global_pgds() if pgd is changed
Patch10: fix a problem int the patch
Changelogs from v1 to v2:
Patch1: new patch, offline memory twice. 1st iterate: offline every non primary
memory block. 2nd iterate: offline primary (i.e. first added) memory
block.
Patch3: new patch, no logical change, just remove reduntant codes.
Patch9: merge the patch from wujianguo into this patch. flush tlb on all cpu
after the pagetable is changed.
Patch12: new patch, free node_data when a node is offlined.
Tang Chen (6):
memory-hotplug: move pgdat_resize_lock into
sparse_remove_one_section()
memory-hotplug: remove page table of x86_64 architecture
memory-hotplug: remove memmap of sparse-vmemmap
memory-hotplug: Integrated __remove_section() of
CONFIG_SPARSEMEM_VMEMMAP.
memory-hotplug: remove sysfs file of node
memory-hotplug: Do not allocate pdgat if it was not freed when
offline.
Wen Congyang (5):
memory-hotplug: try to offline the memory twice to avoid dependence
memory-hotplug: remove redundant codes
memory-hotplug: introduce new function arch_remove_memory() for
removing page table depends on architecture
memory-hotplug: Common APIs to support page tables hot-remove
memory-hotplug: free node_data when a node is offlined
Yasuaki Ishimatsu (4):
memory-hotplug: check whether all memory blocks are offlined or not
when removing memory
memory-hotplug: remove /sys/firmware/memmap/X sysfs
memory-hotplug: implement register_page_bootmem_info_section of
sparse-vmemmap
memory-hotplug: memory_hotplug: clear zone when removing the memory
arch/arm64/mm/mmu.c | 3 +
arch/ia64/mm/discontig.c | 10 +
arch/ia64/mm/init.c | 18 ++
arch/powerpc/mm/init_64.c | 10 +
arch/powerpc/mm/mem.c | 12 +
arch/s390/mm/init.c | 12 +
arch/s390/mm/vmem.c | 10 +
arch/sh/mm/init.c | 17 ++
arch/sparc/mm/init_64.c | 10 +
arch/tile/mm/init.c | 8 +
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_32.c | 12 +
arch/x86/mm/init_64.c | 390 +++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 ++--
drivers/acpi/acpi_memhotplug.c | 8 +-
drivers/base/memory.c | 6 +
drivers/firmware/memmap.c | 96 +++++++-
include/linux/bootmem.h | 1 +
include/linux/firmware-map.h | 6 +
include/linux/memory_hotplug.h | 15 +-
include/linux/mm.h | 4 +-
mm/memory_hotplug.c | 459 +++++++++++++++++++++++++++++++---
mm/sparse.c | 8 +-
23 files changed, 1094 insertions(+), 69 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 which is allocated by bootmem.
So the patch makes memory leak. But I think the memory leak size is
very samll. And it does not affect the system.
Signed-off-by: Wen Congyang <redacted>
Signed-off-by: Yasuaki Ishimatsu <redacted>
Signed-off-by: Tang Chen <redacted>
Reviewed-by: Kamezawa Hiroyuki <redacted>
---
drivers/firmware/memmap.c | 96 +++++++++++++++++++++++++++++++++++++++++-
include/linux/firmware-map.h | 6 +++
mm/memory_hotplug.c | 5 ++-
3 files changed, 104 insertions(+), 3 deletions(-)
@@ -79,7 +80,26 @@ static const struct sysfs_ops memmap_attr_ops = {.show=memmap_attr_show,};++staticinlinestructfirmware_map_entry*+to_memmap_entry(structkobject*kobj)+{+returncontainer_of(kobj,structfirmware_map_entry,kobj);+}++staticvoidrelease_firmware_map_entry(structkobject*kobj)+{+structfirmware_map_entry*entry=to_memmap_entry(kobj);++if(PageReserved(virt_to_page(entry)))+/* There is no way to free memory allocated from bootmem */+return;++kfree(entry);+}+staticstructkobj_typememmap_ktype={+.release=release_firmware_map_entry,.sysfs_ops=&memmap_attr_ops,.default_attrs=def_attrs,};
From: Wen Congyang <redacted>
For removing memory, we need to remove page table. But it depends
on architecture. So the patch introduce arch_remove_memory() for
removing page table. Now it only calls __remove_pages().
Note: __remove_pages() for some archtecuture is not implemented
(I don't know how to implement it for s390).
Signed-off-by: Wen Congyang <redacted>
Acked-by: KAMEZAWA Hiroyuki <redacted>
---
arch/ia64/mm/init.c | 18 ++++++++++++++++++
arch/powerpc/mm/mem.c | 12 ++++++++++++
arch/s390/mm/init.c | 12 ++++++++++++
arch/sh/mm/init.c | 17 +++++++++++++++++
arch/tile/mm/init.c | 8 ++++++++
arch/x86/mm/init_32.c | 12 ++++++++++++
arch/x86/mm/init_64.c | 15 +++++++++++++++
include/linux/memory_hotplug.h | 1 +
mm/memory_hotplug.c | 2 ++
9 files changed, 97 insertions(+), 0 deletions(-)
@@ -96,6 +96,7 @@ extern void __online_page_free(struct page *page);#ifdef CONFIG_MEMORY_HOTREMOVEexternboolis_pageblock_removable_nolock(structpage*page);+externintarch_remove_memory(u64start,u64size);#endif /* CONFIG_MEMORY_HOTREMOVE *//* reasonably generic interface to expand the physical pages in a zone */
From: Wen Congyang <redacted>
We call hotadd_new_pgdat() to allocate memory to store node_data. So we
should free it when removing a node.
Signed-off-by: Wen Congyang <redacted>
Reviewed-by: Kamezawa Hiroyuki <redacted>
---
mm/memory_hotplug.c | 30 +++++++++++++++++++++++++++---
1 files changed, 27 insertions(+), 3 deletions(-)
@@ -1699,9 +1699,12 @@ static int check_cpu_on_node(void *data)/* offline the node if all memory sections of this node are removed */staticvoidtry_offline_node(intnid){-unsignedlongstart_pfn=NODE_DATA(nid)->node_start_pfn;-unsignedlongend_pfn=start_pfn+NODE_DATA(nid)->node_spanned_pages;+pg_data_t*pgdat=NODE_DATA(nid);+unsignedlongstart_pfn=pgdat->node_start_pfn;+unsignedlongend_pfn=start_pfn+pgdat->node_spanned_pages;unsignedlongpfn;+structpage*pgdat_page=virt_to_page(pgdat);+inti;for(pfn=start_pfn;pfn<end_pfn;pfn+=PAGES_PER_SECTION){unsignedlongsection_nr=pfn_to_section_nr(pfn);
@@ -1728,6 +1731,27 @@ static void try_offline_node(int nid)*/node_set_offline(nid);unregister_one_node(nid);++if(!PageSlab(pgdat_page)&&!PageCompound(pgdat_page))+/* node data is allocated from boot memory */+return;++/* free waittable in each zone */+for(i=0;i<MAX_NR_ZONES;i++){+structzone*zone=pgdat->node_zones+i;++if(zone->wait_table)+vfree(zone->wait_table);+}++/*+*Sincethereisnowaytoguarenteetheaddressofpgdat/zoneisnot+*onstackofanykernelthreadsorusedbyotherkernelobjects+*withoutreferencecountingorothersymchronizingmethod,donot+*resetnode_dataandfreepgdathere.Justresetitto0andreuse+*thememorywhenthenodeisonlineagain.+*/+memset(pgdat,0,sizeof(*pgdat));}int__refremove_memory(intnid,u64start,u64size)
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 them
when the memory is removed.
The patch adds a new function __remove_zone() to do this.
Signed-off-by: Yasuaki Ishimatsu <redacted>
Signed-off-by: Wen Congyang <redacted>
---
mm/memory_hotplug.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 207 insertions(+), 0 deletions(-)
@@ -430,8 +430,211 @@ 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(intnid,structzone*zone,+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;++if(unlikely(pfn_to_nid(start_pfn)!=nid))+continue;++if(zone&&zone!=page_zone(pfn_to_page(start_pfn)))+continue;++returnstart_pfn;+}++return0;+}++/* find the biggest valid pfn in the range [start_pfn, end_pfn). */+staticintfind_biggest_section_pfn(intnid,structzone*zone,+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;++if(unlikely(pfn_to_nid(pfn)!=nid))+continue;++if(zone&&zone!=page_zone(pfn_to_page(pfn)))+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;+intnid=zone_to_nid(zone);++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(nid,zone,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(nid,zone,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(page_zone(pfn_to_page(pfn))!=zone)+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;+intnid=pgdat->node_id;++if(pgdat_start_pfn==start_pfn){+/*+*Ifthesectionissmallestsectioninthepgdat,itneed+*shrinkpgdat->node_start_pfnandpgdat->node_spanned_pages.+*Inthiscase,wefindsecondsmallestvalidmem_section+*forshrinkingzone.+*/+pfn=find_smallest_section_pfn(nid,NULL,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(nid,NULL,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(pfn_to_nid(pfn)!=nid)+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){+unsignedlongstart_pfn;+intscn_nr;intret=-EINVAL;if(!valid_section(ms))
@@ -441,6 +644,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);+sparse_remove_one_section(zone,ms);return0;}
This patch introduces a new API vmemmap_free() to free and remove
vmemmap pagetables. Since pagetable implements are different, each
architecture has to provide its own version of vmemmap_free(), just
like vmemmap_populate().
Note: vmemmap_free() are not implemented for ia64, ppc, s390, and sparc.
Signed-off-by: Yasuaki Ishimatsu <redacted>
Signed-off-by: Jianguo Wu <redacted>
Signed-off-by: Wen Congyang <redacted>
Signed-off-by: Tang Chen <redacted>
---
arch/arm64/mm/mmu.c | 3 +++
arch/ia64/mm/discontig.c | 4 ++++
arch/powerpc/mm/init_64.c | 4 ++++
arch/s390/mm/vmem.c | 4 ++++
arch/sparc/mm/init_64.c | 4 ++++
arch/x86/mm/init_64.c | 8 ++++++++
include/linux/mm.h | 1 +
mm/sparse.c | 3 ++-
8 files changed, 30 insertions(+), 1 deletions(-)
This patch introduces a new function try_offline_node() to
remove sysfs file of node when all memory sections of this
node are removed. If some memory sections of this node are
not removed, this function does nothing.
Signed-off-by: Wen Congyang <redacted>
Signed-off-by: Tang Chen <redacted>
---
drivers/acpi/acpi_memhotplug.c | 8 ++++-
include/linux/memory_hotplug.h | 2 +-
mm/memory_hotplug.c | 58 ++++++++++++++++++++++++++++++++++++++-
3 files changed, 63 insertions(+), 5 deletions(-)
@@ -295,9 +295,11 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)staticintacpi_memory_remove_memory(structacpi_memory_device*mem_device){-intresult=0;+intresult=0,nid;structacpi_memory_info*info,*n;+nid=acpi_get_node(mem_device->device->handle);+list_for_each_entry_safe(info,n,&mem_device->res_list,list){if(info->failed)/* The kernel does not use this memory block */
@@ -310,7 +312,9 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)*/return-EBUSY;-result=remove_memory(info->start_addr,info->length);+if(nid<0)+nid=memory_add_physaddr_to_nid(info->start_addr);+result=remove_memory(nid,info->start_addr,info->length);if(result)returnresult;
@@ -1678,7 +1679,58 @@ static int is_memblock_offlined_cb(struct memory_block *mem, void *arg)returnret;}-int__refremove_memory(u64start,u64size)+staticintcheck_cpu_on_node(void*data)+{+structpglist_data*pgdat=data;+intcpu;++for_each_present_cpu(cpu){+if(cpu_to_node(cpu)==pgdat->node_id)+/*+*thecpuonthisnodeisn'tremoved,andwecan't+*offlinethisnode.+*/+return-EBUSY;+}++return0;+}++/* offline the node if all memory sections of this node are removed */+staticvoidtry_offline_node(intnid)+{+unsignedlongstart_pfn=NODE_DATA(nid)->node_start_pfn;+unsignedlongend_pfn=start_pfn+NODE_DATA(nid)->node_spanned_pages;+unsignedlongpfn;++for(pfn=start_pfn;pfn<end_pfn;pfn+=PAGES_PER_SECTION){+unsignedlongsection_nr=pfn_to_section_nr(pfn);++if(!present_section_nr(section_nr))+continue;++if(pfn_to_nid(pfn)!=nid)+continue;++/*+*somememorysectionsofthisnodearenotremoved,andwe+*can'tofflinenodenow.+*/+return;+}++if(stop_machine(check_cpu_on_node,NODE_DATA(nid),NULL))+return;++/*+*allmemory/cpuofthisnodeareremoved,wecanofflinethis+*nodenow.+*/+node_set_offline(nid);+unregister_one_node(nid);+}++int__refremove_memory(intnid,u64start,u64size){unsignedlongstart_pfn,end_pfn;intret=0;
@@ -1742,7 +1796,7 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages){return-EINVAL;}-intremove_memory(u64start,u64size)+intremove_memory(intnid,u64start,u64size){return-EINVAL;}
@@ -693,6 +693,12 @@ int offline_memory_block(struct memory_block *mem)returnret;}+/* return true if the memory block is offlined, otherwise, return false */+boolis_memblock_offlined(structmemory_block*mem)+{+returnmem->state==MEM_OFFLINE;+}+/**Initializethesysfssupportformemorydevices...*/
@@ -1430,6 +1430,54 @@ repeat:gotorepeat;}+lock_memory_hotplug();++/*+*wehaveofflinedallmemoryblockslikethis:+*1.lockmemoryhotplug+*2.offlineamemoryblock+*3.unlockmemoryhotplug+*+*repeatstep1-3toofflinethememoryblock.Allmemoryblocks+*mustbeofflinedbeforeremovingmemory.Butwedon'tholdthe+*lockinthewholeoperation.Soweshouldcheckwhetherall+*memoryblocksareofflined.+*/++mem=NULL;+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=is_memblock_offlined(mem);+if(!ret){+pr_warn("removing memory fails, because memory "+"[%#010llx-%#010llx] is onlined\n",+PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)),+PFN_PHYS(section_nr_to_pfn(mem->end_section_nr+1))-1);++kobject_put(&mem->dev.kobj);+unlock_memory_hotplug();+returnret;+}+}++if(mem)+kobject_put(&mem->dev.kobj);+unlock_memory_hotplug();+return0;}#else
From: Wen Congyang <redacted>
When memory is removed, the corresponding pagetables should alse be removed.
This patch introduces some common APIs to support vmemmap pagetable and x86_64
architecture pagetable removing.
All pages of virtual mapping in removed memory cannot be freedi if some pages
used as PGD/PUD includes not only removed memory but also other memory. So the
patch uses the following way 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.
Signed-off-by: Yasuaki Ishimatsu <redacted>
Signed-off-by: Jianguo Wu <redacted>
Signed-off-by: Wen Congyang <redacted>
Signed-off-by: Tang Chen <redacted>
---
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_64.c | 299 ++++++++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 +++---
include/linux/bootmem.h | 1 +
4 files changed, 326 insertions(+), 22 deletions(-)
@@ -682,6 +682,305 @@ int arch_add_memory(int nid, u64 start, u64 size)}EXPORT_SYMBOL_GPL(arch_add_memory);+#define PAGE_INUSE 0xFD++staticvoid__meminitfree_pagetable(structpage*page,intorder)+{+structzone*zone;+boolbootmem=false;+unsignedlongmagic;+unsignedintnr_pages=1<<order;++/* bootmem page has reserved flag */+if(PageReserved(page)){+__ClearPageReserved(page);+bootmem=true;++magic=(unsignedlong)page->lru.next;+if(magic==SECTION_INFO||magic==MIX_SECTION_INFO){+while(nr_pages--)+put_page_bootmem(page++);+}else+__free_pages_bootmem(page,order);+}else+free_pages((unsignedlong)page_address(page),order);++/*+*SECTION_INFOpagesandMIX_SECTION_INFOpages+*areallallocatedbybootmem.+*/+if(bootmem){+zone=page_zone(page);+zone_span_writelock(zone);+zone->present_pages+=nr_pages;+zone_span_writeunlock(zone);+totalram_pages+=nr_pages;+}+}++staticvoid__meminitfree_pte_table(pte_t*pte_start,pmd_t*pmd)+{+pte_t*pte;+inti;++for(i=0;i<PTRS_PER_PTE;i++){+pte=pte_start+i;+if(pte_val(*pte))+return;+}++/* free a pte talbe */+free_pagetable(pmd_page(*pmd),0);+spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+}++staticvoid__meminitfree_pmd_table(pmd_t*pmd_start,pud_t*pud)+{+pmd_t*pmd;+inti;++for(i=0;i<PTRS_PER_PMD;i++){+pmd=pmd_start+i;+if(pmd_val(*pmd))+return;+}++/* free a pmd talbe */+free_pagetable(pud_page(*pud),0);+spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+}++/* Return true if pgd is changed, otherwise return false. */+staticbool__meminitfree_pud_table(pud_t*pud_start,pgd_t*pgd)+{+pud_t*pud;+inti;++for(i=0;i<PTRS_PER_PUD;i++){+pud=pud_start+i;+if(pud_val(*pud))+returnfalse;+}++/* free a pud table */+free_pagetable(pgd_page(*pgd),0);+spin_lock(&init_mm.page_table_lock);+pgd_clear(pgd);+spin_unlock(&init_mm.page_table_lock);++returntrue;+}++staticvoid__meminit+remove_pte_table(pte_t*pte_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongnext,pages=0;+pte_t*pte;+void*page_addr;+phys_addr_tphys_addr;++pte=pte_start+pte_index(addr);+for(;addr<end;addr=next,pte++){+next=(addr+PAGE_SIZE)&PAGE_MASK;+if(next>end)+next=end;++if(!pte_present(*pte))+continue;++/*+*Wemapped[0,1G)memoryasidentitymappingwhen+*initializing,inarch/x86/kernel/head_64.S.These+*pagetablescannotberemoved.+*/+phys_addr=pte_val(*pte)+(addr&PAGE_MASK);+if(phys_addr<(phys_addr_t)0x40000000)+return;++if(IS_ALIGNED(addr,PAGE_SIZE)&&+IS_ALIGNED(next,PAGE_SIZE)){+if(!direct){+free_pagetable(pte_page(*pte),0);+pages++;+}++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}else{+/*+*Ifwearenotremovingthewholepage,itmeans+*otherptesinthispagearebeingusedandwecanot+*removethem.Sofilltheunusedpteswith0xFD,and+*removethepagewhenitiswhollyfilledwith0xFD.+*/+memset((void*)addr,PAGE_INUSE,next-addr);+page_addr=page_address(pte_page(*pte));++if(!memchr_inv(page_addr,PAGE_INUSE,PAGE_SIZE)){+free_pagetable(pte_page(*pte),0);+pages++;++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}+}+}++/* Call free_pte_table() in remove_pmd_table(). */+flush_tlb_all();+if(direct)+update_page_count(PG_LEVEL_4K,-pages);+}++staticvoid__meminit+remove_pmd_table(pmd_t*pmd_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpte_phys,next,pages=0;+pte_t*pte_base;+pmd_t*pmd;++pmd=pmd_start+pmd_index(addr);+for(;addr<end;addr=next,pmd++){+next=pmd_addr_end(addr,end);++if(!pmd_present(*pmd))+continue;++if(pmd_large(*pmd)){+if(IS_ALIGNED(addr,PMD_SIZE)&&+IS_ALIGNED(next,PMD_SIZE)){+if(!direct){+free_pagetable(pmd_page(*pmd),+get_order(PMD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse2Mpage,butweneedtoremovepartofthem,+*sosplit2Mpageto4Kpage.+*/+pte_base=(pte_t*)alloc_low_page(&pte_phys);+BUG_ON(!pte_base);+__split_large_page((pte_t*)pmd,addr,+(pte_t*)pte_base);++spin_lock(&init_mm.page_table_lock);+pmd_populate_kernel(&init_mm,pmd,__va(pte_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pte_base=(pte_t*)map_low_page((pte_t*)pmd_page_vaddr(*pmd));+remove_pte_table(pte_base,addr,next,direct);+free_pte_table(pte_base,pmd);+unmap_low_page(pte_base);+}++/* Call free_pmd_table() in remove_pud_table(). */+if(direct)+update_page_count(PG_LEVEL_2M,-pages);+}++staticvoid__meminit+remove_pud_table(pud_t*pud_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpmd_phys,next,pages=0;+pmd_t*pmd_base;+pud_t*pud;++pud=pud_start+pud_index(addr);+for(;addr<end;addr=next,pud++){+next=pud_addr_end(addr,end);++if(!pud_present(*pud))+continue;++if(pud_large(*pud)){+if(IS_ALIGNED(addr,PUD_SIZE)&&+IS_ALIGNED(next,PUD_SIZE)){+if(!direct){+free_pagetable(pud_page(*pud),+get_order(PUD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse1Gpage,butweneedtoremovepartofthem,+*sosplit1Gpageto2Mpage.+*/+pmd_base=(pmd_t*)alloc_low_page(&pmd_phys);+BUG_ON(!pmd_base);+__split_large_page((pte_t*)pud,addr,+(pte_t*)pmd_base);++spin_lock(&init_mm.page_table_lock);+pud_populate(&init_mm,pud,__va(pmd_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pmd_base=(pmd_t*)map_low_page((pmd_t*)pud_page_vaddr(*pud));+remove_pmd_table(pmd_base,addr,next,direct);+free_pmd_table(pmd_base,pud);+unmap_low_page(pmd_base);+}++if(direct)+update_page_count(PG_LEVEL_1G,-pages);+}++/* start and end are both virtual address. */+staticvoid__meminit+remove_pagetable(unsignedlongstart,unsignedlongend,booldirect)+{+unsignedlongnext;+pgd_t*pgd;+pud_t*pud;+boolpgd_changed=false;++for(;start<end;start=next){+pgd=pgd_offset_k(start);+if(!pgd_present(*pgd))+continue;++next=pgd_addr_end(start,end);++pud=(pud_t*)map_low_page((pud_t*)pgd_page_vaddr(*pgd));+remove_pud_table(pud,start,next,direct);+if(free_pud_table(pud,pgd))+pgd_changed=true;+unmap_low_page(pud);+}++if(pgd_changed)+sync_global_pgds(start,end-1);++flush_tlb_all();+}+#ifdef CONFIG_MEMORY_HOTREMOVEint__refarch_remove_memory(u64start,u64size){
@@ -1381,20 +1381,26 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)return__offline_pages(start_pfn,start_pfn+nr_pages,120*HZ);}-intremove_memory(u64start,u64size)+/**+*walk_memory_range-walksthroughallmemsectionsin[start_pfn,end_pfn)+*@start_pfn:startpfnofthememoryrange+*@end_pfn:endpftofthememoryrange+*@arg:argumentpassedtofunc+*@func:callbackforeachmemorysectionwalked+*+*Thisfunctionwalksthroughallpresentmemsectionsinrange+*[start_pfn,end_pfn)andcallfunconeachmemsection.+*+*Returnsthereturnvalueoffunc.+*/+staticintwalk_memory_range(unsignedlongstart_pfn,unsignedlongend_pfn,+void*arg,int(*func)(structmemory_block*,void*)){structmemory_block*mem=NULL;structmem_section*section;-unsignedlongstart_pfn,end_pfn;unsignedlongpfn,section_nr;intret;-intreturn_on_error=0;-intretry=0;--start_pfn=PFN_DOWN(start);-end_pfn=start_pfn+PFN_DOWN(size);-repeat:for(pfn=start_pfn;pfn<end_pfn;pfn+=PAGES_PER_SECTION){section_nr=pfn_to_section_nr(pfn);if(!present_section_nr(section_nr))
@@ -1411,22 +1417,76 @@ repeat:if(!mem)continue;-ret=offline_memory_block(mem);+ret=func(mem,arg);if(ret){-if(return_on_error){-kobject_put(&mem->dev.kobj);-returnret;-}else{-retry=1;-}+kobject_put(&mem->dev.kobj);+returnret;}}if(mem)kobject_put(&mem->dev.kobj);-if(retry){-return_on_error=1;+return0;+}++/**+*offline_memory_block_cb-callbackfunctionforoffliningmemoryblock+*@mem:thememoryblocktobeofflined+*@arg:buffertoholderrormsg+*+*Alwaysreturn0,andputtheerrormsginargifany.+*/+staticintoffline_memory_block_cb(structmemory_block*mem,void*arg)+{+int*ret=arg;+interror=offline_memory_block(mem);++if(error!=0&&*ret==0)+*ret=error;++return0;+}++staticintis_memblock_offlined_cb(structmemory_block*mem,void*arg)+{+intret=!is_memblock_offlined(mem);++if(unlikely(ret))+pr_warn("removing memory fails, because memory "+"[%#010llx-%#010llx] is onlined\n",+PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)),+PFN_PHYS(section_nr_to_pfn(mem->end_section_nr+1))-1);++returnret;+}++intremove_memory(u64start,u64size)+{+unsignedlongstart_pfn,end_pfn;+intret=0;+intretry=1;++start_pfn=PFN_DOWN(start);+end_pfn=start_pfn+PFN_DOWN(size);++/*+*WhenCONFIG_MEMCGison,onememoryblockmaybeusedbyother+*blockstostorepagecgroupwhenonliningpages.Butwedon'tknow+*inwhatorderpagesareonlined.Soweiteratetwicetooffline+*memory:+*1stiterate:offlineeverynonprimarymemoryblock.+*2nditerate:offlineprimary(i.e.firstadded)memoryblock.+*/+repeat:+walk_memory_range(start_pfn,end_pfn,&ret,+offline_memory_block_cb);+if(ret){+if(!retry)+returnret;++retry=0;+ret=0;gotorepeat;}
@@ -1444,38 +1504,13 @@ repeat:*memoryblocksareofflined.*/-mem=NULL;-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=is_memblock_offlined(mem);-if(!ret){-pr_warn("removing memory fails, because memory "-"[%#010llx-%#010llx] is onlined\n",-PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)),-PFN_PHYS(section_nr_to_pfn(mem->end_section_nr+1))-1);--kobject_put(&mem->dev.kobj);-unlock_memory_hotplug();-returnret;-}+ret=walk_memory_range(start_pfn,end_pfn,NULL,+is_memblock_offlined_cb);+if(ret){+unlock_memory_hotplug();+returnret;}-if(mem)-kobject_put(&mem->dev.kobj);unlock_memory_hotplug();return0;
From: Wen Congyang <redacted>
memory can't be offlined when CONFIG_MEMCG is selected.
For example: there is a memory device on node 1. The address range
is [1G, 1.5G). You will find 4 new directories memory8, memory9, memory10,
and memory11 under the directory /sys/devices/system/memory/.
If CONFIG_MEMCG is selected, we will allocate memory to store page cgroup
when we online pages. When we online memory8, the memory stored page cgroup
is not provided by this memory device. But when we online memory9, the memory
stored page cgroup may be provided by memory8. So we can't offline memory8
now. We should offline the memory in the reversed order.
When the memory device is hotremoved, we will auto offline memory provided
by this memory device. But we don't know which memory is onlined first, so
offlining memory may fail. In such case, iterate twice to offline the memory.
1st iterate: offline every non primary memory block.
2nd iterate: offline primary (i.e. first added) memory block.
This idea is suggested by KOSAKI Motohiro.
Signed-off-by: Wen Congyang <redacted>
---
mm/memory_hotplug.c | 16 ++++++++++++++--
1 files changed, 14 insertions(+), 2 deletions(-)
Currently __remove_section for SPARSEMEM_VMEMMAP does nothing. But even if
we use SPARSEMEM_VMEMMAP, we can unregister the memory_section.
Signed-off-by: Yasuaki Ishimatsu <redacted>
Signed-off-by: Wen Congyang <redacted>
Signed-off-by: Tang Chen <redacted>
---
mm/memory_hotplug.c | 11 -----------
1 files changed, 0 insertions(+), 11 deletions(-)
Since there is no way to guarentee the address of pgdat/zone is not
on stack of any kernel threads or used by other kernel objects
without reference counting or other symchronizing method, we cannot
reset node_data and free pgdat when offlining a node. Just reset pgdat
to 0 and reuse the memory when the node is online again.
The problem is suggested by Kamezawa Hiroyuki [off-list ref]
The idea is from Wen Congyang [off-list ref]
NOTE: If we don't reset pgdat to 0, the WARN_ON in free_area_init_node()
will be triggered.
Signed-off-by: Tang Chen <redacted>
Reviewed-by: Wen Congyang <redacted>
---
mm/memory_hotplug.c | 20 ++++++++++++--------
1 files changed, 12 insertions(+), 8 deletions(-)
@@ -1015,11 +1015,14 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)unsignedlongzholes_size[MAX_NR_ZONES]={0};unsignedlongstart_pfn=start>>PAGE_SHIFT;-pgdat=arch_alloc_nodedata(nid);-if(!pgdat)-returnNULL;+pgdat=NODE_DATA(nid);+if(!pgdat){+pgdat=arch_alloc_nodedata(nid);+if(!pgdat)+returnNULL;-arch_refresh_nodedata(nid,pgdat);+arch_refresh_nodedata(nid,pgdat);+}/* we can use NODE_DATA(nid) from here */
@@ -1100,7 +1104,7 @@ int __ref add_memory(int nid, u64 start, u64 size)/* we online node here. we can't roll back from here. */node_set_online(nid);-if(new_pgdat){+if(new_node){ret=register_one_node(nid);/**Ifsysfsfileofnewnodecan'tcreate,cpuonthenode
From: Andrew Morton <akpm@linux-foundation.org> Date: 2013-01-09 22:23:19
On Wed, 9 Jan 2013 17:32:24 +0800
Tang Chen [off-list ref] wrote:
Here is the physical memory hot-remove patch-set based on 3.8rc-2.
This patch-set aims to implement physical memory hot-removing.
The patches can free/remove the following things:
- /sys/firmware/memmap/X/{end, start, type} : [PATCH 4/15]
- memmap of sparse-vmemmap : [PATCH 6,7,8,10/15]
- page table of removed memory : [RFC PATCH 7,8,10/15]
- node and related sysfs files : [RFC PATCH 13-15/15]
Existing problem:
If CONFIG_MEMCG is selected, we will allocate memory to store page cgroup
when we online pages.
For example: there is a memory device on node 1. The address range
is [1G, 1.5G). You will find 4 new directories memory8, memory9, memory10,
and memory11 under the directory /sys/devices/system/memory/.
If CONFIG_MEMCG is selected, when we online memory8, the memory stored page
cgroup is not provided by this memory device. But when we online memory9, the
memory stored page cgroup may be provided by memory8. So we can't offline
memory8 now. We should offline the memory in the reversed order.
When the memory device is hotremoved, we will auto offline memory provided
by this memory device. But we don't know which memory is onlined first, so
offlining memory may fail.
This does sound like a significant problem. We should assume that
mmecg is available and in use.
In patch1, we provide a solution which is not good enough:
Iterate twice to offline the memory.
1st iterate: offline every non primary memory block.
2nd iterate: offline primary (i.e. first added) memory block.
Let's flesh this out a bit.
If we online memory8, memory9, memory10 and memory11 then I'd have
thought that they would need to offlined in reverse order, which will
require four iterations, not two. Is this wrong and if so, why?
Also, what happens if we wish to offline only memory9? Do we offline
memory11 then memory10 then memory9 and then re-online memory10 and
memory11?
And a new idea from Wen Congyang [off-list ref] is:
allocate the memory from the memory block they are describing.
Yes.
But we are not sure if it is OK to do so because there is not existing API
to do so, and we need to move page_cgroup memory allocation from MEM_GOING_ONLINE
to MEM_ONLINE.
This all sounds solvable - can we proceed in this fashion?
And also, it may interfere the hugepage.
Please provide full details on this problem.
Note: if the memory provided by the memory device is used by the kernel, it
can't be offlined. It is not a bug.
Right. But how often does this happen in testing? In other words,
please provide an overall description of how well memory hot-remove is
presently operating. Is it reliable? What is the success rate in
real-world situations? Are there precautions which the administrator
can take to improve the success rate? What are the remaining problems
and are there plans to address them?
From: Andrew Morton <akpm@linux-foundation.org> Date: 2013-01-09 22:49:10
On Wed, 9 Jan 2013 17:32:28 +0800
Tang Chen [off-list ref] wrote:
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 which is allocated by bootmem.
So the patch makes memory leak. But I think the memory leak size is
very samll. And it does not affect the system.
Well that's bad. Can we remember the address of that memory and then
reuse the storage if/when the memory is re-added? That at least puts an upper
bound on the leak.
From: Andrew Morton <akpm@linux-foundation.org> Date: 2013-01-09 22:50:35
On Wed, 9 Jan 2013 17:32:29 +0800
Tang Chen [off-list ref] wrote:
For removing memory, we need to remove page table. But it depends
on architecture. So the patch introduce arch_remove_memory() for
removing page table. Now it only calls __remove_pages().
Note: __remove_pages() for some archtecuture is not implemented
(I don't know how to implement it for s390).
From: Andrew Morton <akpm@linux-foundation.org> Date: 2013-01-09 23:11:46
On Wed, 9 Jan 2013 17:32:26 +0800
Tang Chen [off-list ref] wrote:
We remove the memory like this:
1. lock memory hotplug
2. offline a memory block
3. unlock memory hotplug
4. repeat 1-3 to offline all memory blocks
5. lock memory hotplug
6. remove memory(TODO)
7. unlock memory hotplug
All memory blocks must be offlined before removing memory. But we don't hold
the lock in the whole operation. So we should check whether all memory blocks
are offlined before step6. Otherwise, kernel maybe panicked.
Well, the obvious question is: why don't we hold lock_memory_hotplug()
for all of steps 1-4? Please send the reasons for this in a form which
I can paste into the changelog.
Actually, I wonder if doing this would fix a race in the current
remove_memory() repeat: loop. That code does a
find_memory_block_hinted() followed by offline_memory_block(), but
afaict find_memory_block_hinted() only does a get_device(). Is the
get_device() sufficiently strong to prevent problems if another thread
concurrently offlines or otherwise alters this memory_block's state?
From: Andrew Morton <akpm@linux-foundation.org> Date: 2013-01-09 23:19:25
On Wed, 9 Jan 2013 17:32:28 +0800
Tang Chen [off-list ref] wrote:
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 which is allocated by bootmem.
So the patch makes memory leak. But I think the memory leak size is
very samll. And it does not affect the system.
...
+static struct firmware_map_entry * __meminit
+firmware_map_find_entry(u64 start, u64 end, const char *type)
+{
+ struct firmware_map_entry *entry;
+
+ spin_lock(&map_entries_lock);
+ list_for_each_entry(entry, &map_entries, list)
+ if ((entry->start == start) && (entry->end == end) &&
+ (!strcmp(entry->type, type))) {
+ spin_unlock(&map_entries_lock);
+ return entry;
+ }
+
+ spin_unlock(&map_entries_lock);
+ return NULL;
+}
...
+ entry = firmware_map_find_entry(start, end - 1, type);
+ if (!entry)
+ return -EINVAL;
+
+ firmware_map_remove_entry(entry);
...
The above code looks racy. After firmware_map_find_entry() does the
spin_unlock() there is nothing to prevent a concurrent
firmware_map_remove_entry() from removing the entry, so the kernel ends
up calling firmware_map_remove_entry() twice against the same entry.
An easy fix for this is to hold the spinlock across the entire
lookup/remove operation.
This problem is inherent to firmware_map_find_entry() as you have
implemented it, so this function simply should not exist in the current
form - no caller can use it without being buggy! A simple fix for this
is to remove the spin_lock()/spin_unlock() from
firmware_map_find_entry() and add locking documentation to
firmware_map_find_entry(), explaining that the caller must hold
map_entries_lock and must not release that lock until processing of
firmware_map_find_entry()'s return value has completed.
From: Andrew Morton <akpm@linux-foundation.org> Date: 2013-01-09 23:33:28
On Wed, 9 Jan 2013 17:32:24 +0800
Tang Chen [off-list ref] wrote:
This patch-set aims to implement physical memory hot-removing.
As you were on th patch delivery path, all of these patches should have
your Signed-off-by:. But some were missing it. I fixed this in my
copy of the patches.
I suspect this patchset adds a significant amount of code which will
not be used if CONFIG_MEMORY_HOTPLUG=n. "[PATCH v6 06/15]
memory-hotplug: implement register_page_bootmem_info_section of
sparse-vmemmap", for example. This is not a good thing, so please go
through the patchset (in fact, go through all the memhotplug code) and
let's see if we can reduce the bloat for CONFIG_MEMORY_HOTPLUG=n
kernels.
This needn't be done immediately - it would be OK by me if you were to
defer this exercise until all the new memhotplug code is largely in
place. But please, let's do it.
Hi Andrew,
Thank you very much for your pushing. :)
On 01/10/2013 06:23 AM, Andrew Morton wrote:
This does sound like a significant problem. We should assume that
mmecg is available and in use.
quoted
In patch1, we provide a solution which is not good enough:
Iterate twice to offline the memory.
1st iterate: offline every non primary memory block.
2nd iterate: offline primary (i.e. first added) memory block.
Let's flesh this out a bit.
If we online memory8, memory9, memory10 and memory11 then I'd have
thought that they would need to offlined in reverse order, which will
require four iterations, not two. Is this wrong and if so, why?
Well, we may need more than two iterations if all memory8, memory9,
memory10 are in use by kernel, and 10 depends on 9, 9 depends on 8.
So, as you see here, the iteration method is not good enough.
But this only happens when the memory is used by kernel, which will not
be able to be migrated. So if we can use a boot option, such as
movablecore_map, or movable_online functionality to limit the memory as
movable, the kernel will not use this memory. So it is safe when we are
doing node hot-remove.
Also, what happens if we wish to offline only memory9? Do we offline
memory11 then memory10 then memory9 and then re-online memory10 and
memory11?
In this case, offlining memory9 could fail if user do this by himself,
for example using sysfs.
In this path, it is in memory hot-remove path. So when we remove a
memory device, it will automatically offline all pages, and it is in
reverse order by itself.
And again, this is not good enough. We will figure out a reasonable way
to solve it soon.
quoted
And a new idea from Wen Congyang[off-list ref] is:
allocate the memory from the memory block they are describing.
Yes.
quoted
But we are not sure if it is OK to do so because there is not existing API
to do so, and we need to move page_cgroup memory allocation from MEM_GOING_ONLINE
to MEM_ONLINE.
This all sounds solvable - can we proceed in this fashion?
Yes, we are in progress now.
quoted
And also, it may interfere the hugepage.
Please provide full details on this problem.
It is not very clear now, and if I find something, I'll share it out.
quoted
Note: if the memory provided by the memory device is used by the kernel, it
can't be offlined. It is not a bug.
Right. But how often does this happen in testing? In other words,
please provide an overall description of how well memory hot-remove is
presently operating. Is it reliable? What is the success rate in
real-world situations?
We test the hot-remove functionality mostly with movable_online used.
And the memory used by kernel is not allowed to be removed.
We will do some tests in the kernel memory offline cases, and tell you
the test results soon.
And since we are trying out some other ways, I think the problem will
be solved soon.
Are there precautions which the administrator
can take to improve the success rate?
Administrator could use movablecore_map boot option or movable_online
functionality (which is now in kernel) to limit memory as movable to
avoid this problem.
What are the remaining problems
and are there plans to address them?
For now, we will try to allocate page_group on the memory block which
itself is describing. And all the other parts seems work well now.
And we are still testing. If we have any problem, we will share.
Thanks. :)
--
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
Hi Andrew,
On 01/10/2013 07:33 AM, Andrew Morton wrote:
On Wed, 9 Jan 2013 17:32:24 +0800
Tang Chen[off-list ref] wrote:
quoted
This patch-set aims to implement physical memory hot-removing.
As you were on th patch delivery path, all of these patches should have
your Signed-off-by:. But some were missing it. I fixed this in my
copy of the patches.
Thank you very much for the help. Next time I'll add it myself.
I suspect this patchset adds a significant amount of code which will
not be used if CONFIG_MEMORY_HOTPLUG=n. "[PATCH v6 06/15]
memory-hotplug: implement register_page_bootmem_info_section of
sparse-vmemmap", for example. This is not a good thing, so please go
through the patchset (in fact, go through all the memhotplug code) and
let's see if we can reduce the bloat for CONFIG_MEMORY_HOTPLUG=n
kernels.
This needn't be done immediately - it would be OK by me if you were to
defer this exercise until all the new memhotplug code is largely in
place. But please, let's do it.
OK, I'll do have a check on it when the page_cgroup problem is solved.
Thanks. :)
Hi Andrew,
On 01/10/2013 06:50 AM, Andrew Morton wrote:
On Wed, 9 Jan 2013 17:32:29 +0800
Tang Chen[off-list ref] wrote:
quoted
For removing memory, we need to remove page table. But it depends
on architecture. So the patch introduce arch_remove_memory() for
removing page table. Now it only calls __remove_pages().
Note: __remove_pages() for some archtecuture is not implemented
(I don't know how to implement it for s390).
Can this break the build for s390?
No, I don't think so. The arch_remove_memory() in s390 will only
return -EBUSY.
Thanks. :)
Hi Andrew,
On 01/10/2013 06:49 AM, Andrew Morton wrote:
On Wed, 9 Jan 2013 17:32:28 +0800
Tang Chen[off-list ref] wrote:
quoted
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 which is allocated by bootmem.
So the patch makes memory leak. But I think the memory leak size is
very samll. And it does not affect the system.
Well that's bad. Can we remember the address of that memory and then
reuse the storage if/when the memory is re-added? That at least puts an upper
bound on the leak.
I think we can do this. I'll post a new patch to do so.
Thanks. :)
Hi Andrew,
On 01/10/2013 07:11 AM, Andrew Morton wrote:
On Wed, 9 Jan 2013 17:32:26 +0800
Tang Chen[off-list ref] wrote:
quoted
We remove the memory like this:
1. lock memory hotplug
2. offline a memory block
3. unlock memory hotplug
4. repeat 1-3 to offline all memory blocks
5. lock memory hotplug
6. remove memory(TODO)
7. unlock memory hotplug
All memory blocks must be offlined before removing memory. But we don't hold
the lock in the whole operation. So we should check whether all memory blocks
are offlined before step6. Otherwise, kernel maybe panicked.
Well, the obvious question is: why don't we hold lock_memory_hotplug()
for all of steps 1-4? Please send the reasons for this in a form which
I can paste into the changelog.
In the changelog form:
Offlining a memory block and removing a memory device can be two
different operations. Users can just offline some memory blocks
without removing the memory device. For this purpose, the kernel has
held lock_memory_hotplug() in __offline_pages(). To reuse the code
for memory hot-remove, we repeat step 1-3 to offline all the memory
blocks, repeatedly lock and unlock memory hotplug, but not hold the
memory hotplug lock in the whole operation.
Actually, I wonder if doing this would fix a race in the current
remove_memory() repeat: loop. That code does a
find_memory_block_hinted() followed by offline_memory_block(), but
afaict find_memory_block_hinted() only does a get_device(). Is the
get_device() sufficiently strong to prevent problems if another thread
concurrently offlines or otherwise alters this memory_block's state?
I think we already have memory_block->state_mutex to protect the
concurrently changing of memory_block's state.
The find_memory_block_hinted() here is to find the memory_block
corresponding to the memory section we are dealing with.
Thanks. :)
Hi Andrew,
On 01/10/2013 07:19 AM, Andrew Morton wrote:
quoted
...
+ entry = firmware_map_find_entry(start, end - 1, type);
+ if (!entry)
+ return -EINVAL;
+
+ firmware_map_remove_entry(entry);
...
The above code looks racy. After firmware_map_find_entry() does the
spin_unlock() there is nothing to prevent a concurrent
firmware_map_remove_entry() from removing the entry, so the kernel ends
up calling firmware_map_remove_entry() twice against the same entry.
An easy fix for this is to hold the spinlock across the entire
lookup/remove operation.
This problem is inherent to firmware_map_find_entry() as you have
implemented it, so this function simply should not exist in the current
form - no caller can use it without being buggy! A simple fix for this
is to remove the spin_lock()/spin_unlock() from
firmware_map_find_entry() and add locking documentation to
firmware_map_find_entry(), explaining that the caller must hold
map_entries_lock and must not release that lock until processing of
firmware_map_find_entry()'s return value has completed.
Thank you for your advice, I'll fix it soon.
Since you have merged the patch-set, do I need to resend all these
patches again, or just send a patch to fix it based on the current
one ?
Thanks. :)
From: Glauber Costa <hidden> Date: 2013-01-10 07:14:20
On 01/10/2013 06:17 AM, Tang Chen wrote:
quoted
quoted
Note: if the memory provided by the memory device is used by the
kernel, it
can't be offlined. It is not a bug.
Right. But how often does this happen in testing? In other words,
please provide an overall description of how well memory hot-remove is
presently operating. Is it reliable? What is the success rate in
real-world situations?
We test the hot-remove functionality mostly with movable_online used.
And the memory used by kernel is not allowed to be removed.
Can you try doing this using cpusets configured to hardwall ?
It is my understanding that the object allocators will try hard not to
allocate anything outside the walls defined by cpuset. Which means that
if you have one process per node, and they are hardwalled, your kernel
memory will be spread evenly among the machine. With a big enough load,
they should eventually be present in all blocks.
Another question I have for you: Have you considering calling
shrink_slab to try to deplete the caches and therefore free at least
slab memory in the nodes that can't be offlined? Is it relevant?
Note: if the memory provided by the memory device is used by the
kernel, it
can't be offlined. It is not a bug.
Right. But how often does this happen in testing? In other words,
please provide an overall description of how well memory hot-remove is
presently operating. Is it reliable? What is the success rate in
real-world situations?
We test the hot-remove functionality mostly with movable_online used.
And the memory used by kernel is not allowed to be removed.
Can you try doing this using cpusets configured to hardwall ?
It is my understanding that the object allocators will try hard not to
allocate anything outside the walls defined by cpuset. Which means that
if you have one process per node, and they are hardwalled, your kernel
memory will be spread evenly among the machine. With a big enough load,
they should eventually be present in all blocks.
I'm sorry I couldn't catch your point.
Do you want to confirm whether cpuset can work enough instead of ZONE_MOVABLE ?
Or Do you want to confirm whether ZONE_MOVABLE will not work if it's used with cpuset ?
Another question I have for you: Have you considering calling
shrink_slab to try to deplete the caches and therefore free at least
slab memory in the nodes that can't be offlined? Is it relevant?
At this stage, we don't consider to call shrink_slab(). We require
nearly 100% success at offlining memory for removing DIMM.
It's my understanding.
IMHO, I don't think shrink_slab() can kill all objects in a node even
if they are some caches. We need more study for doing that.
Thanks,
-Kame
From: Glauber Costa <hidden> Date: 2013-01-10 07:55:08
On 01/10/2013 11:31 AM, Kamezawa Hiroyuki wrote:
(2013/01/10 16:14), Glauber Costa wrote:
quoted
On 01/10/2013 06:17 AM, Tang Chen wrote:
quoted
quoted
quoted
Note: if the memory provided by the memory device is used by the
kernel, it
can't be offlined. It is not a bug.
Right. But how often does this happen in testing? In other words,
please provide an overall description of how well memory hot-remove is
presently operating. Is it reliable? What is the success rate in
real-world situations?
We test the hot-remove functionality mostly with movable_online used.
And the memory used by kernel is not allowed to be removed.
Can you try doing this using cpusets configured to hardwall ?
It is my understanding that the object allocators will try hard not to
allocate anything outside the walls defined by cpuset. Which means that
if you have one process per node, and they are hardwalled, your kernel
memory will be spread evenly among the machine. With a big enough load,
they should eventually be present in all blocks.
I'm sorry I couldn't catch your point.
Do you want to confirm whether cpuset can work enough instead of
ZONE_MOVABLE ?
Or Do you want to confirm whether ZONE_MOVABLE will not work if it's
used with cpuset ?
No, I am not proposing to use cpuset do tackle the problem. I am just
wondering if you would still have high success rates with cpusets in use
with hardwalls. This is just one example of a workload that would spread
kernel memory around quite heavily.
So this is just me trying to understand the limitations of the mechanism.
quoted
Another question I have for you: Have you considering calling
shrink_slab to try to deplete the caches and therefore free at least
slab memory in the nodes that can't be offlined? Is it relevant?
At this stage, we don't consider to call shrink_slab(). We require
nearly 100% success at offlining memory for removing DIMM.
It's my understanding.
Of course, this is indisputable.
IMHO, I don't think shrink_slab() can kill all objects in a node even
if they are some caches. We need more study for doing that.
Indeed, shrink_slab can only kill cached objects. They, however, are
usually a very big part of kernel memory. I wonder though if in case of
failure, it is worth it to try at least one shrink pass before you give up.
It is not very different from what is in memory-failure.c, except that
we could do better and do a more targetted shrinking (support for that
is being worked on)
Note: if the memory provided by the memory device is used by the
kernel, it
can't be offlined. It is not a bug.
Right. But how often does this happen in testing? In other words,
please provide an overall description of how well memory hot-remove is
presently operating. Is it reliable? What is the success rate in
real-world situations?
We test the hot-remove functionality mostly with movable_online used.
And the memory used by kernel is not allowed to be removed.
Can you try doing this using cpusets configured to hardwall ?
It is my understanding that the object allocators will try hard not to
allocate anything outside the walls defined by cpuset. Which means that
if you have one process per node, and they are hardwalled, your kernel
memory will be spread evenly among the machine. With a big enough load,
they should eventually be present in all blocks.
I'm sorry I couldn't catch your point.
Do you want to confirm whether cpuset can work enough instead of
ZONE_MOVABLE ?
Or Do you want to confirm whether ZONE_MOVABLE will not work if it's
used with cpuset ?
No, I am not proposing to use cpuset do tackle the problem. I am just
wondering if you would still have high success rates with cpusets in use
with hardwalls. This is just one example of a workload that would spread
kernel memory around quite heavily.
So this is just me trying to understand the limitations of the mechanism.
Hm, okay. In my undestanding, if the whole memory of a node is configured as
MOVABLE, no kernel memory will not be allocated in the node because zonelist
will not match. So, if cpuset is used with hardwalls, user will see -ENOMEM or OOM,
I guess. even fork() will fail if fallback-to-other-node is not allowed.
If it's configure as ZONE_NORMAL, you need to pray for offlining memory.
AFAIK, IBM's ppc? has 16MB section size. So, some of sections can be offlined
even if they are configured as ZONE_NORMAL. For them, placement of offlined
memory is not important because it's virtualized by LPAR, they don't try
to remove DIMM, they just want to increase/decrease amount of memory.
It's an another approach.
But here, we(fujitsu) tries to remove a system board/DIMM.
So, configuring the whole memory of a node as ZONE_MOVABLE and tries to guarantee
DIMM as removable.
quoted
IMHO, I don't think shrink_slab() can kill all objects in a node even
if they are some caches. We need more study for doing that.
Indeed, shrink_slab can only kill cached objects. They, however, are
usually a very big part of kernel memory. I wonder though if in case of
failure, it is worth it to try at least one shrink pass before you give up.
Yeah, now, his (our) approach is never allowing kernel memory on a node to be
hot-removed by ZONE_MOVABLE. So, shrink_slab()'s effect will not be seen.
If other brave guys tries to use ZONE_NORMAL for hot-pluggable DIMM, I see,
it's worth triying.
How about checking the target memsection is in NORMAL or in MOVABLE at
hot-removing ? If NORMAL, shrink_slab() will be worth to be called.
BTW, shrink_slab() is now node/zone aware ? If not, fixing that first will
be better direction I guess.
Thanks,
-Kame
From: Glauber Costa <hidden> Date: 2013-01-10 08:36:05
If it's configure as ZONE_NORMAL, you need to pray for offlining memory.
AFAIK, IBM's ppc? has 16MB section size. So, some of sections can be
offlined
even if they are configured as ZONE_NORMAL. For them, placement of offlined
memory is not important because it's virtualized by LPAR, they don't try
to remove DIMM, they just want to increase/decrease amount of memory.
It's an another approach.
But here, we(fujitsu) tries to remove a system board/DIMM.
So, configuring the whole memory of a node as ZONE_MOVABLE and tries to
guarantee
DIMM as removable.
quoted
quoted
IMHO, I don't think shrink_slab() can kill all objects in a node even
if they are some caches. We need more study for doing that.
Indeed, shrink_slab can only kill cached objects. They, however, are
usually a very big part of kernel memory. I wonder though if in case of
failure, it is worth it to try at least one shrink pass before you
give up.
Yeah, now, his (our) approach is never allowing kernel memory on a node
to be
hot-removed by ZONE_MOVABLE. So, shrink_slab()'s effect will not be seen.
Ok, that clarifies it to me.
If other brave guys tries to use ZONE_NORMAL for hot-pluggable DIMM, I see,
it's worth triying.
I was under the impression that this was being done in here.
How about checking the target memsection is in NORMAL or in MOVABLE at
hot-removing ? If NORMAL, shrink_slab() will be worth to be called.
Yes, this is what I meant. I think there is value investigating this,
since for a lot of workloads, a lot of the kernel memory will consist of
shrinkable cached memory. It would provide you with the same level of
guarantees (zero), but can improve the success rate (this is, of
course, a guess)
BTW, shrink_slab() is now node/zone aware ? If not, fixing that first will
be better direction I guess.
It is not upstream, but there are patches for this that I am already
using in my private tree.
From: Simon Jeons <hidden> Date: 2013-01-29 12:53:05
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
Here is the physical memory hot-remove patch-set based on 3.8rc-2.
Some questions ask you, not has relationship with this patchset, but is
memory hotplug stuff.
1. In function node_states_check_changes_online:
comments:
* If we don't have HIGHMEM nor movable node,
* node_states[N_NORMAL_MEMORY] contains nodes which have zones of
* 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE.
How to understand it? Why we don't have HIGHMEM nor movable node and
node_staes[N_NORMAL_MEMORY] contains 0...ZONE_MOVABLE, IIUC,
N_NORMAL_MEMORY only means the node has regular memory.
* If we don't have movable node, node_states[N_NORMAL_MEMORY]
* contains nodes which have zones of 0...ZONE_MOVABLE,
* set zone_last to ZONE_MOVABLE.
How to understand?
2. In function move_pfn_range_left, why end <= z2->zone_start_pfn is not
correct? The comments said that must include/overlap, why?
3. In function online_pages, the normal case(w/o online_kenrel,
online_movable), why not check if the new zone is overlap with adjacent
zones?
4. Could you summarize the difference implementation between hot-add and
logic-add, hot-remove and logic-remove?
This patch-set aims to implement physical memory hot-removing.
The patches can free/remove the following things:
- /sys/firmware/memmap/X/{end, start, type} : [PATCH 4/15]
- memmap of sparse-vmemmap : [PATCH 6,7,8,10/15]
- page table of removed memory : [RFC PATCH 7,8,10/15]
- node and related sysfs files : [RFC PATCH 13-15/15]
Existing problem:
If CONFIG_MEMCG is selected, we will allocate memory to store page cgroup
when we online pages.
For example: there is a memory device on node 1. The address range
is [1G, 1.5G). You will find 4 new directories memory8, memory9, memory10,
and memory11 under the directory /sys/devices/system/memory/.
If CONFIG_MEMCG is selected, when we online memory8, the memory stored page
cgroup is not provided by this memory device. But when we online memory9, the
memory stored page cgroup may be provided by memory8. So we can't offline
memory8 now. We should offline the memory in the reversed order.
When the memory device is hotremoved, we will auto offline memory provided
by this memory device. But we don't know which memory is onlined first, so
offlining memory may fail.
In patch1, we provide a solution which is not good enough:
Iterate twice to offline the memory.
1st iterate: offline every non primary memory block.
2nd iterate: offline primary (i.e. first added) memory block.
And a new idea from Wen Congyang [off-list ref] is:
allocate the memory from the memory block they are describing.
But we are not sure if it is OK to do so because there is not existing API
to do so, and we need to move page_cgroup memory allocation from MEM_GOING_ONLINE
to MEM_ONLINE. And also, it may interfere the hugepage.
How to test this patchset?
1. apply this patchset and build the kernel. MEMORY_HOTPLUG, MEMORY_HOTREMOVE,
ACPI_HOTPLUG_MEMORY must be selected.
2. load the module acpi_memhotplug
3. hotplug the memory device(it depends on your hardware)
You will see the memory device under the directory /sys/bus/acpi/devices/.
Its name is PNP0C80:XX.
4. online/offline pages provided by this memory device
You can write online/offline to /sys/devices/system/memory/memoryX/state to
online/offline pages provided by this memory device
5. hotremove the memory device
You can hotremove the memory device by the hardware, or writing 1 to
/sys/bus/acpi/devices/PNP0C80:XX/eject.
Is there a similar knode to hot-add the memory device?
Note: if the memory provided by the memory device is used by the kernel, it
can't be offlined. It is not a bug.
Changelogs from v5 to v6:
Patch3: Add some more comments to explain memory hot-remove.
Patch4: Remove bootmem member in struct firmware_map_entry.
Patch6: Repeatedly register bootmem pages when using hugepage.
Patch8: Repeatedly free bootmem pages when using hugepage.
Patch14: Don't free pgdat when offlining a node, just reset it to 0.
Patch15: New patch, pgdat is not freed in patch14, so don't allocate a new
one when online a node.
Changelogs from v4 to v5:
Patch7: new patch, move pgdat_resize_lock into sparse_remove_one_section() to
avoid disabling irq because we need flush tlb when free pagetables.
Patch8: new patch, pick up some common APIs that are used to free direct mapping
and vmemmap pagetables.
Patch9: free direct mapping pagetables on x86_64 arch.
Patch10: free vmemmap pagetables.
Patch11: since freeing memmap with vmemmap has been implemented, the config
macro CONFIG_SPARSEMEM_VMEMMAP when defining __remove_section() is
no longer needed.
Patch13: no need to modify acpi_memory_disable_device() since it was removed,
and add nid parameter when calling remove_memory().
Changelogs from v3 to v4:
Patch7: remove unused codes.
Patch8: fix nr_pages that is passed to free_map_bootmem()
Changelogs from v2 to v3:
Patch9: call sync_global_pgds() if pgd is changed
Patch10: fix a problem int the patch
Changelogs from v1 to v2:
Patch1: new patch, offline memory twice. 1st iterate: offline every non primary
memory block. 2nd iterate: offline primary (i.e. first added) memory
block.
Patch3: new patch, no logical change, just remove reduntant codes.
Patch9: merge the patch from wujianguo into this patch. flush tlb on all cpu
after the pagetable is changed.
Patch12: new patch, free node_data when a node is offlined.
Tang Chen (6):
memory-hotplug: move pgdat_resize_lock into
sparse_remove_one_section()
memory-hotplug: remove page table of x86_64 architecture
memory-hotplug: remove memmap of sparse-vmemmap
memory-hotplug: Integrated __remove_section() of
CONFIG_SPARSEMEM_VMEMMAP.
memory-hotplug: remove sysfs file of node
memory-hotplug: Do not allocate pdgat if it was not freed when
offline.
Wen Congyang (5):
memory-hotplug: try to offline the memory twice to avoid dependence
memory-hotplug: remove redundant codes
memory-hotplug: introduce new function arch_remove_memory() for
removing page table depends on architecture
memory-hotplug: Common APIs to support page tables hot-remove
memory-hotplug: free node_data when a node is offlined
Yasuaki Ishimatsu (4):
memory-hotplug: check whether all memory blocks are offlined or not
when removing memory
memory-hotplug: remove /sys/firmware/memmap/X sysfs
memory-hotplug: implement register_page_bootmem_info_section of
sparse-vmemmap
memory-hotplug: memory_hotplug: clear zone when removing the memory
arch/arm64/mm/mmu.c | 3 +
arch/ia64/mm/discontig.c | 10 +
arch/ia64/mm/init.c | 18 ++
arch/powerpc/mm/init_64.c | 10 +
arch/powerpc/mm/mem.c | 12 +
arch/s390/mm/init.c | 12 +
arch/s390/mm/vmem.c | 10 +
arch/sh/mm/init.c | 17 ++
arch/sparc/mm/init_64.c | 10 +
arch/tile/mm/init.c | 8 +
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_32.c | 12 +
arch/x86/mm/init_64.c | 390 +++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 ++--
drivers/acpi/acpi_memhotplug.c | 8 +-
drivers/base/memory.c | 6 +
drivers/firmware/memmap.c | 96 +++++++-
include/linux/bootmem.h | 1 +
include/linux/firmware-map.h | 6 +
include/linux/memory_hotplug.h | 15 +-
include/linux/mm.h | 4 +-
mm/memory_hotplug.c | 459 +++++++++++++++++++++++++++++++---
mm/sparse.c | 8 +-
23 files changed, 1094 insertions(+), 69 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Simon Jeons <hidden> Date: 2013-01-29 13:02:36
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
From: Wen Congyang <redacted>
When memory is removed, the corresponding pagetables should alse be removed.
This patch introduces some common APIs to support vmemmap pagetable and x86_64
architecture pagetable removing.
When page table of hot-add memory is created?
quoted hunk
All pages of virtual mapping in removed memory cannot be freedi if some pages
used as PGD/PUD includes not only removed memory but also other memory. So the
patch uses the following way 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.
Signed-off-by: Yasuaki Ishimatsu <redacted>
Signed-off-by: Jianguo Wu <redacted>
Signed-off-by: Wen Congyang <redacted>
Signed-off-by: Tang Chen <redacted>
---
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_64.c | 299 ++++++++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 +++---
include/linux/bootmem.h | 1 +
4 files changed, 326 insertions(+), 22 deletions(-)
@@ -682,6 +682,305 @@ int arch_add_memory(int nid, u64 start, u64 size)}EXPORT_SYMBOL_GPL(arch_add_memory);+#define PAGE_INUSE 0xFD++staticvoid__meminitfree_pagetable(structpage*page,intorder)+{+structzone*zone;+boolbootmem=false;+unsignedlongmagic;+unsignedintnr_pages=1<<order;++/* bootmem page has reserved flag */+if(PageReserved(page)){+__ClearPageReserved(page);+bootmem=true;++magic=(unsignedlong)page->lru.next;+if(magic==SECTION_INFO||magic==MIX_SECTION_INFO){+while(nr_pages--)+put_page_bootmem(page++);+}else+__free_pages_bootmem(page,order);+}else+free_pages((unsignedlong)page_address(page),order);++/*+*SECTION_INFOpagesandMIX_SECTION_INFOpages+*areallallocatedbybootmem.+*/+if(bootmem){+zone=page_zone(page);+zone_span_writelock(zone);+zone->present_pages+=nr_pages;+zone_span_writeunlock(zone);+totalram_pages+=nr_pages;+}+}++staticvoid__meminitfree_pte_table(pte_t*pte_start,pmd_t*pmd)+{+pte_t*pte;+inti;++for(i=0;i<PTRS_PER_PTE;i++){+pte=pte_start+i;+if(pte_val(*pte))+return;+}++/* free a pte talbe */+free_pagetable(pmd_page(*pmd),0);+spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+}++staticvoid__meminitfree_pmd_table(pmd_t*pmd_start,pud_t*pud)+{+pmd_t*pmd;+inti;++for(i=0;i<PTRS_PER_PMD;i++){+pmd=pmd_start+i;+if(pmd_val(*pmd))+return;+}++/* free a pmd talbe */+free_pagetable(pud_page(*pud),0);+spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+}++/* Return true if pgd is changed, otherwise return false. */+staticbool__meminitfree_pud_table(pud_t*pud_start,pgd_t*pgd)+{+pud_t*pud;+inti;++for(i=0;i<PTRS_PER_PUD;i++){+pud=pud_start+i;+if(pud_val(*pud))+returnfalse;+}++/* free a pud table */+free_pagetable(pgd_page(*pgd),0);+spin_lock(&init_mm.page_table_lock);+pgd_clear(pgd);+spin_unlock(&init_mm.page_table_lock);++returntrue;+}++staticvoid__meminit+remove_pte_table(pte_t*pte_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongnext,pages=0;+pte_t*pte;+void*page_addr;+phys_addr_tphys_addr;++pte=pte_start+pte_index(addr);+for(;addr<end;addr=next,pte++){+next=(addr+PAGE_SIZE)&PAGE_MASK;+if(next>end)+next=end;++if(!pte_present(*pte))+continue;++/*+*Wemapped[0,1G)memoryasidentitymappingwhen+*initializing,inarch/x86/kernel/head_64.S.These+*pagetablescannotberemoved.+*/+phys_addr=pte_val(*pte)+(addr&PAGE_MASK);+if(phys_addr<(phys_addr_t)0x40000000)+return;++if(IS_ALIGNED(addr,PAGE_SIZE)&&+IS_ALIGNED(next,PAGE_SIZE)){+if(!direct){+free_pagetable(pte_page(*pte),0);+pages++;+}++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}else{+/*+*Ifwearenotremovingthewholepage,itmeans+*otherptesinthispagearebeingusedandwecanot+*removethem.Sofilltheunusedpteswith0xFD,and+*removethepagewhenitiswhollyfilledwith0xFD.+*/+memset((void*)addr,PAGE_INUSE,next-addr);+page_addr=page_address(pte_page(*pte));++if(!memchr_inv(page_addr,PAGE_INUSE,PAGE_SIZE)){+free_pagetable(pte_page(*pte),0);+pages++;++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}+}+}++/* Call free_pte_table() in remove_pmd_table(). */+flush_tlb_all();+if(direct)+update_page_count(PG_LEVEL_4K,-pages);+}++staticvoid__meminit+remove_pmd_table(pmd_t*pmd_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpte_phys,next,pages=0;+pte_t*pte_base;+pmd_t*pmd;++pmd=pmd_start+pmd_index(addr);+for(;addr<end;addr=next,pmd++){+next=pmd_addr_end(addr,end);++if(!pmd_present(*pmd))+continue;++if(pmd_large(*pmd)){+if(IS_ALIGNED(addr,PMD_SIZE)&&+IS_ALIGNED(next,PMD_SIZE)){+if(!direct){+free_pagetable(pmd_page(*pmd),+get_order(PMD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse2Mpage,butweneedtoremovepartofthem,+*sosplit2Mpageto4Kpage.+*/+pte_base=(pte_t*)alloc_low_page(&pte_phys);+BUG_ON(!pte_base);+__split_large_page((pte_t*)pmd,addr,+(pte_t*)pte_base);++spin_lock(&init_mm.page_table_lock);+pmd_populate_kernel(&init_mm,pmd,__va(pte_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pte_base=(pte_t*)map_low_page((pte_t*)pmd_page_vaddr(*pmd));+remove_pte_table(pte_base,addr,next,direct);+free_pte_table(pte_base,pmd);+unmap_low_page(pte_base);+}++/* Call free_pmd_table() in remove_pud_table(). */+if(direct)+update_page_count(PG_LEVEL_2M,-pages);+}++staticvoid__meminit+remove_pud_table(pud_t*pud_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpmd_phys,next,pages=0;+pmd_t*pmd_base;+pud_t*pud;++pud=pud_start+pud_index(addr);+for(;addr<end;addr=next,pud++){+next=pud_addr_end(addr,end);++if(!pud_present(*pud))+continue;++if(pud_large(*pud)){+if(IS_ALIGNED(addr,PUD_SIZE)&&+IS_ALIGNED(next,PUD_SIZE)){+if(!direct){+free_pagetable(pud_page(*pud),+get_order(PUD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse1Gpage,butweneedtoremovepartofthem,+*sosplit1Gpageto2Mpage.+*/+pmd_base=(pmd_t*)alloc_low_page(&pmd_phys);+BUG_ON(!pmd_base);+__split_large_page((pte_t*)pud,addr,+(pte_t*)pmd_base);++spin_lock(&init_mm.page_table_lock);+pud_populate(&init_mm,pud,__va(pmd_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pmd_base=(pmd_t*)map_low_page((pmd_t*)pud_page_vaddr(*pud));+remove_pmd_table(pmd_base,addr,next,direct);+free_pmd_table(pmd_base,pud);+unmap_low_page(pmd_base);+}++if(direct)+update_page_count(PG_LEVEL_1G,-pages);+}++/* start and end are both virtual address. */+staticvoid__meminit+remove_pagetable(unsignedlongstart,unsignedlongend,booldirect)+{+unsignedlongnext;+pgd_t*pgd;+pud_t*pud;+boolpgd_changed=false;++for(;start<end;start=next){+pgd=pgd_offset_k(start);+if(!pgd_present(*pgd))+continue;++next=pgd_addr_end(start,end);++pud=(pud_t*)map_low_page((pud_t*)pgd_page_vaddr(*pgd));+remove_pud_table(pud,start,next,direct);+if(free_pud_table(pud,pgd))+pgd_changed=true;+unmap_low_page(pud);+}++if(pgd_changed)+sync_global_pgds(start,end-1);++flush_tlb_all();+}+#ifdef CONFIG_MEMORY_HOTREMOVEint__refarch_remove_memory(u64start,u64size){
From: Simon Jeons <hidden> Date: 2013-01-29 13:05:08
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
From: Wen Congyang <redacted>
When memory is removed, the corresponding pagetables should alse be removed.
This patch introduces some common APIs to support vmemmap pagetable and x86_64
architecture pagetable removing.
Why don't need to build_all_zonelists like online_pages does during
hot-add path(add_memory)?
quoted hunk
All pages of virtual mapping in removed memory cannot be freedi if some pages
used as PGD/PUD includes not only removed memory but also other memory. So the
patch uses the following way 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.
Signed-off-by: Yasuaki Ishimatsu <redacted>
Signed-off-by: Jianguo Wu <redacted>
Signed-off-by: Wen Congyang <redacted>
Signed-off-by: Tang Chen <redacted>
---
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_64.c | 299 ++++++++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 +++---
include/linux/bootmem.h | 1 +
4 files changed, 326 insertions(+), 22 deletions(-)
@@ -682,6 +682,305 @@ int arch_add_memory(int nid, u64 start, u64 size)}EXPORT_SYMBOL_GPL(arch_add_memory);+#define PAGE_INUSE 0xFD++staticvoid__meminitfree_pagetable(structpage*page,intorder)+{+structzone*zone;+boolbootmem=false;+unsignedlongmagic;+unsignedintnr_pages=1<<order;++/* bootmem page has reserved flag */+if(PageReserved(page)){+__ClearPageReserved(page);+bootmem=true;++magic=(unsignedlong)page->lru.next;+if(magic==SECTION_INFO||magic==MIX_SECTION_INFO){+while(nr_pages--)+put_page_bootmem(page++);+}else+__free_pages_bootmem(page,order);+}else+free_pages((unsignedlong)page_address(page),order);++/*+*SECTION_INFOpagesandMIX_SECTION_INFOpages+*areallallocatedbybootmem.+*/+if(bootmem){+zone=page_zone(page);+zone_span_writelock(zone);+zone->present_pages+=nr_pages;+zone_span_writeunlock(zone);+totalram_pages+=nr_pages;+}+}++staticvoid__meminitfree_pte_table(pte_t*pte_start,pmd_t*pmd)+{+pte_t*pte;+inti;++for(i=0;i<PTRS_PER_PTE;i++){+pte=pte_start+i;+if(pte_val(*pte))+return;+}++/* free a pte talbe */+free_pagetable(pmd_page(*pmd),0);+spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+}++staticvoid__meminitfree_pmd_table(pmd_t*pmd_start,pud_t*pud)+{+pmd_t*pmd;+inti;++for(i=0;i<PTRS_PER_PMD;i++){+pmd=pmd_start+i;+if(pmd_val(*pmd))+return;+}++/* free a pmd talbe */+free_pagetable(pud_page(*pud),0);+spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+}++/* Return true if pgd is changed, otherwise return false. */+staticbool__meminitfree_pud_table(pud_t*pud_start,pgd_t*pgd)+{+pud_t*pud;+inti;++for(i=0;i<PTRS_PER_PUD;i++){+pud=pud_start+i;+if(pud_val(*pud))+returnfalse;+}++/* free a pud table */+free_pagetable(pgd_page(*pgd),0);+spin_lock(&init_mm.page_table_lock);+pgd_clear(pgd);+spin_unlock(&init_mm.page_table_lock);++returntrue;+}++staticvoid__meminit+remove_pte_table(pte_t*pte_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongnext,pages=0;+pte_t*pte;+void*page_addr;+phys_addr_tphys_addr;++pte=pte_start+pte_index(addr);+for(;addr<end;addr=next,pte++){+next=(addr+PAGE_SIZE)&PAGE_MASK;+if(next>end)+next=end;++if(!pte_present(*pte))+continue;++/*+*Wemapped[0,1G)memoryasidentitymappingwhen+*initializing,inarch/x86/kernel/head_64.S.These+*pagetablescannotberemoved.+*/+phys_addr=pte_val(*pte)+(addr&PAGE_MASK);+if(phys_addr<(phys_addr_t)0x40000000)+return;++if(IS_ALIGNED(addr,PAGE_SIZE)&&+IS_ALIGNED(next,PAGE_SIZE)){+if(!direct){+free_pagetable(pte_page(*pte),0);+pages++;+}++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}else{+/*+*Ifwearenotremovingthewholepage,itmeans+*otherptesinthispagearebeingusedandwecanot+*removethem.Sofilltheunusedpteswith0xFD,and+*removethepagewhenitiswhollyfilledwith0xFD.+*/+memset((void*)addr,PAGE_INUSE,next-addr);+page_addr=page_address(pte_page(*pte));++if(!memchr_inv(page_addr,PAGE_INUSE,PAGE_SIZE)){+free_pagetable(pte_page(*pte),0);+pages++;++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}+}+}++/* Call free_pte_table() in remove_pmd_table(). */+flush_tlb_all();+if(direct)+update_page_count(PG_LEVEL_4K,-pages);+}++staticvoid__meminit+remove_pmd_table(pmd_t*pmd_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpte_phys,next,pages=0;+pte_t*pte_base;+pmd_t*pmd;++pmd=pmd_start+pmd_index(addr);+for(;addr<end;addr=next,pmd++){+next=pmd_addr_end(addr,end);++if(!pmd_present(*pmd))+continue;++if(pmd_large(*pmd)){+if(IS_ALIGNED(addr,PMD_SIZE)&&+IS_ALIGNED(next,PMD_SIZE)){+if(!direct){+free_pagetable(pmd_page(*pmd),+get_order(PMD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse2Mpage,butweneedtoremovepartofthem,+*sosplit2Mpageto4Kpage.+*/+pte_base=(pte_t*)alloc_low_page(&pte_phys);+BUG_ON(!pte_base);+__split_large_page((pte_t*)pmd,addr,+(pte_t*)pte_base);++spin_lock(&init_mm.page_table_lock);+pmd_populate_kernel(&init_mm,pmd,__va(pte_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pte_base=(pte_t*)map_low_page((pte_t*)pmd_page_vaddr(*pmd));+remove_pte_table(pte_base,addr,next,direct);+free_pte_table(pte_base,pmd);+unmap_low_page(pte_base);+}++/* Call free_pmd_table() in remove_pud_table(). */+if(direct)+update_page_count(PG_LEVEL_2M,-pages);+}++staticvoid__meminit+remove_pud_table(pud_t*pud_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpmd_phys,next,pages=0;+pmd_t*pmd_base;+pud_t*pud;++pud=pud_start+pud_index(addr);+for(;addr<end;addr=next,pud++){+next=pud_addr_end(addr,end);++if(!pud_present(*pud))+continue;++if(pud_large(*pud)){+if(IS_ALIGNED(addr,PUD_SIZE)&&+IS_ALIGNED(next,PUD_SIZE)){+if(!direct){+free_pagetable(pud_page(*pud),+get_order(PUD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse1Gpage,butweneedtoremovepartofthem,+*sosplit1Gpageto2Mpage.+*/+pmd_base=(pmd_t*)alloc_low_page(&pmd_phys);+BUG_ON(!pmd_base);+__split_large_page((pte_t*)pud,addr,+(pte_t*)pmd_base);++spin_lock(&init_mm.page_table_lock);+pud_populate(&init_mm,pud,__va(pmd_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pmd_base=(pmd_t*)map_low_page((pmd_t*)pud_page_vaddr(*pud));+remove_pmd_table(pmd_base,addr,next,direct);+free_pmd_table(pmd_base,pud);+unmap_low_page(pmd_base);+}++if(direct)+update_page_count(PG_LEVEL_1G,-pages);+}++/* start and end are both virtual address. */+staticvoid__meminit+remove_pagetable(unsignedlongstart,unsignedlongend,booldirect)+{+unsignedlongnext;+pgd_t*pgd;+pud_t*pud;+boolpgd_changed=false;++for(;start<end;start=next){+pgd=pgd_offset_k(start);+if(!pgd_present(*pgd))+continue;++next=pgd_addr_end(start,end);++pud=(pud_t*)map_low_page((pud_t*)pgd_page_vaddr(*pgd));+remove_pud_table(pud,start,next,direct);+if(free_pud_table(pud,pgd))+pgd_changed=true;+unmap_low_page(pud);+}++if(pgd_changed)+sync_global_pgds(start,end-1);++flush_tlb_all();+}+#ifdef CONFIG_MEMORY_HOTREMOVEint__refarch_remove_memory(u64start,u64size){
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
quoted
From: Wen Congyang <redacted>
When memory is removed, the corresponding pagetables should alse be removed.
This patch introduces some common APIs to support vmemmap pagetable and x86_64
architecture pagetable removing.
When page table of hot-add memory is created?
Hi Simon,
For x86_64, page table of hot-add memory is created by:
add_memory->arch_add_memory->init_memory_mapping->kernel_physical_mapping_init
quoted
All pages of virtual mapping in removed memory cannot be freedi if some pages
used as PGD/PUD includes not only removed memory but also other memory. So the
patch uses the following way 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.
Signed-off-by: Yasuaki Ishimatsu <redacted>
Signed-off-by: Jianguo Wu <redacted>
Signed-off-by: Wen Congyang <redacted>
Signed-off-by: Tang Chen <redacted>
---
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_64.c | 299 ++++++++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 +++---
include/linux/bootmem.h | 1 +
4 files changed, 326 insertions(+), 22 deletions(-)
@@ -682,6 +682,305 @@ int arch_add_memory(int nid, u64 start, u64 size)}EXPORT_SYMBOL_GPL(arch_add_memory);+#define PAGE_INUSE 0xFD++staticvoid__meminitfree_pagetable(structpage*page,intorder)+{+structzone*zone;+boolbootmem=false;+unsignedlongmagic;+unsignedintnr_pages=1<<order;++/* bootmem page has reserved flag */+if(PageReserved(page)){+__ClearPageReserved(page);+bootmem=true;++magic=(unsignedlong)page->lru.next;+if(magic==SECTION_INFO||magic==MIX_SECTION_INFO){+while(nr_pages--)+put_page_bootmem(page++);+}else+__free_pages_bootmem(page,order);+}else+free_pages((unsignedlong)page_address(page),order);++/*+*SECTION_INFOpagesandMIX_SECTION_INFOpages+*areallallocatedbybootmem.+*/+if(bootmem){+zone=page_zone(page);+zone_span_writelock(zone);+zone->present_pages+=nr_pages;+zone_span_writeunlock(zone);+totalram_pages+=nr_pages;+}+}++staticvoid__meminitfree_pte_table(pte_t*pte_start,pmd_t*pmd)+{+pte_t*pte;+inti;++for(i=0;i<PTRS_PER_PTE;i++){+pte=pte_start+i;+if(pte_val(*pte))+return;+}++/* free a pte talbe */+free_pagetable(pmd_page(*pmd),0);+spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+}++staticvoid__meminitfree_pmd_table(pmd_t*pmd_start,pud_t*pud)+{+pmd_t*pmd;+inti;++for(i=0;i<PTRS_PER_PMD;i++){+pmd=pmd_start+i;+if(pmd_val(*pmd))+return;+}++/* free a pmd talbe */+free_pagetable(pud_page(*pud),0);+spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+}++/* Return true if pgd is changed, otherwise return false. */+staticbool__meminitfree_pud_table(pud_t*pud_start,pgd_t*pgd)+{+pud_t*pud;+inti;++for(i=0;i<PTRS_PER_PUD;i++){+pud=pud_start+i;+if(pud_val(*pud))+returnfalse;+}++/* free a pud table */+free_pagetable(pgd_page(*pgd),0);+spin_lock(&init_mm.page_table_lock);+pgd_clear(pgd);+spin_unlock(&init_mm.page_table_lock);++returntrue;+}++staticvoid__meminit+remove_pte_table(pte_t*pte_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongnext,pages=0;+pte_t*pte;+void*page_addr;+phys_addr_tphys_addr;++pte=pte_start+pte_index(addr);+for(;addr<end;addr=next,pte++){+next=(addr+PAGE_SIZE)&PAGE_MASK;+if(next>end)+next=end;++if(!pte_present(*pte))+continue;++/*+*Wemapped[0,1G)memoryasidentitymappingwhen+*initializing,inarch/x86/kernel/head_64.S.These+*pagetablescannotberemoved.+*/+phys_addr=pte_val(*pte)+(addr&PAGE_MASK);+if(phys_addr<(phys_addr_t)0x40000000)+return;++if(IS_ALIGNED(addr,PAGE_SIZE)&&+IS_ALIGNED(next,PAGE_SIZE)){+if(!direct){+free_pagetable(pte_page(*pte),0);+pages++;+}++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}else{+/*+*Ifwearenotremovingthewholepage,itmeans+*otherptesinthispagearebeingusedandwecanot+*removethem.Sofilltheunusedpteswith0xFD,and+*removethepagewhenitiswhollyfilledwith0xFD.+*/+memset((void*)addr,PAGE_INUSE,next-addr);+page_addr=page_address(pte_page(*pte));++if(!memchr_inv(page_addr,PAGE_INUSE,PAGE_SIZE)){+free_pagetable(pte_page(*pte),0);+pages++;++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}+}+}++/* Call free_pte_table() in remove_pmd_table(). */+flush_tlb_all();+if(direct)+update_page_count(PG_LEVEL_4K,-pages);+}++staticvoid__meminit+remove_pmd_table(pmd_t*pmd_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpte_phys,next,pages=0;+pte_t*pte_base;+pmd_t*pmd;++pmd=pmd_start+pmd_index(addr);+for(;addr<end;addr=next,pmd++){+next=pmd_addr_end(addr,end);++if(!pmd_present(*pmd))+continue;++if(pmd_large(*pmd)){+if(IS_ALIGNED(addr,PMD_SIZE)&&+IS_ALIGNED(next,PMD_SIZE)){+if(!direct){+free_pagetable(pmd_page(*pmd),+get_order(PMD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse2Mpage,butweneedtoremovepartofthem,+*sosplit2Mpageto4Kpage.+*/+pte_base=(pte_t*)alloc_low_page(&pte_phys);+BUG_ON(!pte_base);+__split_large_page((pte_t*)pmd,addr,+(pte_t*)pte_base);++spin_lock(&init_mm.page_table_lock);+pmd_populate_kernel(&init_mm,pmd,__va(pte_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pte_base=(pte_t*)map_low_page((pte_t*)pmd_page_vaddr(*pmd));+remove_pte_table(pte_base,addr,next,direct);+free_pte_table(pte_base,pmd);+unmap_low_page(pte_base);+}++/* Call free_pmd_table() in remove_pud_table(). */+if(direct)+update_page_count(PG_LEVEL_2M,-pages);+}++staticvoid__meminit+remove_pud_table(pud_t*pud_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpmd_phys,next,pages=0;+pmd_t*pmd_base;+pud_t*pud;++pud=pud_start+pud_index(addr);+for(;addr<end;addr=next,pud++){+next=pud_addr_end(addr,end);++if(!pud_present(*pud))+continue;++if(pud_large(*pud)){+if(IS_ALIGNED(addr,PUD_SIZE)&&+IS_ALIGNED(next,PUD_SIZE)){+if(!direct){+free_pagetable(pud_page(*pud),+get_order(PUD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse1Gpage,butweneedtoremovepartofthem,+*sosplit1Gpageto2Mpage.+*/+pmd_base=(pmd_t*)alloc_low_page(&pmd_phys);+BUG_ON(!pmd_base);+__split_large_page((pte_t*)pud,addr,+(pte_t*)pmd_base);++spin_lock(&init_mm.page_table_lock);+pud_populate(&init_mm,pud,__va(pmd_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pmd_base=(pmd_t*)map_low_page((pmd_t*)pud_page_vaddr(*pud));+remove_pmd_table(pmd_base,addr,next,direct);+free_pmd_table(pmd_base,pud);+unmap_low_page(pmd_base);+}++if(direct)+update_page_count(PG_LEVEL_1G,-pages);+}++/* start and end are both virtual address. */+staticvoid__meminit+remove_pagetable(unsignedlongstart,unsignedlongend,booldirect)+{+unsignedlongnext;+pgd_t*pgd;+pud_t*pud;+boolpgd_changed=false;++for(;start<end;start=next){+pgd=pgd_offset_k(start);+if(!pgd_present(*pgd))+continue;++next=pgd_addr_end(start,end);++pud=(pud_t*)map_low_page((pud_t*)pgd_page_vaddr(*pgd));+remove_pud_table(pud,start,next,direct);+if(free_pud_table(pud,pgd))+pgd_changed=true;+unmap_low_page(pud);+}++if(pgd_changed)+sync_global_pgds(start,end-1);++flush_tlb_all();+}+#ifdef CONFIG_MEMORY_HOTREMOVEint__refarch_remove_memory(u64start,u64size){
From: Simon Jeons <hidden> Date: 2013-01-30 02:13:21
On Wed, 2013-01-30 at 09:53 +0800, Jianguo Wu wrote:
On 2013/1/29 21:02, Simon Jeons wrote:
quoted
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
quoted
From: Wen Congyang <redacted>
When memory is removed, the corresponding pagetables should alse be removed.
This patch introduces some common APIs to support vmemmap pagetable and x86_64
architecture pagetable removing.
When page table of hot-add memory is created?
Hi Simon,
For x86_64, page table of hot-add memory is created by:
add_memory->arch_add_memory->init_memory_mapping->kernel_physical_mapping_init
Yup, thanks. :)
quoted
quoted
All pages of virtual mapping in removed memory cannot be freedi if some pages
used as PGD/PUD includes not only removed memory but also other memory. So the
patch uses the following way 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.
Signed-off-by: Yasuaki Ishimatsu <redacted>
Signed-off-by: Jianguo Wu <redacted>
Signed-off-by: Wen Congyang <redacted>
Signed-off-by: Tang Chen <redacted>
---
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_64.c | 299 ++++++++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 +++---
include/linux/bootmem.h | 1 +
4 files changed, 326 insertions(+), 22 deletions(-)
@@ -682,6 +682,305 @@ int arch_add_memory(int nid, u64 start, u64 size)}EXPORT_SYMBOL_GPL(arch_add_memory);+#define PAGE_INUSE 0xFD++staticvoid__meminitfree_pagetable(structpage*page,intorder)+{+structzone*zone;+boolbootmem=false;+unsignedlongmagic;+unsignedintnr_pages=1<<order;++/* bootmem page has reserved flag */+if(PageReserved(page)){+__ClearPageReserved(page);+bootmem=true;++magic=(unsignedlong)page->lru.next;+if(magic==SECTION_INFO||magic==MIX_SECTION_INFO){+while(nr_pages--)+put_page_bootmem(page++);+}else+__free_pages_bootmem(page,order);+}else+free_pages((unsignedlong)page_address(page),order);++/*+*SECTION_INFOpagesandMIX_SECTION_INFOpages+*areallallocatedbybootmem.+*/+if(bootmem){+zone=page_zone(page);+zone_span_writelock(zone);+zone->present_pages+=nr_pages;+zone_span_writeunlock(zone);+totalram_pages+=nr_pages;+}+}++staticvoid__meminitfree_pte_table(pte_t*pte_start,pmd_t*pmd)+{+pte_t*pte;+inti;++for(i=0;i<PTRS_PER_PTE;i++){+pte=pte_start+i;+if(pte_val(*pte))+return;+}++/* free a pte talbe */+free_pagetable(pmd_page(*pmd),0);+spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+}++staticvoid__meminitfree_pmd_table(pmd_t*pmd_start,pud_t*pud)+{+pmd_t*pmd;+inti;++for(i=0;i<PTRS_PER_PMD;i++){+pmd=pmd_start+i;+if(pmd_val(*pmd))+return;+}++/* free a pmd talbe */+free_pagetable(pud_page(*pud),0);+spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+}++/* Return true if pgd is changed, otherwise return false. */+staticbool__meminitfree_pud_table(pud_t*pud_start,pgd_t*pgd)+{+pud_t*pud;+inti;++for(i=0;i<PTRS_PER_PUD;i++){+pud=pud_start+i;+if(pud_val(*pud))+returnfalse;+}++/* free a pud table */+free_pagetable(pgd_page(*pgd),0);+spin_lock(&init_mm.page_table_lock);+pgd_clear(pgd);+spin_unlock(&init_mm.page_table_lock);++returntrue;+}++staticvoid__meminit+remove_pte_table(pte_t*pte_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongnext,pages=0;+pte_t*pte;+void*page_addr;+phys_addr_tphys_addr;++pte=pte_start+pte_index(addr);+for(;addr<end;addr=next,pte++){+next=(addr+PAGE_SIZE)&PAGE_MASK;+if(next>end)+next=end;++if(!pte_present(*pte))+continue;++/*+*Wemapped[0,1G)memoryasidentitymappingwhen+*initializing,inarch/x86/kernel/head_64.S.These+*pagetablescannotberemoved.+*/+phys_addr=pte_val(*pte)+(addr&PAGE_MASK);+if(phys_addr<(phys_addr_t)0x40000000)+return;++if(IS_ALIGNED(addr,PAGE_SIZE)&&+IS_ALIGNED(next,PAGE_SIZE)){+if(!direct){+free_pagetable(pte_page(*pte),0);+pages++;+}++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}else{+/*+*Ifwearenotremovingthewholepage,itmeans+*otherptesinthispagearebeingusedandwecanot+*removethem.Sofilltheunusedpteswith0xFD,and+*removethepagewhenitiswhollyfilledwith0xFD.+*/+memset((void*)addr,PAGE_INUSE,next-addr);+page_addr=page_address(pte_page(*pte));++if(!memchr_inv(page_addr,PAGE_INUSE,PAGE_SIZE)){+free_pagetable(pte_page(*pte),0);+pages++;++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}+}+}++/* Call free_pte_table() in remove_pmd_table(). */+flush_tlb_all();+if(direct)+update_page_count(PG_LEVEL_4K,-pages);+}++staticvoid__meminit+remove_pmd_table(pmd_t*pmd_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpte_phys,next,pages=0;+pte_t*pte_base;+pmd_t*pmd;++pmd=pmd_start+pmd_index(addr);+for(;addr<end;addr=next,pmd++){+next=pmd_addr_end(addr,end);++if(!pmd_present(*pmd))+continue;++if(pmd_large(*pmd)){+if(IS_ALIGNED(addr,PMD_SIZE)&&+IS_ALIGNED(next,PMD_SIZE)){+if(!direct){+free_pagetable(pmd_page(*pmd),+get_order(PMD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse2Mpage,butweneedtoremovepartofthem,+*sosplit2Mpageto4Kpage.+*/+pte_base=(pte_t*)alloc_low_page(&pte_phys);+BUG_ON(!pte_base);+__split_large_page((pte_t*)pmd,addr,+(pte_t*)pte_base);++spin_lock(&init_mm.page_table_lock);+pmd_populate_kernel(&init_mm,pmd,__va(pte_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pte_base=(pte_t*)map_low_page((pte_t*)pmd_page_vaddr(*pmd));+remove_pte_table(pte_base,addr,next,direct);+free_pte_table(pte_base,pmd);+unmap_low_page(pte_base);+}++/* Call free_pmd_table() in remove_pud_table(). */+if(direct)+update_page_count(PG_LEVEL_2M,-pages);+}++staticvoid__meminit+remove_pud_table(pud_t*pud_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpmd_phys,next,pages=0;+pmd_t*pmd_base;+pud_t*pud;++pud=pud_start+pud_index(addr);+for(;addr<end;addr=next,pud++){+next=pud_addr_end(addr,end);++if(!pud_present(*pud))+continue;++if(pud_large(*pud)){+if(IS_ALIGNED(addr,PUD_SIZE)&&+IS_ALIGNED(next,PUD_SIZE)){+if(!direct){+free_pagetable(pud_page(*pud),+get_order(PUD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse1Gpage,butweneedtoremovepartofthem,+*sosplit1Gpageto2Mpage.+*/+pmd_base=(pmd_t*)alloc_low_page(&pmd_phys);+BUG_ON(!pmd_base);+__split_large_page((pte_t*)pud,addr,+(pte_t*)pmd_base);++spin_lock(&init_mm.page_table_lock);+pud_populate(&init_mm,pud,__va(pmd_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pmd_base=(pmd_t*)map_low_page((pmd_t*)pud_page_vaddr(*pud));+remove_pmd_table(pmd_base,addr,next,direct);+free_pmd_table(pmd_base,pud);+unmap_low_page(pmd_base);+}++if(direct)+update_page_count(PG_LEVEL_1G,-pages);+}++/* start and end are both virtual address. */+staticvoid__meminit+remove_pagetable(unsignedlongstart,unsignedlongend,booldirect)+{+unsignedlongnext;+pgd_t*pgd;+pud_t*pud;+boolpgd_changed=false;++for(;start<end;start=next){+pgd=pgd_offset_k(start);+if(!pgd_present(*pgd))+continue;++next=pgd_addr_end(start,end);++pud=(pud_t*)map_low_page((pud_t*)pgd_page_vaddr(*pgd));+remove_pud_table(pud,start,next,direct);+if(free_pud_table(pud,pgd))+pgd_changed=true;+unmap_low_page(pud);+}++if(pgd_changed)+sync_global_pgds(start,end-1);++flush_tlb_all();+}+#ifdef CONFIG_MEMORY_HOTREMOVEint__refarch_remove_memory(u64start,u64size){
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
quoted
From: Wen Congyang<redacted>
When memory is removed, the corresponding pagetables should alse be removed.
This patch introduces some common APIs to support vmemmap pagetable and x86_64
architecture pagetable removing.
Why don't need to build_all_zonelists like online_pages does during
hot-add path(add_memory)?
Hi Simon,
As you said, build_all_zonelists is done by online_pages. When the
memory device
is hot-added, we cannot use it. we can only use is when we online the
pages on it.
But we can online the pages as different types, kernel or movable (which
belongs to
different zones), and we can online part of the memory, not all of them.
So each time we online some pages, we should check if we need to update
the zone list.
So I think that is why we do build_all_zonelists when online_pages.
(just my opinion)
Thanks. :)
quoted
All pages of virtual mapping in removed memory cannot be freedi if some pages
used as PGD/PUD includes not only removed memory but also other memory. So the
patch uses the following way 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.
Signed-off-by: Yasuaki Ishimatsu<redacted>
Signed-off-by: Jianguo Wu<redacted>
Signed-off-by: Wen Congyang<redacted>
Signed-off-by: Tang Chen<redacted>
---
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_64.c | 299 ++++++++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 +++---
include/linux/bootmem.h | 1 +
4 files changed, 326 insertions(+), 22 deletions(-)
@@ -682,6 +682,305 @@ int arch_add_memory(int nid, u64 start, u64 size)}EXPORT_SYMBOL_GPL(arch_add_memory);+#define PAGE_INUSE 0xFD++staticvoid__meminitfree_pagetable(structpage*page,intorder)+{+structzone*zone;+boolbootmem=false;+unsignedlongmagic;+unsignedintnr_pages=1<<order;++/* bootmem page has reserved flag */+if(PageReserved(page)){+__ClearPageReserved(page);+bootmem=true;++magic=(unsignedlong)page->lru.next;+if(magic==SECTION_INFO||magic==MIX_SECTION_INFO){+while(nr_pages--)+put_page_bootmem(page++);+}else+__free_pages_bootmem(page,order);+}else+free_pages((unsignedlong)page_address(page),order);++/*+*SECTION_INFOpagesandMIX_SECTION_INFOpages+*areallallocatedbybootmem.+*/+if(bootmem){+zone=page_zone(page);+zone_span_writelock(zone);+zone->present_pages+=nr_pages;+zone_span_writeunlock(zone);+totalram_pages+=nr_pages;+}+}++staticvoid__meminitfree_pte_table(pte_t*pte_start,pmd_t*pmd)+{+pte_t*pte;+inti;++for(i=0;i<PTRS_PER_PTE;i++){+pte=pte_start+i;+if(pte_val(*pte))+return;+}++/* free a pte talbe */+free_pagetable(pmd_page(*pmd),0);+spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+}++staticvoid__meminitfree_pmd_table(pmd_t*pmd_start,pud_t*pud)+{+pmd_t*pmd;+inti;++for(i=0;i<PTRS_PER_PMD;i++){+pmd=pmd_start+i;+if(pmd_val(*pmd))+return;+}++/* free a pmd talbe */+free_pagetable(pud_page(*pud),0);+spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+}++/* Return true if pgd is changed, otherwise return false. */+staticbool__meminitfree_pud_table(pud_t*pud_start,pgd_t*pgd)+{+pud_t*pud;+inti;++for(i=0;i<PTRS_PER_PUD;i++){+pud=pud_start+i;+if(pud_val(*pud))+returnfalse;+}++/* free a pud table */+free_pagetable(pgd_page(*pgd),0);+spin_lock(&init_mm.page_table_lock);+pgd_clear(pgd);+spin_unlock(&init_mm.page_table_lock);++returntrue;+}++staticvoid__meminit+remove_pte_table(pte_t*pte_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongnext,pages=0;+pte_t*pte;+void*page_addr;+phys_addr_tphys_addr;++pte=pte_start+pte_index(addr);+for(;addr<end;addr=next,pte++){+next=(addr+PAGE_SIZE)&PAGE_MASK;+if(next>end)+next=end;++if(!pte_present(*pte))+continue;++/*+*Wemapped[0,1G)memoryasidentitymappingwhen+*initializing,inarch/x86/kernel/head_64.S.These+*pagetablescannotberemoved.+*/+phys_addr=pte_val(*pte)+(addr&PAGE_MASK);+if(phys_addr<(phys_addr_t)0x40000000)+return;++if(IS_ALIGNED(addr,PAGE_SIZE)&&+IS_ALIGNED(next,PAGE_SIZE)){+if(!direct){+free_pagetable(pte_page(*pte),0);+pages++;+}++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}else{+/*+*Ifwearenotremovingthewholepage,itmeans+*otherptesinthispagearebeingusedandwecanot+*removethem.Sofilltheunusedpteswith0xFD,and+*removethepagewhenitiswhollyfilledwith0xFD.+*/+memset((void*)addr,PAGE_INUSE,next-addr);+page_addr=page_address(pte_page(*pte));++if(!memchr_inv(page_addr,PAGE_INUSE,PAGE_SIZE)){+free_pagetable(pte_page(*pte),0);+pages++;++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}+}+}++/* Call free_pte_table() in remove_pmd_table(). */+flush_tlb_all();+if(direct)+update_page_count(PG_LEVEL_4K,-pages);+}++staticvoid__meminit+remove_pmd_table(pmd_t*pmd_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpte_phys,next,pages=0;+pte_t*pte_base;+pmd_t*pmd;++pmd=pmd_start+pmd_index(addr);+for(;addr<end;addr=next,pmd++){+next=pmd_addr_end(addr,end);++if(!pmd_present(*pmd))+continue;++if(pmd_large(*pmd)){+if(IS_ALIGNED(addr,PMD_SIZE)&&+IS_ALIGNED(next,PMD_SIZE)){+if(!direct){+free_pagetable(pmd_page(*pmd),+get_order(PMD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse2Mpage,butweneedtoremovepartofthem,+*sosplit2Mpageto4Kpage.+*/+pte_base=(pte_t*)alloc_low_page(&pte_phys);+BUG_ON(!pte_base);+__split_large_page((pte_t*)pmd,addr,+(pte_t*)pte_base);++spin_lock(&init_mm.page_table_lock);+pmd_populate_kernel(&init_mm,pmd,__va(pte_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pte_base=(pte_t*)map_low_page((pte_t*)pmd_page_vaddr(*pmd));+remove_pte_table(pte_base,addr,next,direct);+free_pte_table(pte_base,pmd);+unmap_low_page(pte_base);+}++/* Call free_pmd_table() in remove_pud_table(). */+if(direct)+update_page_count(PG_LEVEL_2M,-pages);+}++staticvoid__meminit+remove_pud_table(pud_t*pud_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpmd_phys,next,pages=0;+pmd_t*pmd_base;+pud_t*pud;++pud=pud_start+pud_index(addr);+for(;addr<end;addr=next,pud++){+next=pud_addr_end(addr,end);++if(!pud_present(*pud))+continue;++if(pud_large(*pud)){+if(IS_ALIGNED(addr,PUD_SIZE)&&+IS_ALIGNED(next,PUD_SIZE)){+if(!direct){+free_pagetable(pud_page(*pud),+get_order(PUD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse1Gpage,butweneedtoremovepartofthem,+*sosplit1Gpageto2Mpage.+*/+pmd_base=(pmd_t*)alloc_low_page(&pmd_phys);+BUG_ON(!pmd_base);+__split_large_page((pte_t*)pud,addr,+(pte_t*)pmd_base);++spin_lock(&init_mm.page_table_lock);+pud_populate(&init_mm,pud,__va(pmd_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pmd_base=(pmd_t*)map_low_page((pmd_t*)pud_page_vaddr(*pud));+remove_pmd_table(pmd_base,addr,next,direct);+free_pmd_table(pmd_base,pud);+unmap_low_page(pmd_base);+}++if(direct)+update_page_count(PG_LEVEL_1G,-pages);+}++/* start and end are both virtual address. */+staticvoid__meminit+remove_pagetable(unsignedlongstart,unsignedlongend,booldirect)+{+unsignedlongnext;+pgd_t*pgd;+pud_t*pud;+boolpgd_changed=false;++for(;start<end;start=next){+pgd=pgd_offset_k(start);+if(!pgd_present(*pgd))+continue;++next=pgd_addr_end(start,end);++pud=(pud_t*)map_low_page((pud_t*)pgd_page_vaddr(*pgd));+remove_pud_table(pud,start,next,direct);+if(free_pud_table(pud,pgd))+pgd_changed=true;+unmap_low_page(pud);+}++if(pgd_changed)+sync_global_pgds(start,end-1);++flush_tlb_all();+}+#ifdef CONFIG_MEMORY_HOTREMOVEint__refarch_remove_memory(u64start,u64size){
--
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
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
quoted
Here is the physical memory hot-remove patch-set based on 3.8rc-2.
Hi Simon,
I'll summarize all the info and answer you later. :)
Thanks for asking. :)
Some questions ask you, not has relationship with this patchset, but is
memory hotplug stuff.
1. In function node_states_check_changes_online:
comments:
* If we don't have HIGHMEM nor movable node,
* node_states[N_NORMAL_MEMORY] contains nodes which have zones of
* 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE.
How to understand it? Why we don't have HIGHMEM nor movable node and
node_staes[N_NORMAL_MEMORY] contains 0...ZONE_MOVABLE, IIUC,
N_NORMAL_MEMORY only means the node has regular memory.
* If we don't have movable node, node_states[N_NORMAL_MEMORY]
* contains nodes which have zones of 0...ZONE_MOVABLE,
* set zone_last to ZONE_MOVABLE.
How to understand?
2. In function move_pfn_range_left, why end<= z2->zone_start_pfn is not
correct? The comments said that must include/overlap, why?
3. In function online_pages, the normal case(w/o online_kenrel,
online_movable), why not check if the new zone is overlap with adjacent
zones?
4. Could you summarize the difference implementation between hot-add and
logic-add, hot-remove and logic-remove?
quoted
This patch-set aims to implement physical memory hot-removing.
The patches can free/remove the following things:
- /sys/firmware/memmap/X/{end, start, type} : [PATCH 4/15]
- memmap of sparse-vmemmap : [PATCH 6,7,8,10/15]
- page table of removed memory : [RFC PATCH 7,8,10/15]
- node and related sysfs files : [RFC PATCH 13-15/15]
Existing problem:
If CONFIG_MEMCG is selected, we will allocate memory to store page cgroup
when we online pages.
For example: there is a memory device on node 1. The address range
is [1G, 1.5G). You will find 4 new directories memory8, memory9, memory10,
and memory11 under the directory /sys/devices/system/memory/.
If CONFIG_MEMCG is selected, when we online memory8, the memory stored page
cgroup is not provided by this memory device. But when we online memory9, the
memory stored page cgroup may be provided by memory8. So we can't offline
memory8 now. We should offline the memory in the reversed order.
When the memory device is hotremoved, we will auto offline memory provided
by this memory device. But we don't know which memory is onlined first, so
offlining memory may fail.
In patch1, we provide a solution which is not good enough:
Iterate twice to offline the memory.
1st iterate: offline every non primary memory block.
2nd iterate: offline primary (i.e. first added) memory block.
And a new idea from Wen Congyang[off-list ref] is:
allocate the memory from the memory block they are describing.
But we are not sure if it is OK to do so because there is not existing API
to do so, and we need to move page_cgroup memory allocation from MEM_GOING_ONLINE
to MEM_ONLINE. And also, it may interfere the hugepage.
How to test this patchset?
1. apply this patchset and build the kernel. MEMORY_HOTPLUG, MEMORY_HOTREMOVE,
ACPI_HOTPLUG_MEMORY must be selected.
2. load the module acpi_memhotplug
3. hotplug the memory device(it depends on your hardware)
You will see the memory device under the directory /sys/bus/acpi/devices/.
Its name is PNP0C80:XX.
4. online/offline pages provided by this memory device
You can write online/offline to /sys/devices/system/memory/memoryX/state to
online/offline pages provided by this memory device
5. hotremove the memory device
You can hotremove the memory device by the hardware, or writing 1 to
/sys/bus/acpi/devices/PNP0C80:XX/eject.
Is there a similar knode to hot-add the memory device?
quoted
Note: if the memory provided by the memory device is used by the kernel, it
can't be offlined. It is not a bug.
Changelogs from v5 to v6:
Patch3: Add some more comments to explain memory hot-remove.
Patch4: Remove bootmem member in struct firmware_map_entry.
Patch6: Repeatedly register bootmem pages when using hugepage.
Patch8: Repeatedly free bootmem pages when using hugepage.
Patch14: Don't free pgdat when offlining a node, just reset it to 0.
Patch15: New patch, pgdat is not freed in patch14, so don't allocate a new
one when online a node.
Changelogs from v4 to v5:
Patch7: new patch, move pgdat_resize_lock into sparse_remove_one_section() to
avoid disabling irq because we need flush tlb when free pagetables.
Patch8: new patch, pick up some common APIs that are used to free direct mapping
and vmemmap pagetables.
Patch9: free direct mapping pagetables on x86_64 arch.
Patch10: free vmemmap pagetables.
Patch11: since freeing memmap with vmemmap has been implemented, the config
macro CONFIG_SPARSEMEM_VMEMMAP when defining __remove_section() is
no longer needed.
Patch13: no need to modify acpi_memory_disable_device() since it was removed,
and add nid parameter when calling remove_memory().
Changelogs from v3 to v4:
Patch7: remove unused codes.
Patch8: fix nr_pages that is passed to free_map_bootmem()
Changelogs from v2 to v3:
Patch9: call sync_global_pgds() if pgd is changed
Patch10: fix a problem int the patch
Changelogs from v1 to v2:
Patch1: new patch, offline memory twice. 1st iterate: offline every non primary
memory block. 2nd iterate: offline primary (i.e. first added) memory
block.
Patch3: new patch, no logical change, just remove reduntant codes.
Patch9: merge the patch from wujianguo into this patch. flush tlb on all cpu
after the pagetable is changed.
Patch12: new patch, free node_data when a node is offlined.
Tang Chen (6):
memory-hotplug: move pgdat_resize_lock into
sparse_remove_one_section()
memory-hotplug: remove page table of x86_64 architecture
memory-hotplug: remove memmap of sparse-vmemmap
memory-hotplug: Integrated __remove_section() of
CONFIG_SPARSEMEM_VMEMMAP.
memory-hotplug: remove sysfs file of node
memory-hotplug: Do not allocate pdgat if it was not freed when
offline.
Wen Congyang (5):
memory-hotplug: try to offline the memory twice to avoid dependence
memory-hotplug: remove redundant codes
memory-hotplug: introduce new function arch_remove_memory() for
removing page table depends on architecture
memory-hotplug: Common APIs to support page tables hot-remove
memory-hotplug: free node_data when a node is offlined
Yasuaki Ishimatsu (4):
memory-hotplug: check whether all memory blocks are offlined or not
when removing memory
memory-hotplug: remove /sys/firmware/memmap/X sysfs
memory-hotplug: implement register_page_bootmem_info_section of
sparse-vmemmap
memory-hotplug: memory_hotplug: clear zone when removing the memory
arch/arm64/mm/mmu.c | 3 +
arch/ia64/mm/discontig.c | 10 +
arch/ia64/mm/init.c | 18 ++
arch/powerpc/mm/init_64.c | 10 +
arch/powerpc/mm/mem.c | 12 +
arch/s390/mm/init.c | 12 +
arch/s390/mm/vmem.c | 10 +
arch/sh/mm/init.c | 17 ++
arch/sparc/mm/init_64.c | 10 +
arch/tile/mm/init.c | 8 +
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_32.c | 12 +
arch/x86/mm/init_64.c | 390 +++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 ++--
drivers/acpi/acpi_memhotplug.c | 8 +-
drivers/base/memory.c | 6 +
drivers/firmware/memmap.c | 96 +++++++-
include/linux/bootmem.h | 1 +
include/linux/firmware-map.h | 6 +
include/linux/memory_hotplug.h | 15 +-
include/linux/mm.h | 4 +-
mm/memory_hotplug.c | 459 +++++++++++++++++++++++++++++++---
mm/sparse.c | 8 +-
23 files changed, 1094 insertions(+), 69 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email:<a href=mailto:"dont@kvack.org"> email@kvack.org</a>
From: Simon Jeons <hidden> Date: 2013-01-30 02:48:49
On Wed, 2013-01-30 at 10:32 +0800, Tang Chen wrote:
On 01/29/2013 08:52 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
quoted
Here is the physical memory hot-remove patch-set based on 3.8rc-2.
Hi Simon,
I'll summarize all the info and answer you later. :)
Thanks for asking. :)
Thanks Tang, IIRC, there's qemu feature support memory hot-add/remove
emulation if we don't have machine which supports memory hot-add/remove
to test. Is that qemu feature merged? Otherwise where can I get that
patchset?
quoted
Some questions ask you, not has relationship with this patchset, but is
memory hotplug stuff.
1. In function node_states_check_changes_online:
comments:
* If we don't have HIGHMEM nor movable node,
* node_states[N_NORMAL_MEMORY] contains nodes which have zones of
* 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE.
How to understand it? Why we don't have HIGHMEM nor movable node and
node_staes[N_NORMAL_MEMORY] contains 0...ZONE_MOVABLE, IIUC,
N_NORMAL_MEMORY only means the node has regular memory.
* If we don't have movable node, node_states[N_NORMAL_MEMORY]
* contains nodes which have zones of 0...ZONE_MOVABLE,
* set zone_last to ZONE_MOVABLE.
How to understand?
2. In function move_pfn_range_left, why end<= z2->zone_start_pfn is not
correct? The comments said that must include/overlap, why?
3. In function online_pages, the normal case(w/o online_kenrel,
online_movable), why not check if the new zone is overlap with adjacent
zones?
4. Could you summarize the difference implementation between hot-add and
logic-add, hot-remove and logic-remove?
quoted
This patch-set aims to implement physical memory hot-removing.
The patches can free/remove the following things:
- /sys/firmware/memmap/X/{end, start, type} : [PATCH 4/15]
- memmap of sparse-vmemmap : [PATCH 6,7,8,10/15]
- page table of removed memory : [RFC PATCH 7,8,10/15]
- node and related sysfs files : [RFC PATCH 13-15/15]
Existing problem:
If CONFIG_MEMCG is selected, we will allocate memory to store page cgroup
when we online pages.
For example: there is a memory device on node 1. The address range
is [1G, 1.5G). You will find 4 new directories memory8, memory9, memory10,
and memory11 under the directory /sys/devices/system/memory/.
If CONFIG_MEMCG is selected, when we online memory8, the memory stored page
cgroup is not provided by this memory device. But when we online memory9, the
memory stored page cgroup may be provided by memory8. So we can't offline
memory8 now. We should offline the memory in the reversed order.
When the memory device is hotremoved, we will auto offline memory provided
by this memory device. But we don't know which memory is onlined first, so
offlining memory may fail.
In patch1, we provide a solution which is not good enough:
Iterate twice to offline the memory.
1st iterate: offline every non primary memory block.
2nd iterate: offline primary (i.e. first added) memory block.
And a new idea from Wen Congyang[off-list ref] is:
allocate the memory from the memory block they are describing.
But we are not sure if it is OK to do so because there is not existing API
to do so, and we need to move page_cgroup memory allocation from MEM_GOING_ONLINE
to MEM_ONLINE. And also, it may interfere the hugepage.
How to test this patchset?
1. apply this patchset and build the kernel. MEMORY_HOTPLUG, MEMORY_HOTREMOVE,
ACPI_HOTPLUG_MEMORY must be selected.
2. load the module acpi_memhotplug
3. hotplug the memory device(it depends on your hardware)
You will see the memory device under the directory /sys/bus/acpi/devices/.
Its name is PNP0C80:XX.
4. online/offline pages provided by this memory device
You can write online/offline to /sys/devices/system/memory/memoryX/state to
online/offline pages provided by this memory device
5. hotremove the memory device
You can hotremove the memory device by the hardware, or writing 1 to
/sys/bus/acpi/devices/PNP0C80:XX/eject.
Is there a similar knode to hot-add the memory device?
quoted
Note: if the memory provided by the memory device is used by the kernel, it
can't be offlined. It is not a bug.
Changelogs from v5 to v6:
Patch3: Add some more comments to explain memory hot-remove.
Patch4: Remove bootmem member in struct firmware_map_entry.
Patch6: Repeatedly register bootmem pages when using hugepage.
Patch8: Repeatedly free bootmem pages when using hugepage.
Patch14: Don't free pgdat when offlining a node, just reset it to 0.
Patch15: New patch, pgdat is not freed in patch14, so don't allocate a new
one when online a node.
Changelogs from v4 to v5:
Patch7: new patch, move pgdat_resize_lock into sparse_remove_one_section() to
avoid disabling irq because we need flush tlb when free pagetables.
Patch8: new patch, pick up some common APIs that are used to free direct mapping
and vmemmap pagetables.
Patch9: free direct mapping pagetables on x86_64 arch.
Patch10: free vmemmap pagetables.
Patch11: since freeing memmap with vmemmap has been implemented, the config
macro CONFIG_SPARSEMEM_VMEMMAP when defining __remove_section() is
no longer needed.
Patch13: no need to modify acpi_memory_disable_device() since it was removed,
and add nid parameter when calling remove_memory().
Changelogs from v3 to v4:
Patch7: remove unused codes.
Patch8: fix nr_pages that is passed to free_map_bootmem()
Changelogs from v2 to v3:
Patch9: call sync_global_pgds() if pgd is changed
Patch10: fix a problem int the patch
Changelogs from v1 to v2:
Patch1: new patch, offline memory twice. 1st iterate: offline every non primary
memory block. 2nd iterate: offline primary (i.e. first added) memory
block.
Patch3: new patch, no logical change, just remove reduntant codes.
Patch9: merge the patch from wujianguo into this patch. flush tlb on all cpu
after the pagetable is changed.
Patch12: new patch, free node_data when a node is offlined.
Tang Chen (6):
memory-hotplug: move pgdat_resize_lock into
sparse_remove_one_section()
memory-hotplug: remove page table of x86_64 architecture
memory-hotplug: remove memmap of sparse-vmemmap
memory-hotplug: Integrated __remove_section() of
CONFIG_SPARSEMEM_VMEMMAP.
memory-hotplug: remove sysfs file of node
memory-hotplug: Do not allocate pdgat if it was not freed when
offline.
Wen Congyang (5):
memory-hotplug: try to offline the memory twice to avoid dependence
memory-hotplug: remove redundant codes
memory-hotplug: introduce new function arch_remove_memory() for
removing page table depends on architecture
memory-hotplug: Common APIs to support page tables hot-remove
memory-hotplug: free node_data when a node is offlined
Yasuaki Ishimatsu (4):
memory-hotplug: check whether all memory blocks are offlined or not
when removing memory
memory-hotplug: remove /sys/firmware/memmap/X sysfs
memory-hotplug: implement register_page_bootmem_info_section of
sparse-vmemmap
memory-hotplug: memory_hotplug: clear zone when removing the memory
arch/arm64/mm/mmu.c | 3 +
arch/ia64/mm/discontig.c | 10 +
arch/ia64/mm/init.c | 18 ++
arch/powerpc/mm/init_64.c | 10 +
arch/powerpc/mm/mem.c | 12 +
arch/s390/mm/init.c | 12 +
arch/s390/mm/vmem.c | 10 +
arch/sh/mm/init.c | 17 ++
arch/sparc/mm/init_64.c | 10 +
arch/tile/mm/init.c | 8 +
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_32.c | 12 +
arch/x86/mm/init_64.c | 390 +++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 ++--
drivers/acpi/acpi_memhotplug.c | 8 +-
drivers/base/memory.c | 6 +
drivers/firmware/memmap.c | 96 +++++++-
include/linux/bootmem.h | 1 +
include/linux/firmware-map.h | 6 +
include/linux/memory_hotplug.h | 15 +-
include/linux/mm.h | 4 +-
mm/memory_hotplug.c | 459 +++++++++++++++++++++++++++++++---
mm/sparse.c | 8 +-
23 files changed, 1094 insertions(+), 69 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email:<a href=mailto:"dont@kvack.org"> email@kvack.org</a>
On Wed, 2013-01-30 at 10:32 +0800, Tang Chen wrote:
quoted
On 01/29/2013 08:52 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
quoted
Here is the physical memory hot-remove patch-set based on 3.8rc-2.
Hi Simon,
I'll summarize all the info and answer you later. :)
Thanks for asking. :)
Thanks Tang, IIRC, there's qemu feature support memory hot-add/remove
emulation if we don't have machine which supports memory hot-add/remove
to test. Is that qemu feature merged? Otherwise where can I get that
patchset?
Hi Simon,
There are patches to support hot-add/remove in qemu, but they are not
merged yet.
You can get the latest patches here:
http://lists.nongnu.org/archive/html/qemu-devel/2012-12/msg02693.html
BTY, it is unstable and full of problems, and you need to compile your
own seabios too.
Thanks. :)
quoted
quoted
Some questions ask you, not has relationship with this patchset, but is
memory hotplug stuff.
1. In function node_states_check_changes_online:
comments:
* If we don't have HIGHMEM nor movable node,
* node_states[N_NORMAL_MEMORY] contains nodes which have zones of
* 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE.
How to understand it? Why we don't have HIGHMEM nor movable node and
node_staes[N_NORMAL_MEMORY] contains 0...ZONE_MOVABLE, IIUC,
N_NORMAL_MEMORY only means the node has regular memory.
* If we don't have movable node, node_states[N_NORMAL_MEMORY]
* contains nodes which have zones of 0...ZONE_MOVABLE,
* set zone_last to ZONE_MOVABLE.
How to understand?
2. In function move_pfn_range_left, why end<= z2->zone_start_pfn is not
correct? The comments said that must include/overlap, why?
3. In function online_pages, the normal case(w/o online_kenrel,
online_movable), why not check if the new zone is overlap with adjacent
zones?
4. Could you summarize the difference implementation between hot-add and
logic-add, hot-remove and logic-remove?
quoted
This patch-set aims to implement physical memory hot-removing.
The patches can free/remove the following things:
- /sys/firmware/memmap/X/{end, start, type} : [PATCH 4/15]
- memmap of sparse-vmemmap : [PATCH 6,7,8,10/15]
- page table of removed memory : [RFC PATCH 7,8,10/15]
- node and related sysfs files : [RFC PATCH 13-15/15]
Existing problem:
If CONFIG_MEMCG is selected, we will allocate memory to store page cgroup
when we online pages.
For example: there is a memory device on node 1. The address range
is [1G, 1.5G). You will find 4 new directories memory8, memory9, memory10,
and memory11 under the directory /sys/devices/system/memory/.
If CONFIG_MEMCG is selected, when we online memory8, the memory stored page
cgroup is not provided by this memory device. But when we online memory9, the
memory stored page cgroup may be provided by memory8. So we can't offline
memory8 now. We should offline the memory in the reversed order.
When the memory device is hotremoved, we will auto offline memory provided
by this memory device. But we don't know which memory is onlined first, so
offlining memory may fail.
In patch1, we provide a solution which is not good enough:
Iterate twice to offline the memory.
1st iterate: offline every non primary memory block.
2nd iterate: offline primary (i.e. first added) memory block.
And a new idea from Wen Congyang[off-list ref] is:
allocate the memory from the memory block they are describing.
But we are not sure if it is OK to do so because there is not existing API
to do so, and we need to move page_cgroup memory allocation from MEM_GOING_ONLINE
to MEM_ONLINE. And also, it may interfere the hugepage.
How to test this patchset?
1. apply this patchset and build the kernel. MEMORY_HOTPLUG, MEMORY_HOTREMOVE,
ACPI_HOTPLUG_MEMORY must be selected.
2. load the module acpi_memhotplug
3. hotplug the memory device(it depends on your hardware)
You will see the memory device under the directory /sys/bus/acpi/devices/.
Its name is PNP0C80:XX.
4. online/offline pages provided by this memory device
You can write online/offline to /sys/devices/system/memory/memoryX/state to
online/offline pages provided by this memory device
5. hotremove the memory device
You can hotremove the memory device by the hardware, or writing 1 to
/sys/bus/acpi/devices/PNP0C80:XX/eject.
Is there a similar knode to hot-add the memory device?
quoted
Note: if the memory provided by the memory device is used by the kernel, it
can't be offlined. It is not a bug.
Changelogs from v5 to v6:
Patch3: Add some more comments to explain memory hot-remove.
Patch4: Remove bootmem member in struct firmware_map_entry.
Patch6: Repeatedly register bootmem pages when using hugepage.
Patch8: Repeatedly free bootmem pages when using hugepage.
Patch14: Don't free pgdat when offlining a node, just reset it to 0.
Patch15: New patch, pgdat is not freed in patch14, so don't allocate a new
one when online a node.
Changelogs from v4 to v5:
Patch7: new patch, move pgdat_resize_lock into sparse_remove_one_section() to
avoid disabling irq because we need flush tlb when free pagetables.
Patch8: new patch, pick up some common APIs that are used to free direct mapping
and vmemmap pagetables.
Patch9: free direct mapping pagetables on x86_64 arch.
Patch10: free vmemmap pagetables.
Patch11: since freeing memmap with vmemmap has been implemented, the config
macro CONFIG_SPARSEMEM_VMEMMAP when defining __remove_section() is
no longer needed.
Patch13: no need to modify acpi_memory_disable_device() since it was removed,
and add nid parameter when calling remove_memory().
Changelogs from v3 to v4:
Patch7: remove unused codes.
Patch8: fix nr_pages that is passed to free_map_bootmem()
Changelogs from v2 to v3:
Patch9: call sync_global_pgds() if pgd is changed
Patch10: fix a problem int the patch
Changelogs from v1 to v2:
Patch1: new patch, offline memory twice. 1st iterate: offline every non primary
memory block. 2nd iterate: offline primary (i.e. first added) memory
block.
Patch3: new patch, no logical change, just remove reduntant codes.
Patch9: merge the patch from wujianguo into this patch. flush tlb on all cpu
after the pagetable is changed.
Patch12: new patch, free node_data when a node is offlined.
Tang Chen (6):
memory-hotplug: move pgdat_resize_lock into
sparse_remove_one_section()
memory-hotplug: remove page table of x86_64 architecture
memory-hotplug: remove memmap of sparse-vmemmap
memory-hotplug: Integrated __remove_section() of
CONFIG_SPARSEMEM_VMEMMAP.
memory-hotplug: remove sysfs file of node
memory-hotplug: Do not allocate pdgat if it was not freed when
offline.
Wen Congyang (5):
memory-hotplug: try to offline the memory twice to avoid dependence
memory-hotplug: remove redundant codes
memory-hotplug: introduce new function arch_remove_memory() for
removing page table depends on architecture
memory-hotplug: Common APIs to support page tables hot-remove
memory-hotplug: free node_data when a node is offlined
Yasuaki Ishimatsu (4):
memory-hotplug: check whether all memory blocks are offlined or not
when removing memory
memory-hotplug: remove /sys/firmware/memmap/X sysfs
memory-hotplug: implement register_page_bootmem_info_section of
sparse-vmemmap
memory-hotplug: memory_hotplug: clear zone when removing the memory
arch/arm64/mm/mmu.c | 3 +
arch/ia64/mm/discontig.c | 10 +
arch/ia64/mm/init.c | 18 ++
arch/powerpc/mm/init_64.c | 10 +
arch/powerpc/mm/mem.c | 12 +
arch/s390/mm/init.c | 12 +
arch/s390/mm/vmem.c | 10 +
arch/sh/mm/init.c | 17 ++
arch/sparc/mm/init_64.c | 10 +
arch/tile/mm/init.c | 8 +
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_32.c | 12 +
arch/x86/mm/init_64.c | 390 +++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 ++--
drivers/acpi/acpi_memhotplug.c | 8 +-
drivers/base/memory.c | 6 +
drivers/firmware/memmap.c | 96 +++++++-
include/linux/bootmem.h | 1 +
include/linux/firmware-map.h | 6 +
include/linux/memory_hotplug.h | 15 +-
include/linux/mm.h | 4 +-
mm/memory_hotplug.c | 459 +++++++++++++++++++++++++++++++---
mm/sparse.c | 8 +-
23 files changed, 1094 insertions(+), 69 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email:<a href=mailto:"dont@kvack.org"> email@kvack.org</a>
--
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: Simon Jeons <hidden> Date: 2013-01-30 03:27:15
On Wed, 2013-01-30 at 10:16 +0800, Tang Chen wrote:
On 01/29/2013 09:04 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
quoted
From: Wen Congyang<redacted>
When memory is removed, the corresponding pagetables should alse be removed.
This patch introduces some common APIs to support vmemmap pagetable and x86_64
architecture pagetable removing.
Why don't need to build_all_zonelists like online_pages does during
hot-add path(add_memory)?
Hi Simon,
As you said, build_all_zonelists is done by online_pages. When the
memory device
is hot-added, we cannot use it. we can only use is when we online the
pages on it.
Why?
If a node has just one memory device and memory is small, some zone will
not present like zone_highmem, then hot-add another memory device and
zone_highmem appear, if you should build_all_zonelists this time?
But we can online the pages as different types, kernel or movable (which
belongs to
different zones), and we can online part of the memory, not all of them.
So each time we online some pages, we should check if we need to update
the zone list.
So I think that is why we do build_all_zonelists when online_pages.
(just my opinion)
Thanks. :)
quoted
quoted
All pages of virtual mapping in removed memory cannot be freedi if some pages
used as PGD/PUD includes not only removed memory but also other memory. So the
patch uses the following way 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.
Signed-off-by: Yasuaki Ishimatsu<redacted>
Signed-off-by: Jianguo Wu<redacted>
Signed-off-by: Wen Congyang<redacted>
Signed-off-by: Tang Chen<redacted>
---
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_64.c | 299 ++++++++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 +++---
include/linux/bootmem.h | 1 +
4 files changed, 326 insertions(+), 22 deletions(-)
@@ -682,6 +682,305 @@ int arch_add_memory(int nid, u64 start, u64 size)}EXPORT_SYMBOL_GPL(arch_add_memory);+#define PAGE_INUSE 0xFD++staticvoid__meminitfree_pagetable(structpage*page,intorder)+{+structzone*zone;+boolbootmem=false;+unsignedlongmagic;+unsignedintnr_pages=1<<order;++/* bootmem page has reserved flag */+if(PageReserved(page)){+__ClearPageReserved(page);+bootmem=true;++magic=(unsignedlong)page->lru.next;+if(magic==SECTION_INFO||magic==MIX_SECTION_INFO){+while(nr_pages--)+put_page_bootmem(page++);+}else+__free_pages_bootmem(page,order);+}else+free_pages((unsignedlong)page_address(page),order);++/*+*SECTION_INFOpagesandMIX_SECTION_INFOpages+*areallallocatedbybootmem.+*/+if(bootmem){+zone=page_zone(page);+zone_span_writelock(zone);+zone->present_pages+=nr_pages;+zone_span_writeunlock(zone);+totalram_pages+=nr_pages;+}+}++staticvoid__meminitfree_pte_table(pte_t*pte_start,pmd_t*pmd)+{+pte_t*pte;+inti;++for(i=0;i<PTRS_PER_PTE;i++){+pte=pte_start+i;+if(pte_val(*pte))+return;+}++/* free a pte talbe */+free_pagetable(pmd_page(*pmd),0);+spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+}++staticvoid__meminitfree_pmd_table(pmd_t*pmd_start,pud_t*pud)+{+pmd_t*pmd;+inti;++for(i=0;i<PTRS_PER_PMD;i++){+pmd=pmd_start+i;+if(pmd_val(*pmd))+return;+}++/* free a pmd talbe */+free_pagetable(pud_page(*pud),0);+spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+}++/* Return true if pgd is changed, otherwise return false. */+staticbool__meminitfree_pud_table(pud_t*pud_start,pgd_t*pgd)+{+pud_t*pud;+inti;++for(i=0;i<PTRS_PER_PUD;i++){+pud=pud_start+i;+if(pud_val(*pud))+returnfalse;+}++/* free a pud table */+free_pagetable(pgd_page(*pgd),0);+spin_lock(&init_mm.page_table_lock);+pgd_clear(pgd);+spin_unlock(&init_mm.page_table_lock);++returntrue;+}++staticvoid__meminit+remove_pte_table(pte_t*pte_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongnext,pages=0;+pte_t*pte;+void*page_addr;+phys_addr_tphys_addr;++pte=pte_start+pte_index(addr);+for(;addr<end;addr=next,pte++){+next=(addr+PAGE_SIZE)&PAGE_MASK;+if(next>end)+next=end;++if(!pte_present(*pte))+continue;++/*+*Wemapped[0,1G)memoryasidentitymappingwhen+*initializing,inarch/x86/kernel/head_64.S.These+*pagetablescannotberemoved.+*/+phys_addr=pte_val(*pte)+(addr&PAGE_MASK);+if(phys_addr<(phys_addr_t)0x40000000)+return;++if(IS_ALIGNED(addr,PAGE_SIZE)&&+IS_ALIGNED(next,PAGE_SIZE)){+if(!direct){+free_pagetable(pte_page(*pte),0);+pages++;+}++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}else{+/*+*Ifwearenotremovingthewholepage,itmeans+*otherptesinthispagearebeingusedandwecanot+*removethem.Sofilltheunusedpteswith0xFD,and+*removethepagewhenitiswhollyfilledwith0xFD.+*/+memset((void*)addr,PAGE_INUSE,next-addr);+page_addr=page_address(pte_page(*pte));++if(!memchr_inv(page_addr,PAGE_INUSE,PAGE_SIZE)){+free_pagetable(pte_page(*pte),0);+pages++;++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}+}+}++/* Call free_pte_table() in remove_pmd_table(). */+flush_tlb_all();+if(direct)+update_page_count(PG_LEVEL_4K,-pages);+}++staticvoid__meminit+remove_pmd_table(pmd_t*pmd_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpte_phys,next,pages=0;+pte_t*pte_base;+pmd_t*pmd;++pmd=pmd_start+pmd_index(addr);+for(;addr<end;addr=next,pmd++){+next=pmd_addr_end(addr,end);++if(!pmd_present(*pmd))+continue;++if(pmd_large(*pmd)){+if(IS_ALIGNED(addr,PMD_SIZE)&&+IS_ALIGNED(next,PMD_SIZE)){+if(!direct){+free_pagetable(pmd_page(*pmd),+get_order(PMD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse2Mpage,butweneedtoremovepartofthem,+*sosplit2Mpageto4Kpage.+*/+pte_base=(pte_t*)alloc_low_page(&pte_phys);+BUG_ON(!pte_base);+__split_large_page((pte_t*)pmd,addr,+(pte_t*)pte_base);++spin_lock(&init_mm.page_table_lock);+pmd_populate_kernel(&init_mm,pmd,__va(pte_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pte_base=(pte_t*)map_low_page((pte_t*)pmd_page_vaddr(*pmd));+remove_pte_table(pte_base,addr,next,direct);+free_pte_table(pte_base,pmd);+unmap_low_page(pte_base);+}++/* Call free_pmd_table() in remove_pud_table(). */+if(direct)+update_page_count(PG_LEVEL_2M,-pages);+}++staticvoid__meminit+remove_pud_table(pud_t*pud_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpmd_phys,next,pages=0;+pmd_t*pmd_base;+pud_t*pud;++pud=pud_start+pud_index(addr);+for(;addr<end;addr=next,pud++){+next=pud_addr_end(addr,end);++if(!pud_present(*pud))+continue;++if(pud_large(*pud)){+if(IS_ALIGNED(addr,PUD_SIZE)&&+IS_ALIGNED(next,PUD_SIZE)){+if(!direct){+free_pagetable(pud_page(*pud),+get_order(PUD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse1Gpage,butweneedtoremovepartofthem,+*sosplit1Gpageto2Mpage.+*/+pmd_base=(pmd_t*)alloc_low_page(&pmd_phys);+BUG_ON(!pmd_base);+__split_large_page((pte_t*)pud,addr,+(pte_t*)pmd_base);++spin_lock(&init_mm.page_table_lock);+pud_populate(&init_mm,pud,__va(pmd_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pmd_base=(pmd_t*)map_low_page((pmd_t*)pud_page_vaddr(*pud));+remove_pmd_table(pmd_base,addr,next,direct);+free_pmd_table(pmd_base,pud);+unmap_low_page(pmd_base);+}++if(direct)+update_page_count(PG_LEVEL_1G,-pages);+}++/* start and end are both virtual address. */+staticvoid__meminit+remove_pagetable(unsignedlongstart,unsignedlongend,booldirect)+{+unsignedlongnext;+pgd_t*pgd;+pud_t*pud;+boolpgd_changed=false;++for(;start<end;start=next){+pgd=pgd_offset_k(start);+if(!pgd_present(*pgd))+continue;++next=pgd_addr_end(start,end);++pud=(pud_t*)map_low_page((pud_t*)pgd_page_vaddr(*pgd));+remove_pud_table(pud,start,next,direct);+if(free_pud_table(pud,pgd))+pgd_changed=true;+unmap_low_page(pud);+}++if(pgd_changed)+sync_global_pgds(start,end-1);++flush_tlb_all();+}+#ifdef CONFIG_MEMORY_HOTREMOVEint__refarch_remove_memory(u64start,u64size){
--
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
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
On Wed, 2013-01-30 at 10:16 +0800, Tang Chen wrote:
quoted
On 01/29/2013 09:04 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
quoted
From: Wen Congyang<redacted>
When memory is removed, the corresponding pagetables should alse be removed.
This patch introduces some common APIs to support vmemmap pagetable and x86_64
architecture pagetable removing.
Why don't need to build_all_zonelists like online_pages does during
hot-add path(add_memory)?
Hi Simon,
As you said, build_all_zonelists is done by online_pages. When the
memory device
is hot-added, we cannot use it. we can only use is when we online the
pages on it.
Why?
If a node has just one memory device and memory is small, some zone will
not present like zone_highmem, then hot-add another memory device and
zone_highmem appear, if you should build_all_zonelists this time?
Hi Simon,
We built zone list when the first memory on the node is hot-added.
add_memory()
|-->if (!node_online(nid)) hotadd_new_pgdat()
|-->free_area_init_node()
|-->build_all_zonelists()
All the zones on the new node will be initialized as empty. So here, we
build zone list.
But actually we did nothing because no page is online, and zones are empty.
In build_zonelists_node(), populated_zone(zone) will always be false.
The real work of building zone list is when pages are online. :)
And in your question, you said some small memory is there, and
zone_normal is present.
OK, when these pages are onlined (not added), the zone list has been
rebuilt.
But pages in zone_highmem is not added, which means not onlined, so we
don't need to
build zone list for it. And later, the zone_highmem pages are added, we
still don't
rebuild the zone list because the real rebuilding work is when the pages
are onlined.
I think this is the current logic. :)
Thanks. :)
quoted
But we can online the pages as different types, kernel or movable (which
belongs to
different zones), and we can online part of the memory, not all of them.
So each time we online some pages, we should check if we need to update
the zone list.
So I think that is why we do build_all_zonelists when online_pages.
(just my opinion)
Thanks. :)
quoted
quoted
All pages of virtual mapping in removed memory cannot be freedi if some pages
used as PGD/PUD includes not only removed memory but also other memory. So the
patch uses the following way 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.
Signed-off-by: Yasuaki Ishimatsu<redacted>
Signed-off-by: Jianguo Wu<redacted>
Signed-off-by: Wen Congyang<redacted>
Signed-off-by: Tang Chen<redacted>
---
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_64.c | 299 ++++++++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 +++---
include/linux/bootmem.h | 1 +
4 files changed, 326 insertions(+), 22 deletions(-)
@@ -682,6 +682,305 @@ int arch_add_memory(int nid, u64 start, u64 size)}EXPORT_SYMBOL_GPL(arch_add_memory);+#define PAGE_INUSE 0xFD++staticvoid__meminitfree_pagetable(structpage*page,intorder)+{+structzone*zone;+boolbootmem=false;+unsignedlongmagic;+unsignedintnr_pages=1<<order;++/* bootmem page has reserved flag */+if(PageReserved(page)){+__ClearPageReserved(page);+bootmem=true;++magic=(unsignedlong)page->lru.next;+if(magic==SECTION_INFO||magic==MIX_SECTION_INFO){+while(nr_pages--)+put_page_bootmem(page++);+}else+__free_pages_bootmem(page,order);+}else+free_pages((unsignedlong)page_address(page),order);++/*+*SECTION_INFOpagesandMIX_SECTION_INFOpages+*areallallocatedbybootmem.+*/+if(bootmem){+zone=page_zone(page);+zone_span_writelock(zone);+zone->present_pages+=nr_pages;+zone_span_writeunlock(zone);+totalram_pages+=nr_pages;+}+}++staticvoid__meminitfree_pte_table(pte_t*pte_start,pmd_t*pmd)+{+pte_t*pte;+inti;++for(i=0;i<PTRS_PER_PTE;i++){+pte=pte_start+i;+if(pte_val(*pte))+return;+}++/* free a pte talbe */+free_pagetable(pmd_page(*pmd),0);+spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+}++staticvoid__meminitfree_pmd_table(pmd_t*pmd_start,pud_t*pud)+{+pmd_t*pmd;+inti;++for(i=0;i<PTRS_PER_PMD;i++){+pmd=pmd_start+i;+if(pmd_val(*pmd))+return;+}++/* free a pmd talbe */+free_pagetable(pud_page(*pud),0);+spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+}++/* Return true if pgd is changed, otherwise return false. */+staticbool__meminitfree_pud_table(pud_t*pud_start,pgd_t*pgd)+{+pud_t*pud;+inti;++for(i=0;i<PTRS_PER_PUD;i++){+pud=pud_start+i;+if(pud_val(*pud))+returnfalse;+}++/* free a pud table */+free_pagetable(pgd_page(*pgd),0);+spin_lock(&init_mm.page_table_lock);+pgd_clear(pgd);+spin_unlock(&init_mm.page_table_lock);++returntrue;+}++staticvoid__meminit+remove_pte_table(pte_t*pte_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongnext,pages=0;+pte_t*pte;+void*page_addr;+phys_addr_tphys_addr;++pte=pte_start+pte_index(addr);+for(;addr<end;addr=next,pte++){+next=(addr+PAGE_SIZE)&PAGE_MASK;+if(next>end)+next=end;++if(!pte_present(*pte))+continue;++/*+*Wemapped[0,1G)memoryasidentitymappingwhen+*initializing,inarch/x86/kernel/head_64.S.These+*pagetablescannotberemoved.+*/+phys_addr=pte_val(*pte)+(addr&PAGE_MASK);+if(phys_addr<(phys_addr_t)0x40000000)+return;++if(IS_ALIGNED(addr,PAGE_SIZE)&&+IS_ALIGNED(next,PAGE_SIZE)){+if(!direct){+free_pagetable(pte_page(*pte),0);+pages++;+}++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}else{+/*+*Ifwearenotremovingthewholepage,itmeans+*otherptesinthispagearebeingusedandwecanot+*removethem.Sofilltheunusedpteswith0xFD,and+*removethepagewhenitiswhollyfilledwith0xFD.+*/+memset((void*)addr,PAGE_INUSE,next-addr);+page_addr=page_address(pte_page(*pte));++if(!memchr_inv(page_addr,PAGE_INUSE,PAGE_SIZE)){+free_pagetable(pte_page(*pte),0);+pages++;++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}+}+}++/* Call free_pte_table() in remove_pmd_table(). */+flush_tlb_all();+if(direct)+update_page_count(PG_LEVEL_4K,-pages);+}++staticvoid__meminit+remove_pmd_table(pmd_t*pmd_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpte_phys,next,pages=0;+pte_t*pte_base;+pmd_t*pmd;++pmd=pmd_start+pmd_index(addr);+for(;addr<end;addr=next,pmd++){+next=pmd_addr_end(addr,end);++if(!pmd_present(*pmd))+continue;++if(pmd_large(*pmd)){+if(IS_ALIGNED(addr,PMD_SIZE)&&+IS_ALIGNED(next,PMD_SIZE)){+if(!direct){+free_pagetable(pmd_page(*pmd),+get_order(PMD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse2Mpage,butweneedtoremovepartofthem,+*sosplit2Mpageto4Kpage.+*/+pte_base=(pte_t*)alloc_low_page(&pte_phys);+BUG_ON(!pte_base);+__split_large_page((pte_t*)pmd,addr,+(pte_t*)pte_base);++spin_lock(&init_mm.page_table_lock);+pmd_populate_kernel(&init_mm,pmd,__va(pte_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pte_base=(pte_t*)map_low_page((pte_t*)pmd_page_vaddr(*pmd));+remove_pte_table(pte_base,addr,next,direct);+free_pte_table(pte_base,pmd);+unmap_low_page(pte_base);+}++/* Call free_pmd_table() in remove_pud_table(). */+if(direct)+update_page_count(PG_LEVEL_2M,-pages);+}++staticvoid__meminit+remove_pud_table(pud_t*pud_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpmd_phys,next,pages=0;+pmd_t*pmd_base;+pud_t*pud;++pud=pud_start+pud_index(addr);+for(;addr<end;addr=next,pud++){+next=pud_addr_end(addr,end);++if(!pud_present(*pud))+continue;++if(pud_large(*pud)){+if(IS_ALIGNED(addr,PUD_SIZE)&&+IS_ALIGNED(next,PUD_SIZE)){+if(!direct){+free_pagetable(pud_page(*pud),+get_order(PUD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse1Gpage,butweneedtoremovepartofthem,+*sosplit1Gpageto2Mpage.+*/+pmd_base=(pmd_t*)alloc_low_page(&pmd_phys);+BUG_ON(!pmd_base);+__split_large_page((pte_t*)pud,addr,+(pte_t*)pmd_base);++spin_lock(&init_mm.page_table_lock);+pud_populate(&init_mm,pud,__va(pmd_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pmd_base=(pmd_t*)map_low_page((pmd_t*)pud_page_vaddr(*pud));+remove_pmd_table(pmd_base,addr,next,direct);+free_pmd_table(pmd_base,pud);+unmap_low_page(pmd_base);+}++if(direct)+update_page_count(PG_LEVEL_1G,-pages);+}++/* start and end are both virtual address. */+staticvoid__meminit+remove_pagetable(unsignedlongstart,unsignedlongend,booldirect)+{+unsignedlongnext;+pgd_t*pgd;+pud_t*pud;+boolpgd_changed=false;++for(;start<end;start=next){+pgd=pgd_offset_k(start);+if(!pgd_present(*pgd))+continue;++next=pgd_addr_end(start,end);++pud=(pud_t*)map_low_page((pud_t*)pgd_page_vaddr(*pgd));+remove_pud_table(pud,start,next,direct);+if(free_pud_table(pud,pgd))+pgd_changed=true;+unmap_low_page(pud);+}++if(pgd_changed)+sync_global_pgds(start,end-1);++flush_tlb_all();+}+#ifdef CONFIG_MEMORY_HOTREMOVEint__refarch_remove_memory(u64start,u64size){
--
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
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email:<a href=mailto:"dont@kvack.org"> email@kvack.org</a>
From: Simon Jeons <hidden> Date: 2013-01-30 07:33:11
On Wed, 2013-01-30 at 13:55 +0800, Tang Chen wrote:
On 01/30/2013 11:27 AM, Simon Jeons wrote:
quoted
On Wed, 2013-01-30 at 10:16 +0800, Tang Chen wrote:
quoted
On 01/29/2013 09:04 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
quoted
From: Wen Congyang<redacted>
When memory is removed, the corresponding pagetables should alse be removed.
This patch introduces some common APIs to support vmemmap pagetable and x86_64
architecture pagetable removing.
Why don't need to build_all_zonelists like online_pages does during
hot-add path(add_memory)?
Hi Simon,
As you said, build_all_zonelists is done by online_pages. When the
memory device
is hot-added, we cannot use it. we can only use is when we online the
pages on it.
Why?
If a node has just one memory device and memory is small, some zone will
not present like zone_highmem, then hot-add another memory device and
zone_highmem appear, if you should build_all_zonelists this time?
Hi Simon,
We built zone list when the first memory on the node is hot-added.
add_memory()
|-->if (!node_online(nid)) hotadd_new_pgdat()
|-->free_area_init_node()
|-->build_all_zonelists()
All the zones on the new node will be initialized as empty. So here, we
build zone list.
But actually we did nothing because no page is online, and zones are empty.
In build_zonelists_node(), populated_zone(zone) will always be false.
The real work of building zone list is when pages are online. :)
And in your question, you said some small memory is there, and
zone_normal is present.
OK, when these pages are onlined (not added), the zone list has been
rebuilt.
But pages in zone_highmem is not added, which means not onlined, so we
don't need to
build zone list for it. And later, the zone_highmem pages are added, we
still don't
rebuild the zone list because the real rebuilding work is when the pages
are onlined.
I think this is the current logic. :)
Thanks for you clarify. Actually, I miss "Even if the memory is
hot-added, it is not at ready-to-use state. For using newly added
memory, you have to 'online' the memory section" in the doc. :)
Thanks. :)
quoted
quoted
But we can online the pages as different types, kernel or movable (which
belongs to
different zones), and we can online part of the memory, not all of them.
So each time we online some pages, we should check if we need to update
the zone list.
So I think that is why we do build_all_zonelists when online_pages.
(just my opinion)
Thanks. :)
quoted
quoted
All pages of virtual mapping in removed memory cannot be freedi if some pages
used as PGD/PUD includes not only removed memory but also other memory. So the
patch uses the following way 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.
Signed-off-by: Yasuaki Ishimatsu<redacted>
Signed-off-by: Jianguo Wu<redacted>
Signed-off-by: Wen Congyang<redacted>
Signed-off-by: Tang Chen<redacted>
---
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_64.c | 299 ++++++++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 +++---
include/linux/bootmem.h | 1 +
4 files changed, 326 insertions(+), 22 deletions(-)
@@ -682,6 +682,305 @@ int arch_add_memory(int nid, u64 start, u64 size)}EXPORT_SYMBOL_GPL(arch_add_memory);+#define PAGE_INUSE 0xFD++staticvoid__meminitfree_pagetable(structpage*page,intorder)+{+structzone*zone;+boolbootmem=false;+unsignedlongmagic;+unsignedintnr_pages=1<<order;++/* bootmem page has reserved flag */+if(PageReserved(page)){+__ClearPageReserved(page);+bootmem=true;++magic=(unsignedlong)page->lru.next;+if(magic==SECTION_INFO||magic==MIX_SECTION_INFO){+while(nr_pages--)+put_page_bootmem(page++);+}else+__free_pages_bootmem(page,order);+}else+free_pages((unsignedlong)page_address(page),order);++/*+*SECTION_INFOpagesandMIX_SECTION_INFOpages+*areallallocatedbybootmem.+*/+if(bootmem){+zone=page_zone(page);+zone_span_writelock(zone);+zone->present_pages+=nr_pages;+zone_span_writeunlock(zone);+totalram_pages+=nr_pages;+}+}++staticvoid__meminitfree_pte_table(pte_t*pte_start,pmd_t*pmd)+{+pte_t*pte;+inti;++for(i=0;i<PTRS_PER_PTE;i++){+pte=pte_start+i;+if(pte_val(*pte))+return;+}++/* free a pte talbe */+free_pagetable(pmd_page(*pmd),0);+spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+}++staticvoid__meminitfree_pmd_table(pmd_t*pmd_start,pud_t*pud)+{+pmd_t*pmd;+inti;++for(i=0;i<PTRS_PER_PMD;i++){+pmd=pmd_start+i;+if(pmd_val(*pmd))+return;+}++/* free a pmd talbe */+free_pagetable(pud_page(*pud),0);+spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+}++/* Return true if pgd is changed, otherwise return false. */+staticbool__meminitfree_pud_table(pud_t*pud_start,pgd_t*pgd)+{+pud_t*pud;+inti;++for(i=0;i<PTRS_PER_PUD;i++){+pud=pud_start+i;+if(pud_val(*pud))+returnfalse;+}++/* free a pud table */+free_pagetable(pgd_page(*pgd),0);+spin_lock(&init_mm.page_table_lock);+pgd_clear(pgd);+spin_unlock(&init_mm.page_table_lock);++returntrue;+}++staticvoid__meminit+remove_pte_table(pte_t*pte_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongnext,pages=0;+pte_t*pte;+void*page_addr;+phys_addr_tphys_addr;++pte=pte_start+pte_index(addr);+for(;addr<end;addr=next,pte++){+next=(addr+PAGE_SIZE)&PAGE_MASK;+if(next>end)+next=end;++if(!pte_present(*pte))+continue;++/*+*Wemapped[0,1G)memoryasidentitymappingwhen+*initializing,inarch/x86/kernel/head_64.S.These+*pagetablescannotberemoved.+*/+phys_addr=pte_val(*pte)+(addr&PAGE_MASK);+if(phys_addr<(phys_addr_t)0x40000000)+return;++if(IS_ALIGNED(addr,PAGE_SIZE)&&+IS_ALIGNED(next,PAGE_SIZE)){+if(!direct){+free_pagetable(pte_page(*pte),0);+pages++;+}++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}else{+/*+*Ifwearenotremovingthewholepage,itmeans+*otherptesinthispagearebeingusedandwecanot+*removethem.Sofilltheunusedpteswith0xFD,and+*removethepagewhenitiswhollyfilledwith0xFD.+*/+memset((void*)addr,PAGE_INUSE,next-addr);+page_addr=page_address(pte_page(*pte));++if(!memchr_inv(page_addr,PAGE_INUSE,PAGE_SIZE)){+free_pagetable(pte_page(*pte),0);+pages++;++spin_lock(&init_mm.page_table_lock);+pte_clear(&init_mm,addr,pte);+spin_unlock(&init_mm.page_table_lock);+}+}+}++/* Call free_pte_table() in remove_pmd_table(). */+flush_tlb_all();+if(direct)+update_page_count(PG_LEVEL_4K,-pages);+}++staticvoid__meminit+remove_pmd_table(pmd_t*pmd_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpte_phys,next,pages=0;+pte_t*pte_base;+pmd_t*pmd;++pmd=pmd_start+pmd_index(addr);+for(;addr<end;addr=next,pmd++){+next=pmd_addr_end(addr,end);++if(!pmd_present(*pmd))+continue;++if(pmd_large(*pmd)){+if(IS_ALIGNED(addr,PMD_SIZE)&&+IS_ALIGNED(next,PMD_SIZE)){+if(!direct){+free_pagetable(pmd_page(*pmd),+get_order(PMD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pmd_clear(pmd);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse2Mpage,butweneedtoremovepartofthem,+*sosplit2Mpageto4Kpage.+*/+pte_base=(pte_t*)alloc_low_page(&pte_phys);+BUG_ON(!pte_base);+__split_large_page((pte_t*)pmd,addr,+(pte_t*)pte_base);++spin_lock(&init_mm.page_table_lock);+pmd_populate_kernel(&init_mm,pmd,__va(pte_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pte_base=(pte_t*)map_low_page((pte_t*)pmd_page_vaddr(*pmd));+remove_pte_table(pte_base,addr,next,direct);+free_pte_table(pte_base,pmd);+unmap_low_page(pte_base);+}++/* Call free_pmd_table() in remove_pud_table(). */+if(direct)+update_page_count(PG_LEVEL_2M,-pages);+}++staticvoid__meminit+remove_pud_table(pud_t*pud_start,unsignedlongaddr,unsignedlongend,+booldirect)+{+unsignedlongpmd_phys,next,pages=0;+pmd_t*pmd_base;+pud_t*pud;++pud=pud_start+pud_index(addr);+for(;addr<end;addr=next,pud++){+next=pud_addr_end(addr,end);++if(!pud_present(*pud))+continue;++if(pud_large(*pud)){+if(IS_ALIGNED(addr,PUD_SIZE)&&+IS_ALIGNED(next,PUD_SIZE)){+if(!direct){+free_pagetable(pud_page(*pud),+get_order(PUD_SIZE));+pages++;+}++spin_lock(&init_mm.page_table_lock);+pud_clear(pud);+spin_unlock(&init_mm.page_table_lock);+continue;+}++/*+*Weuse1Gpage,butweneedtoremovepartofthem,+*sosplit1Gpageto2Mpage.+*/+pmd_base=(pmd_t*)alloc_low_page(&pmd_phys);+BUG_ON(!pmd_base);+__split_large_page((pte_t*)pud,addr,+(pte_t*)pmd_base);++spin_lock(&init_mm.page_table_lock);+pud_populate(&init_mm,pud,__va(pmd_phys));+spin_unlock(&init_mm.page_table_lock);++flush_tlb_all();+}++pmd_base=(pmd_t*)map_low_page((pmd_t*)pud_page_vaddr(*pud));+remove_pmd_table(pmd_base,addr,next,direct);+free_pmd_table(pmd_base,pud);+unmap_low_page(pmd_base);+}++if(direct)+update_page_count(PG_LEVEL_1G,-pages);+}++/* start and end are both virtual address. */+staticvoid__meminit+remove_pagetable(unsignedlongstart,unsignedlongend,booldirect)+{+unsignedlongnext;+pgd_t*pgd;+pud_t*pud;+boolpgd_changed=false;++for(;start<end;start=next){+pgd=pgd_offset_k(start);+if(!pgd_present(*pgd))+continue;++next=pgd_addr_end(start,end);++pud=(pud_t*)map_low_page((pud_t*)pgd_page_vaddr(*pgd));+remove_pud_table(pud,start,next,direct);+if(free_pud_table(pud,pgd))+pgd_changed=true;+unmap_low_page(pud);+}++if(pgd_changed)+sync_global_pgds(start,end-1);++flush_tlb_all();+}+#ifdef CONFIG_MEMORY_HOTREMOVEint__refarch_remove_memory(u64start,u64size){
--
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
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email:<a href=mailto:"dont@kvack.org"> email@kvack.org</a>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
Hi Simon,
Please see below. :)
On 01/29/2013 08:52 PM, Simon Jeons wrote:
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
quoted
Here is the physical memory hot-remove patch-set based on 3.8rc-2.
Some questions ask you, not has relationship with this patchset, but is
memory hotplug stuff.
1. In function node_states_check_changes_online:
comments:
* If we don't have HIGHMEM nor movable node,
* node_states[N_NORMAL_MEMORY] contains nodes which have zones of
* 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE.
How to understand it? Why we don't have HIGHMEM nor movable node and
node_staes[N_NORMAL_MEMORY] contains 0...ZONE_MOVABLE, IIUC,
N_NORMAL_MEMORY only means the node has regular memory.
First of all, I think we need to understand why we need N_MEMORY.
In order to support movable node, which has only ZONE_MOVABLE (the last
zone),
we introduce N_MEMORY to represent the node has normal, highmem and
movable memory.
Here, "we have movable node" means you configured CONFIG_MOVABLE_NODE.
This config option doesn't mean we don't have movable pages, (NO)
it means we don't have a node which has only movable pages (only have
ZONE_MOVABLE). (YES)
Here, if we don't have CONFIG_MOVABLE_NODE (we don't have movable node),
we don't need a
separate node_states[] element to represent a particular node because we
won't have a node
which has only ZONE_MOVABLE.
So,
1) if we don't have highmem nor movable node, N_MEMORY == N_HIGH_MEMORY
== N_NORMAL_MEMORY,
which means N_NORMAL_MEMORY effects as N_MEMORY. If we online pages
as movable, we need
to update node_states[N_NORMAL_MEMORY].
Please refer to the definition of enum zone_type, if we don't have
CONFIG_HIGHMEM, we won't
have ZONE_HIGHMEM, but ZONE_NORMAL and ZONE_MOVABLE will always there.
So we can have movable
pages, and the zone_last should be ZONE_MOVABLE.
Again, because we won't have a node only having ZONE_MOVABLE, so we just
need to update
node_states[N_NORMAL_MEMORY].
* If we don't have movable node, node_states[N_NORMAL_MEMORY]
* contains nodes which have zones of 0...ZONE_MOVABLE,
* set zone_last to ZONE_MOVABLE.
How to understand?
2) this code is in #ifdef CONFIG_HIGHMEM, which means we have highmem,
so if we don't have
movable node, N_MEMORY == N_HIGH_MEMORY, and N_HIGH_MEMORY effects
as N_MEMORY. If we
online pages as movable, we need to update node_states[N_NORMAL_MEMORY].
2. In function move_pfn_range_left, why end<= z2->zone_start_pfn is not
correct? The comments said that must include/overlap, why?
This one is easy, if I understand you correctly.
move_pfn_range_left() is used to move the left most part [start_pfn,
end_pfn) of z2 to z1.
So if end_pfn<= z2->zone_start_pfn, it means [start_pfn, end_pfn) is not
part of z2.
Then it fails.
3. In function online_pages, the normal case(w/o online_kenrel,
online_movable), why not check if the new zone is overlap with adjacent
zones?
Can a zone overlap with the others ? I don't think so.
One pfn could only be in one zone,
zone = page_zone(pfn_to_page(pfn));
it could overlap with others, I think. :)
But maybe I misunderstand you. :)
4. Could you summarize the difference implementation between hot-add and
logic-add, hot-remove and logic-remove?
Sorry, I don't quite understand what do you mean by logic-add/remove.
Would you please explain more ?
If you meant the sys fs interfaces, I think they are just another set of
entrances
of memory hotplug.
Thanks. :)
quoted
This patch-set aims to implement physical memory hot-removing.
The patches can free/remove the following things:
- /sys/firmware/memmap/X/{end, start, type} : [PATCH 4/15]
- memmap of sparse-vmemmap : [PATCH 6,7,8,10/15]
- page table of removed memory : [RFC PATCH 7,8,10/15]
- node and related sysfs files : [RFC PATCH 13-15/15]
Existing problem:
If CONFIG_MEMCG is selected, we will allocate memory to store page cgroup
when we online pages.
For example: there is a memory device on node 1. The address range
is [1G, 1.5G). You will find 4 new directories memory8, memory9, memory10,
and memory11 under the directory /sys/devices/system/memory/.
If CONFIG_MEMCG is selected, when we online memory8, the memory stored page
cgroup is not provided by this memory device. But when we online memory9, the
memory stored page cgroup may be provided by memory8. So we can't offline
memory8 now. We should offline the memory in the reversed order.
When the memory device is hotremoved, we will auto offline memory provided
by this memory device. But we don't know which memory is onlined first, so
offlining memory may fail.
In patch1, we provide a solution which is not good enough:
Iterate twice to offline the memory.
1st iterate: offline every non primary memory block.
2nd iterate: offline primary (i.e. first added) memory block.
And a new idea from Wen Congyang[off-list ref] is:
allocate the memory from the memory block they are describing.
But we are not sure if it is OK to do so because there is not existing API
to do so, and we need to move page_cgroup memory allocation from MEM_GOING_ONLINE
to MEM_ONLINE. And also, it may interfere the hugepage.
How to test this patchset?
1. apply this patchset and build the kernel. MEMORY_HOTPLUG, MEMORY_HOTREMOVE,
ACPI_HOTPLUG_MEMORY must be selected.
2. load the module acpi_memhotplug
3. hotplug the memory device(it depends on your hardware)
You will see the memory device under the directory /sys/bus/acpi/devices/.
Its name is PNP0C80:XX.
4. online/offline pages provided by this memory device
You can write online/offline to /sys/devices/system/memory/memoryX/state to
online/offline pages provided by this memory device
5. hotremove the memory device
You can hotremove the memory device by the hardware, or writing 1 to
/sys/bus/acpi/devices/PNP0C80:XX/eject.
Is there a similar knode to hot-add the memory device?
quoted
Note: if the memory provided by the memory device is used by the kernel, it
can't be offlined. It is not a bug.
Changelogs from v5 to v6:
Patch3: Add some more comments to explain memory hot-remove.
Patch4: Remove bootmem member in struct firmware_map_entry.
Patch6: Repeatedly register bootmem pages when using hugepage.
Patch8: Repeatedly free bootmem pages when using hugepage.
Patch14: Don't free pgdat when offlining a node, just reset it to 0.
Patch15: New patch, pgdat is not freed in patch14, so don't allocate a new
one when online a node.
Changelogs from v4 to v5:
Patch7: new patch, move pgdat_resize_lock into sparse_remove_one_section() to
avoid disabling irq because we need flush tlb when free pagetables.
Patch8: new patch, pick up some common APIs that are used to free direct mapping
and vmemmap pagetables.
Patch9: free direct mapping pagetables on x86_64 arch.
Patch10: free vmemmap pagetables.
Patch11: since freeing memmap with vmemmap has been implemented, the config
macro CONFIG_SPARSEMEM_VMEMMAP when defining __remove_section() is
no longer needed.
Patch13: no need to modify acpi_memory_disable_device() since it was removed,
and add nid parameter when calling remove_memory().
Changelogs from v3 to v4:
Patch7: remove unused codes.
Patch8: fix nr_pages that is passed to free_map_bootmem()
Changelogs from v2 to v3:
Patch9: call sync_global_pgds() if pgd is changed
Patch10: fix a problem int the patch
Changelogs from v1 to v2:
Patch1: new patch, offline memory twice. 1st iterate: offline every non primary
memory block. 2nd iterate: offline primary (i.e. first added) memory
block.
Patch3: new patch, no logical change, just remove reduntant codes.
Patch9: merge the patch from wujianguo into this patch. flush tlb on all cpu
after the pagetable is changed.
Patch12: new patch, free node_data when a node is offlined.
Tang Chen (6):
memory-hotplug: move pgdat_resize_lock into
sparse_remove_one_section()
memory-hotplug: remove page table of x86_64 architecture
memory-hotplug: remove memmap of sparse-vmemmap
memory-hotplug: Integrated __remove_section() of
CONFIG_SPARSEMEM_VMEMMAP.
memory-hotplug: remove sysfs file of node
memory-hotplug: Do not allocate pdgat if it was not freed when
offline.
Wen Congyang (5):
memory-hotplug: try to offline the memory twice to avoid dependence
memory-hotplug: remove redundant codes
memory-hotplug: introduce new function arch_remove_memory() for
removing page table depends on architecture
memory-hotplug: Common APIs to support page tables hot-remove
memory-hotplug: free node_data when a node is offlined
Yasuaki Ishimatsu (4):
memory-hotplug: check whether all memory blocks are offlined or not
when removing memory
memory-hotplug: remove /sys/firmware/memmap/X sysfs
memory-hotplug: implement register_page_bootmem_info_section of
sparse-vmemmap
memory-hotplug: memory_hotplug: clear zone when removing the memory
arch/arm64/mm/mmu.c | 3 +
arch/ia64/mm/discontig.c | 10 +
arch/ia64/mm/init.c | 18 ++
arch/powerpc/mm/init_64.c | 10 +
arch/powerpc/mm/mem.c | 12 +
arch/s390/mm/init.c | 12 +
arch/s390/mm/vmem.c | 10 +
arch/sh/mm/init.c | 17 ++
arch/sparc/mm/init_64.c | 10 +
arch/tile/mm/init.c | 8 +
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_32.c | 12 +
arch/x86/mm/init_64.c | 390 +++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 ++--
drivers/acpi/acpi_memhotplug.c | 8 +-
drivers/base/memory.c | 6 +
drivers/firmware/memmap.c | 96 +++++++-
include/linux/bootmem.h | 1 +
include/linux/firmware-map.h | 6 +
include/linux/memory_hotplug.h | 15 +-
include/linux/mm.h | 4 +-
mm/memory_hotplug.c | 459 +++++++++++++++++++++++++++++++---
mm/sparse.c | 8 +-
23 files changed, 1094 insertions(+), 69 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email:<a href=mailto:"dont@kvack.org"> email@kvack.org</a>
Hi Simon,
Please see below. :)
On 01/29/2013 08:52 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
quoted
Here is the physical memory hot-remove patch-set based on 3.8rc-2.
Some questions ask you, not has relationship with this patchset, but is
memory hotplug stuff.
1. In function node_states_check_changes_online:
comments:
* If we don't have HIGHMEM nor movable node,
* node_states[N_NORMAL_MEMORY] contains nodes which have zones of
* 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE.
How to understand it? Why we don't have HIGHMEM nor movable node and
node_staes[N_NORMAL_MEMORY] contains 0...ZONE_MOVABLE, IIUC,
N_NORMAL_MEMORY only means the node has regular memory.
First of all, I think we need to understand why we need N_MEMORY.
In order to support movable node, which has only ZONE_MOVABLE (the last
zone),
we introduce N_MEMORY to represent the node has normal, highmem and
movable memory.
Here, "we have movable node" means you configured CONFIG_MOVABLE_NODE.
Sorry, should be "we don't have movable node" means you didn't
configured CONFIG_MOVABLE_NODE.
This config option doesn't mean we don't have movable pages, (NO)
it means we don't have a node which has only movable pages (only have
ZONE_MOVABLE). (YES)
Here, if we don't have CONFIG_MOVABLE_NODE (we don't have movable node),
we don't need a
separate node_states[] element to represent a particular node because we
won't have a node
which has only ZONE_MOVABLE.
So,
1) if we don't have highmem nor movable node, N_MEMORY == N_HIGH_MEMORY
== N_NORMAL_MEMORY,
which means N_NORMAL_MEMORY effects as N_MEMORY. If we online pages as
movable, we need
to update node_states[N_NORMAL_MEMORY].
Please refer to the definition of enum zone_type, if we don't have
CONFIG_HIGHMEM, we won't
have ZONE_HIGHMEM, but ZONE_NORMAL and ZONE_MOVABLE will always there.
So we can have movable
pages, and the zone_last should be ZONE_MOVABLE.
Again, because we won't have a node only having ZONE_MOVABLE, so we just
need to update
node_states[N_NORMAL_MEMORY].
quoted
* If we don't have movable node, node_states[N_NORMAL_MEMORY]
* contains nodes which have zones of 0...ZONE_MOVABLE,
* set zone_last to ZONE_MOVABLE.
How to understand?
2) this code is in #ifdef CONFIG_HIGHMEM, which means we have highmem,
so if we don't have
movable node, N_MEMORY == N_HIGH_MEMORY, and N_HIGH_MEMORY effects as
N_MEMORY. If we
online pages as movable, we need to update node_states[N_NORMAL_MEMORY].
quoted
2. In function move_pfn_range_left, why end<= z2->zone_start_pfn is not
correct? The comments said that must include/overlap, why?
This one is easy, if I understand you correctly.
move_pfn_range_left() is used to move the left most part [start_pfn,
end_pfn) of z2 to z1.
So if end_pfn<= z2->zone_start_pfn, it means [start_pfn, end_pfn) is not
part of z2.
Then it fails.
quoted
3. In function online_pages, the normal case(w/o online_kenrel,
online_movable), why not check if the new zone is overlap with adjacent
zones?
Can a zone overlap with the others ? I don't think so.
One pfn could only be in one zone,
zone = page_zone(pfn_to_page(pfn));
it could overlap with others, I think. :)
But maybe I misunderstand you. :)
quoted
4. Could you summarize the difference implementation between hot-add and
logic-add, hot-remove and logic-remove?
Sorry, I don't quite understand what do you mean by logic-add/remove.
Would you please explain more ?
If you meant the sys fs interfaces, I think they are just another set of
entrances
of memory hotplug.
Thanks. :)
quoted
quoted
This patch-set aims to implement physical memory hot-removing.
The patches can free/remove the following things:
- /sys/firmware/memmap/X/{end, start, type} : [PATCH 4/15]
- memmap of sparse-vmemmap : [PATCH 6,7,8,10/15]
- page table of removed memory : [RFC PATCH 7,8,10/15]
- node and related sysfs files : [RFC PATCH 13-15/15]
Existing problem:
If CONFIG_MEMCG is selected, we will allocate memory to store page
cgroup
when we online pages.
For example: there is a memory device on node 1. The address range
is [1G, 1.5G). You will find 4 new directories memory8, memory9,
memory10,
and memory11 under the directory /sys/devices/system/memory/.
If CONFIG_MEMCG is selected, when we online memory8, the memory
stored page
cgroup is not provided by this memory device. But when we online
memory9, the
memory stored page cgroup may be provided by memory8. So we can't
offline
memory8 now. We should offline the memory in the reversed order.
When the memory device is hotremoved, we will auto offline memory
provided
by this memory device. But we don't know which memory is onlined
first, so
offlining memory may fail.
In patch1, we provide a solution which is not good enough:
Iterate twice to offline the memory.
1st iterate: offline every non primary memory block.
2nd iterate: offline primary (i.e. first added) memory block.
And a new idea from Wen Congyang[off-list ref] is:
allocate the memory from the memory block they are describing.
But we are not sure if it is OK to do so because there is not
existing API
to do so, and we need to move page_cgroup memory allocation from
MEM_GOING_ONLINE
to MEM_ONLINE. And also, it may interfere the hugepage.
How to test this patchset?
1. apply this patchset and build the kernel. MEMORY_HOTPLUG,
MEMORY_HOTREMOVE,
ACPI_HOTPLUG_MEMORY must be selected.
2. load the module acpi_memhotplug
3. hotplug the memory device(it depends on your hardware)
You will see the memory device under the directory
/sys/bus/acpi/devices/.
Its name is PNP0C80:XX.
4. online/offline pages provided by this memory device
You can write online/offline to
/sys/devices/system/memory/memoryX/state to
online/offline pages provided by this memory device
5. hotremove the memory device
You can hotremove the memory device by the hardware, or writing 1 to
/sys/bus/acpi/devices/PNP0C80:XX/eject.
Is there a similar knode to hot-add the memory device?
quoted
Note: if the memory provided by the memory device is used by the
kernel, it
can't be offlined. It is not a bug.
Changelogs from v5 to v6:
Patch3: Add some more comments to explain memory hot-remove.
Patch4: Remove bootmem member in struct firmware_map_entry.
Patch6: Repeatedly register bootmem pages when using hugepage.
Patch8: Repeatedly free bootmem pages when using hugepage.
Patch14: Don't free pgdat when offlining a node, just reset it to 0.
Patch15: New patch, pgdat is not freed in patch14, so don't allocate
a new
one when online a node.
Changelogs from v4 to v5:
Patch7: new patch, move pgdat_resize_lock into
sparse_remove_one_section() to
avoid disabling irq because we need flush tlb when free pagetables.
Patch8: new patch, pick up some common APIs that are used to free
direct mapping
and vmemmap pagetables.
Patch9: free direct mapping pagetables on x86_64 arch.
Patch10: free vmemmap pagetables.
Patch11: since freeing memmap with vmemmap has been implemented, the
config
macro CONFIG_SPARSEMEM_VMEMMAP when defining __remove_section() is
no longer needed.
Patch13: no need to modify acpi_memory_disable_device() since it was
removed,
and add nid parameter when calling remove_memory().
Changelogs from v3 to v4:
Patch7: remove unused codes.
Patch8: fix nr_pages that is passed to free_map_bootmem()
Changelogs from v2 to v3:
Patch9: call sync_global_pgds() if pgd is changed
Patch10: fix a problem int the patch
Changelogs from v1 to v2:
Patch1: new patch, offline memory twice. 1st iterate: offline every
non primary
memory block. 2nd iterate: offline primary (i.e. first added) memory
block.
Patch3: new patch, no logical change, just remove reduntant codes.
Patch9: merge the patch from wujianguo into this patch. flush tlb on
all cpu
after the pagetable is changed.
Patch12: new patch, free node_data when a node is offlined.
Tang Chen (6):
memory-hotplug: move pgdat_resize_lock into
sparse_remove_one_section()
memory-hotplug: remove page table of x86_64 architecture
memory-hotplug: remove memmap of sparse-vmemmap
memory-hotplug: Integrated __remove_section() of
CONFIG_SPARSEMEM_VMEMMAP.
memory-hotplug: remove sysfs file of node
memory-hotplug: Do not allocate pdgat if it was not freed when
offline.
Wen Congyang (5):
memory-hotplug: try to offline the memory twice to avoid dependence
memory-hotplug: remove redundant codes
memory-hotplug: introduce new function arch_remove_memory() for
removing page table depends on architecture
memory-hotplug: Common APIs to support page tables hot-remove
memory-hotplug: free node_data when a node is offlined
Yasuaki Ishimatsu (4):
memory-hotplug: check whether all memory blocks are offlined or not
when removing memory
memory-hotplug: remove /sys/firmware/memmap/X sysfs
memory-hotplug: implement register_page_bootmem_info_section of
sparse-vmemmap
memory-hotplug: memory_hotplug: clear zone when removing the memory
arch/arm64/mm/mmu.c | 3 +
arch/ia64/mm/discontig.c | 10 +
arch/ia64/mm/init.c | 18 ++
arch/powerpc/mm/init_64.c | 10 +
arch/powerpc/mm/mem.c | 12 +
arch/s390/mm/init.c | 12 +
arch/s390/mm/vmem.c | 10 +
arch/sh/mm/init.c | 17 ++
arch/sparc/mm/init_64.c | 10 +
arch/tile/mm/init.c | 8 +
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_32.c | 12 +
arch/x86/mm/init_64.c | 390 +++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 ++--
drivers/acpi/acpi_memhotplug.c | 8 +-
drivers/base/memory.c | 6 +
drivers/firmware/memmap.c | 96 +++++++-
include/linux/bootmem.h | 1 +
include/linux/firmware-map.h | 6 +
include/linux/memory_hotplug.h | 15 +-
include/linux/mm.h | 4 +-
mm/memory_hotplug.c | 459 +++++++++++++++++++++++++++++++---
mm/sparse.c | 8 +-
23 files changed, 1094 insertions(+), 69 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email:<a href=mailto:"dont@kvack.org"> email@kvack.org</a>
--
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: Simon Jeons <hidden> Date: 2013-01-31 01:22:39
Hi Tang,
On Wed, 2013-01-30 at 18:15 +0800, Tang Chen wrote:
Hi Simon,
Please see below. :)
On 01/29/2013 08:52 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Wed, 2013-01-09 at 17:32 +0800, Tang Chen wrote:
quoted
Here is the physical memory hot-remove patch-set based on 3.8rc-2.
Some questions ask you, not has relationship with this patchset, but is
memory hotplug stuff.
1. In function node_states_check_changes_online:
comments:
* If we don't have HIGHMEM nor movable node,
* node_states[N_NORMAL_MEMORY] contains nodes which have zones of
* 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE.
How to understand it? Why we don't have HIGHMEM nor movable node and
node_staes[N_NORMAL_MEMORY] contains 0...ZONE_MOVABLE, IIUC,
N_NORMAL_MEMORY only means the node has regular memory.
First of all, I think we need to understand why we need N_MEMORY.
In order to support movable node, which has only ZONE_MOVABLE (the last
zone),
we introduce N_MEMORY to represent the node has normal, highmem and
movable memory.
Here, "we have movable node" means you configured CONFIG_MOVABLE_NODE.
This config option doesn't mean we don't have movable pages, (NO)
it means we don't have a node which has only movable pages (only have
ZONE_MOVABLE). (YES)
Here, if we don't have CONFIG_MOVABLE_NODE (we don't have movable node),
we don't need a
separate node_states[] element to represent a particular node because we
won't have a node
which has only ZONE_MOVABLE.
So,
1) if we don't have highmem nor movable node, N_MEMORY == N_HIGH_MEMORY
== N_NORMAL_MEMORY,
which means N_NORMAL_MEMORY effects as N_MEMORY. If we online pages
as movable, we need
to update node_states[N_NORMAL_MEMORY].
Sorry, I still confuse. :(
update node_states[N_NORMAL_MEMORY] to node_states[N_MEMORY] or
node_states[N_NORMAL_MEMOR] present 0...ZONE_MOVABLE?
Please refer to the definition of enum zone_type, if we don't have
CONFIG_HIGHMEM, we won't
have ZONE_HIGHMEM, but ZONE_NORMAL and ZONE_MOVABLE will always there.
So we can have movable
pages, and the zone_last should be ZONE_MOVABLE.
node_states is what? node_states[N_NORMAL_MEMOR] or
node_states[N_MEMORY]?
Again, because we won't have a node only having ZONE_MOVABLE, so we just
need to update
node_states[N_NORMAL_MEMORY].
quoted
* If we don't have movable node, node_states[N_NORMAL_MEMORY]
* contains nodes which have zones of 0...ZONE_MOVABLE,
* set zone_last to ZONE_MOVABLE.
How to understand?
2) this code is in #ifdef CONFIG_HIGHMEM, which means we have highmem,
so if we don't have
movable node, N_MEMORY == N_HIGH_MEMORY, and N_HIGH_MEMORY effects
as N_MEMORY. If we
online pages as movable, we need to update node_states[N_NORMAL_MEMORY].
quoted
2. In function move_pfn_range_left, why end<= z2->zone_start_pfn is not
correct? The comments said that must include/overlap, why?
This one is easy, if I understand you correctly.
move_pfn_range_left() is used to move the left most part [start_pfn,
end_pfn) of z2 to z1.
So if end_pfn<= z2->zone_start_pfn, it means [start_pfn, end_pfn) is not
part of z2.
Then it fails.
Yup, very clear now. :)
Why check !z1->wait_table in function move_pfn_range_left and function
__add_zone? I think zone->wait_table is initialized in
free_area_init_core, which will be called during system initialization
and hotadd_new_pgdat path.
quoted
3. In function online_pages, the normal case(w/o online_kenrel,
online_movable), why not check if the new zone is overlap with adjacent
zones?
Can a zone overlap with the others ? I don't think so.
One pfn could only be in one zone,
zone = page_zone(pfn_to_page(pfn));
thanks. :)
There is a zone populated check in function online_pages. But zone is
populated in free_area_init_core which will be called during system
initialization and hotadd_new_pgdat path. Why still need this check?
it could overlap with others, I think. :)
But maybe I misunderstand you. :)
quoted
4. Could you summarize the difference implementation between hot-add and
logic-add, hot-remove and logic-remove?
Sorry, I don't quite understand what do you mean by logic-add/remove.
Would you please explain more ?
If you meant the sys fs interfaces, I think they are just another set of
entrances
of memory hotplug.
Please ingore this silly question. :(
Thanks. :)
quoted
quoted
This patch-set aims to implement physical memory hot-removing.
The patches can free/remove the following things:
- /sys/firmware/memmap/X/{end, start, type} : [PATCH 4/15]
- memmap of sparse-vmemmap : [PATCH 6,7,8,10/15]
- page table of removed memory : [RFC PATCH 7,8,10/15]
- node and related sysfs files : [RFC PATCH 13-15/15]
Existing problem:
If CONFIG_MEMCG is selected, we will allocate memory to store page cgroup
when we online pages.
For example: there is a memory device on node 1. The address range
is [1G, 1.5G). You will find 4 new directories memory8, memory9, memory10,
and memory11 under the directory /sys/devices/system/memory/.
If CONFIG_MEMCG is selected, when we online memory8, the memory stored page
cgroup is not provided by this memory device. But when we online memory9, the
memory stored page cgroup may be provided by memory8. So we can't offline
memory8 now. We should offline the memory in the reversed order.
When the memory device is hotremoved, we will auto offline memory provided
by this memory device. But we don't know which memory is onlined first, so
offlining memory may fail.
In patch1, we provide a solution which is not good enough:
Iterate twice to offline the memory.
1st iterate: offline every non primary memory block.
2nd iterate: offline primary (i.e. first added) memory block.
And a new idea from Wen Congyang[off-list ref] is:
allocate the memory from the memory block they are describing.
But we are not sure if it is OK to do so because there is not existing API
to do so, and we need to move page_cgroup memory allocation from MEM_GOING_ONLINE
to MEM_ONLINE. And also, it may interfere the hugepage.
How to test this patchset?
1. apply this patchset and build the kernel. MEMORY_HOTPLUG, MEMORY_HOTREMOVE,
ACPI_HOTPLUG_MEMORY must be selected.
2. load the module acpi_memhotplug
3. hotplug the memory device(it depends on your hardware)
You will see the memory device under the directory /sys/bus/acpi/devices/.
Its name is PNP0C80:XX.
4. online/offline pages provided by this memory device
You can write online/offline to /sys/devices/system/memory/memoryX/state to
online/offline pages provided by this memory device
5. hotremove the memory device
You can hotremove the memory device by the hardware, or writing 1 to
/sys/bus/acpi/devices/PNP0C80:XX/eject.
Is there a similar knode to hot-add the memory device?
quoted
Note: if the memory provided by the memory device is used by the kernel, it
can't be offlined. It is not a bug.
Changelogs from v5 to v6:
Patch3: Add some more comments to explain memory hot-remove.
Patch4: Remove bootmem member in struct firmware_map_entry.
Patch6: Repeatedly register bootmem pages when using hugepage.
Patch8: Repeatedly free bootmem pages when using hugepage.
Patch14: Don't free pgdat when offlining a node, just reset it to 0.
Patch15: New patch, pgdat is not freed in patch14, so don't allocate a new
one when online a node.
Changelogs from v4 to v5:
Patch7: new patch, move pgdat_resize_lock into sparse_remove_one_section() to
avoid disabling irq because we need flush tlb when free pagetables.
Patch8: new patch, pick up some common APIs that are used to free direct mapping
and vmemmap pagetables.
Patch9: free direct mapping pagetables on x86_64 arch.
Patch10: free vmemmap pagetables.
Patch11: since freeing memmap with vmemmap has been implemented, the config
macro CONFIG_SPARSEMEM_VMEMMAP when defining __remove_section() is
no longer needed.
Patch13: no need to modify acpi_memory_disable_device() since it was removed,
and add nid parameter when calling remove_memory().
Changelogs from v3 to v4:
Patch7: remove unused codes.
Patch8: fix nr_pages that is passed to free_map_bootmem()
Changelogs from v2 to v3:
Patch9: call sync_global_pgds() if pgd is changed
Patch10: fix a problem int the patch
Changelogs from v1 to v2:
Patch1: new patch, offline memory twice. 1st iterate: offline every non primary
memory block. 2nd iterate: offline primary (i.e. first added) memory
block.
Patch3: new patch, no logical change, just remove reduntant codes.
Patch9: merge the patch from wujianguo into this patch. flush tlb on all cpu
after the pagetable is changed.
Patch12: new patch, free node_data when a node is offlined.
Tang Chen (6):
memory-hotplug: move pgdat_resize_lock into
sparse_remove_one_section()
memory-hotplug: remove page table of x86_64 architecture
memory-hotplug: remove memmap of sparse-vmemmap
memory-hotplug: Integrated __remove_section() of
CONFIG_SPARSEMEM_VMEMMAP.
memory-hotplug: remove sysfs file of node
memory-hotplug: Do not allocate pdgat if it was not freed when
offline.
Wen Congyang (5):
memory-hotplug: try to offline the memory twice to avoid dependence
memory-hotplug: remove redundant codes
memory-hotplug: introduce new function arch_remove_memory() for
removing page table depends on architecture
memory-hotplug: Common APIs to support page tables hot-remove
memory-hotplug: free node_data when a node is offlined
Yasuaki Ishimatsu (4):
memory-hotplug: check whether all memory blocks are offlined or not
when removing memory
memory-hotplug: remove /sys/firmware/memmap/X sysfs
memory-hotplug: implement register_page_bootmem_info_section of
sparse-vmemmap
memory-hotplug: memory_hotplug: clear zone when removing the memory
arch/arm64/mm/mmu.c | 3 +
arch/ia64/mm/discontig.c | 10 +
arch/ia64/mm/init.c | 18 ++
arch/powerpc/mm/init_64.c | 10 +
arch/powerpc/mm/mem.c | 12 +
arch/s390/mm/init.c | 12 +
arch/s390/mm/vmem.c | 10 +
arch/sh/mm/init.c | 17 ++
arch/sparc/mm/init_64.c | 10 +
arch/tile/mm/init.c | 8 +
arch/x86/include/asm/pgtable_types.h | 1 +
arch/x86/mm/init_32.c | 12 +
arch/x86/mm/init_64.c | 390 +++++++++++++++++++++++++++++
arch/x86/mm/pageattr.c | 47 ++--
drivers/acpi/acpi_memhotplug.c | 8 +-
drivers/base/memory.c | 6 +
drivers/firmware/memmap.c | 96 +++++++-
include/linux/bootmem.h | 1 +
include/linux/firmware-map.h | 6 +
include/linux/memory_hotplug.h | 15 +-
include/linux/mm.h | 4 +-
mm/memory_hotplug.c | 459 +++++++++++++++++++++++++++++++---
mm/sparse.c | 8 +-
23 files changed, 1094 insertions(+), 69 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email:<a href=mailto:"dont@kvack.org"> email@kvack.org</a>
Hi Simon,
Please see below. :)
On 01/31/2013 09:22 AM, Simon Jeons wrote:
Sorry, I still confuse. :(
update node_states[N_NORMAL_MEMORY] to node_states[N_MEMORY] or
node_states[N_NORMAL_MEMOR] present 0...ZONE_MOVABLE?
node_states is what? node_states[N_NORMAL_MEMOR] or
node_states[N_MEMORY]?
Are you asking what node_states[] is ?
node_states[] is an array of nodemask,
extern nodemask_t node_states[NR_NODE_STATES];
For example, node_states[N_NORMAL_MEMOR] represents which nodes have
normal memory.
If N_MEMORY == N_HIGH_MEMORY == N_NORMAL_MEMORY, node_states[N_MEMORY] is
node_states[N_NORMAL_MEMOR]. So it represents which nodes have 0 ...
ZONE_MOVABLE.
Why check !z1->wait_table in function move_pfn_range_left and function
__add_zone? I think zone->wait_table is initialized in
free_area_init_core, which will be called during system initialization
and hotadd_new_pgdat path.
I think,
free_area_init_core(), in the for loop,
|--> size = zone_spanned_pages_in_node();
|--> if (!size)
continue; ---------------- If zone is empty, we jump
out the for loop.
|--> init_currently_empty_zone()
So, if the zone is empty, wait_table is not initialized.
In move_pfn_range_left(z1, z2), we move pages from z2 to z1. But z1
could be empty.
So we need to check it and initialize z1->wait_table because we are
moving pages into it.
There is a zone populated check in function online_pages. But zone is
populated in free_area_init_core which will be called during system
initialization and hotadd_new_pgdat path. Why still need this check?
Because we could also rebuild zone list when we offline pages.
__offline_pages()
|--> zone->present_pages -= offlined_pages;
|--> if (!populated_zone(zone)) {
build_all_zonelists(NULL, NULL);
}
If the zone is empty, and other zones on the same node is not empty, the
node
won't be offlined, and next time we online pages of this zone, the pgdat
won't
be initialized again, and we need to check populated_zone(zone) when
onlining
pages.
Thanks. :)
From: Simon Jeons <hidden> Date: 2013-01-31 06:19:36
Hi Tang,
On Thu, 2013-01-31 at 11:31 +0800, Tang Chen wrote:
Hi Simon,
Please see below. :)
On 01/31/2013 09:22 AM, Simon Jeons wrote:
quoted
Sorry, I still confuse. :(
update node_states[N_NORMAL_MEMORY] to node_states[N_MEMORY] or
node_states[N_NORMAL_MEMOR] present 0...ZONE_MOVABLE?
node_states is what? node_states[N_NORMAL_MEMOR] or
node_states[N_MEMORY]?
Are you asking what node_states[] is ?
node_states[] is an array of nodemask,
extern nodemask_t node_states[NR_NODE_STATES];
For example, node_states[N_NORMAL_MEMOR] represents which nodes have
normal memory.
If N_MEMORY == N_HIGH_MEMORY == N_NORMAL_MEMORY, node_states[N_MEMORY] is
node_states[N_NORMAL_MEMOR]. So it represents which nodes have 0 ...
ZONE_MOVABLE.
Sorry, how can nodes_state[N_NORMAL_MEMORY] represents a node have 0 ...
*ZONE_MOVABLE*, the comment of enum nodes_states said that
N_NORMAL_MEMORY just means the node has regular memory.
quoted
Why check !z1->wait_table in function move_pfn_range_left and function
__add_zone? I think zone->wait_table is initialized in
free_area_init_core, which will be called during system initialization
and hotadd_new_pgdat path.
I think,
free_area_init_core(), in the for loop,
|--> size = zone_spanned_pages_in_node();
|--> if (!size)
continue; ---------------- If zone is empty, we jump
out the for loop.
|--> init_currently_empty_zone()
So, if the zone is empty, wait_table is not initialized.
In move_pfn_range_left(z1, z2), we move pages from z2 to z1. But z1
could be empty.
So we need to check it and initialize z1->wait_table because we are
moving pages into it.
thanks.
quoted
There is a zone populated check in function online_pages. But zone is
populated in free_area_init_core which will be called during system
initialization and hotadd_new_pgdat path. Why still need this check?
Because we could also rebuild zone list when we offline pages.
__offline_pages()
|--> zone->present_pages -= offlined_pages;
|--> if (!populated_zone(zone)) {
build_all_zonelists(NULL, NULL);
}
If the zone is empty, and other zones on the same node is not empty, the
node
won't be offlined, and next time we online pages of this zone, the pgdat
won't
be initialized again, and we need to check populated_zone(zone) when
onlining
pages.
thanks.
Thanks. :)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
Hi Tang,
On Thu, 2013-01-31 at 11:31 +0800, Tang Chen wrote:
quoted
Hi Simon,
Please see below. :)
On 01/31/2013 09:22 AM, Simon Jeons wrote:
quoted
Sorry, I still confuse. :(
update node_states[N_NORMAL_MEMORY] to node_states[N_MEMORY] or
node_states[N_NORMAL_MEMOR] present 0...ZONE_MOVABLE?
node_states is what? node_states[N_NORMAL_MEMOR] or
node_states[N_MEMORY]?
Are you asking what node_states[] is ?
node_states[] is an array of nodemask,
extern nodemask_t node_states[NR_NODE_STATES];
For example, node_states[N_NORMAL_MEMOR] represents which nodes have
normal memory.
If N_MEMORY == N_HIGH_MEMORY == N_NORMAL_MEMORY, node_states[N_MEMORY] is
node_states[N_NORMAL_MEMOR]. So it represents which nodes have 0 ...
ZONE_MOVABLE.
Sorry, how can nodes_state[N_NORMAL_MEMORY] represents a node have 0 ...
*ZONE_MOVABLE*, the comment of enum nodes_states said that
N_NORMAL_MEMORY just means the node has regular memory.
Hi Simon,
Let's say it in this way.
If we don't have CONFIG_HIGHMEM, N_HIGH_MEMORY == N_NORMAL_MEMORY. We
don't have a separate
macro to represent highmem because we don't have highmem.
This is easy to understand, right ?
Now, think it just like above:
If we don't have CONFIG_MOVABLE_NODE, N_MEMORY == N_HIGH_MEMORY ==
N_NORMAL_MEMORY.
This means we don't allow a node to have only movable memory, not we
don't have movable memory.
A node could have normal memory and movable memory. So
nodes_state[N_NORMAL_MEMORY] represents
a node have 0 ... *ZONE_MOVABLE*.
I think the point is: CONFIG_MOVABLE_NODE means we allow a node to have
only movable memory.
So without CONFIG_MOVABLE_NODE, it doesn't mean a node cannot have
movable memory. It means
the node cannot have only movable memory. It can have normal memory and
movable memory.
1) With CONFIG_MOVABLE_NODE:
N_NORMAL_MEMORY: nodes who have normal memory.
normal memory only
normal and highmem
normal and highmem and movablemem
normal and movablemem
N_MEMORY: nodes who has memory (any memory)
normal memory only
normal and highmem
normal and highmem and movablemem
normal and movablemem ---------------- We can have
movablemem.
highmem only -------------------------
highmem and movablemem ---------------
movablemem only ---------------------- We can have
movablemem only. ***
2) With out CONFIG_MOVABLE_NODE:
N_MEMORY == N_NORMAL_MEMORY: (Here, I omit N_HIGH_MEMORY)
normal memory only
normal and highmem
normal and highmem and movablemem
normal and movablemem ---------------- We can have
movablemem.
No movablemem only ------------------- We cannot
have movablemem only. ***
The semantics is not that clear here. So we can only try to understand
it from the code where
we use N_MEMORY. :)
That is my understanding of this.
Thanks. :)
From: Simon Jeons <hidden> Date: 2013-01-31 08:17:20
Hi Tang,
On Thu, 2013-01-31 at 15:10 +0800, Tang Chen wrote:
On 01/31/2013 02:19 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Thu, 2013-01-31 at 11:31 +0800, Tang Chen wrote:
quoted
Hi Simon,
Please see below. :)
On 01/31/2013 09:22 AM, Simon Jeons wrote:
quoted
Sorry, I still confuse. :(
update node_states[N_NORMAL_MEMORY] to node_states[N_MEMORY] or
node_states[N_NORMAL_MEMOR] present 0...ZONE_MOVABLE?
node_states is what? node_states[N_NORMAL_MEMOR] or
node_states[N_MEMORY]?
Are you asking what node_states[] is ?
node_states[] is an array of nodemask,
extern nodemask_t node_states[NR_NODE_STATES];
For example, node_states[N_NORMAL_MEMOR] represents which nodes have
normal memory.
If N_MEMORY == N_HIGH_MEMORY == N_NORMAL_MEMORY, node_states[N_MEMORY] is
node_states[N_NORMAL_MEMOR]. So it represents which nodes have 0 ...
ZONE_MOVABLE.
Sorry, how can nodes_state[N_NORMAL_MEMORY] represents a node have 0 ...
*ZONE_MOVABLE*, the comment of enum nodes_states said that
N_NORMAL_MEMORY just means the node has regular memory.
Hi Simon,
Let's say it in this way.
If we don't have CONFIG_HIGHMEM, N_HIGH_MEMORY == N_NORMAL_MEMORY. We
don't have a separate
macro to represent highmem because we don't have highmem.
This is easy to understand, right ?
Now, think it just like above:
If we don't have CONFIG_MOVABLE_NODE, N_MEMORY == N_HIGH_MEMORY ==
N_NORMAL_MEMORY.
This means we don't allow a node to have only movable memory, not we
don't have movable memory.
A node could have normal memory and movable memory. So
nodes_state[N_NORMAL_MEMORY] represents
a node have 0 ... *ZONE_MOVABLE*.
I think the point is: CONFIG_MOVABLE_NODE means we allow a node to have
only movable memory.
So without CONFIG_MOVABLE_NODE, it doesn't mean a node cannot have
movable memory. It means
the node cannot have only movable memory. It can have normal memory and
movable memory.
1) With CONFIG_MOVABLE_NODE:
N_NORMAL_MEMORY: nodes who have normal memory.
normal memory only
normal and highmem
normal and highmem and movablemem
normal and movablemem
N_MEMORY: nodes who has memory (any memory)
normal memory only
normal and highmem
normal and highmem and movablemem
normal and movablemem ---------------- We can have
movablemem.
highmem only -------------------------
highmem and movablemem ---------------
movablemem only ---------------------- We can have
movablemem only. ***
2) With out CONFIG_MOVABLE_NODE:
N_MEMORY == N_NORMAL_MEMORY: (Here, I omit N_HIGH_MEMORY)
normal memory only
normal and highmem
normal and highmem and movablemem
normal and movablemem ---------------- We can have
movablemem.
No movablemem only ------------------- We cannot
have movablemem only. ***
The semantics is not that clear here. So we can only try to understand
it from the code where
we use N_MEMORY. :)
That is my understanding of this.
Thanks for your clarify, very clear now. :)
Thanks. :)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Simon Jeons <hidden> Date: 2013-01-31 08:48:52
Hi Tang,
On Thu, 2013-01-31 at 15:10 +0800, Tang Chen wrote:
1. IIUC, there is a button on machine which supports hot-remove memory,
then what's the difference between press button and echo to /sys?
2. Since kernel memory is linear mapping(I mean direct mapping part),
why can't put kernel direct mapping memory into one memory device, and
other memory into the other devices? As you know x86_64 don't need
highmem, IIUC, all kernel memory will linear mapping in this case. Is my
idea available? If is correct, x86_32 can't implement in the same way
since highmem(kmap/kmap_atomic/vmalloc) can map any address, so it's
hard to focus kernel memory on single memory device.
3. In current implementation, if memory hotplug just need memory
subsystem and ACPI codes support? Or also needs firmware take part in?
Hope you can explain in details, thanks in advance. :)
4. What's the status of memory hotplug? Apart from can't remove kernel
memory, other things are fully implementation?
On 01/31/2013 02:19 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Thu, 2013-01-31 at 11:31 +0800, Tang Chen wrote:
quoted
Hi Simon,
Please see below. :)
On 01/31/2013 09:22 AM, Simon Jeons wrote:
quoted
Sorry, I still confuse. :(
update node_states[N_NORMAL_MEMORY] to node_states[N_MEMORY] or
node_states[N_NORMAL_MEMOR] present 0...ZONE_MOVABLE?
node_states is what? node_states[N_NORMAL_MEMOR] or
node_states[N_MEMORY]?
Are you asking what node_states[] is ?
node_states[] is an array of nodemask,
extern nodemask_t node_states[NR_NODE_STATES];
For example, node_states[N_NORMAL_MEMOR] represents which nodes have
normal memory.
If N_MEMORY == N_HIGH_MEMORY == N_NORMAL_MEMORY, node_states[N_MEMORY] is
node_states[N_NORMAL_MEMOR]. So it represents which nodes have 0 ...
ZONE_MOVABLE.
Sorry, how can nodes_state[N_NORMAL_MEMORY] represents a node have 0 ...
*ZONE_MOVABLE*, the comment of enum nodes_states said that
N_NORMAL_MEMORY just means the node has regular memory.
Hi Simon,
Let's say it in this way.
If we don't have CONFIG_HIGHMEM, N_HIGH_MEMORY == N_NORMAL_MEMORY. We
don't have a separate
macro to represent highmem because we don't have highmem.
This is easy to understand, right ?
Now, think it just like above:
If we don't have CONFIG_MOVABLE_NODE, N_MEMORY == N_HIGH_MEMORY ==
N_NORMAL_MEMORY.
This means we don't allow a node to have only movable memory, not we
don't have movable memory.
A node could have normal memory and movable memory. So
nodes_state[N_NORMAL_MEMORY] represents
a node have 0 ... *ZONE_MOVABLE*.
I think the point is: CONFIG_MOVABLE_NODE means we allow a node to have
only movable memory.
So without CONFIG_MOVABLE_NODE, it doesn't mean a node cannot have
movable memory. It means
the node cannot have only movable memory. It can have normal memory and
movable memory.
1) With CONFIG_MOVABLE_NODE:
N_NORMAL_MEMORY: nodes who have normal memory.
normal memory only
normal and highmem
normal and highmem and movablemem
normal and movablemem
N_MEMORY: nodes who has memory (any memory)
normal memory only
normal and highmem
normal and highmem and movablemem
normal and movablemem ---------------- We can have
movablemem.
highmem only -------------------------
highmem and movablemem ---------------
movablemem only ---------------------- We can have
movablemem only. ***
2) With out CONFIG_MOVABLE_NODE:
N_MEMORY == N_NORMAL_MEMORY: (Here, I omit N_HIGH_MEMORY)
normal memory only
normal and highmem
normal and highmem and movablemem
normal and movablemem ---------------- We can have
movablemem.
No movablemem only ------------------- We cannot
have movablemem only. ***
The semantics is not that clear here. So we can only try to understand
it from the code where
we use N_MEMORY. :)
That is my understanding of this.
Thanks. :)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
Hi Simon,
On 01/31/2013 04:48 PM, Simon Jeons wrote:
Hi Tang,
On Thu, 2013-01-31 at 15:10 +0800, Tang Chen wrote:
1. IIUC, there is a button on machine which supports hot-remove memory,
then what's the difference between press button and echo to /sys?
No important difference, I think. Since I don't have the machine you are
saying, I cannot surely answer you. :)
AFAIK, pressing the button means trigger the hotplug from hardware, sysfs
is just another entrance. At last, they will run into the same code.
2. Since kernel memory is linear mapping(I mean direct mapping part),
why can't put kernel direct mapping memory into one memory device, and
other memory into the other devices?
We cannot do that because in that way, we will lose NUMA performance.
If you know NUMA, you will understand the following example:
node0: node1:
cpu0~cpu15 cpu16~cpu31
memory0~memory511 memory512~memory1023
cpu16~cpu31 access memory16~memory1023 much faster than memory0~memory511.
If we set direct mapping area in node0, and movable area in node1, then
the kernel code running on cpu16~cpu31 will have to access
memory0~memory511.
This is a terrible performance down.
As you know x86_64 don't need
highmem, IIUC, all kernel memory will linear mapping in this case. Is my
idea available? If is correct, x86_32 can't implement in the same way
since highmem(kmap/kmap_atomic/vmalloc) can map any address, so it's
hard to focus kernel memory on single memory device.
Sorry, I'm not quite familiar with x86_32 box.
3. In current implementation, if memory hotplug just need memory
subsystem and ACPI codes support? Or also needs firmware take part in?
Hope you can explain in details, thanks in advance. :)
We need firmware take part in, such as SRAT in ACPI BIOS, or the firmware
based memory migration mentioned by Liu Jiang.
So far, I only know this. :)
4. What's the status of memory hotplug? Apart from can't remove kernel
memory, other things are fully implementation?
I think the main job is done for now. And there are still bugs to fix.
And this functionality is not stable.
Thanks. :)
From: Simon Jeons <hidden> Date: 2013-01-31 10:38:43
Hi Tang,
On Thu, 2013-01-31 at 17:44 +0800, Tang Chen wrote:
Hi Simon,
On 01/31/2013 04:48 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Thu, 2013-01-31 at 15:10 +0800, Tang Chen wrote:
1. IIUC, there is a button on machine which supports hot-remove memory,
then what's the difference between press button and echo to /sys?
No important difference, I think. Since I don't have the machine you are
saying, I cannot surely answer you. :)
AFAIK, pressing the button means trigger the hotplug from hardware, sysfs
is just another entrance. At last, they will run into the same code.
quoted
2. Since kernel memory is linear mapping(I mean direct mapping part),
why can't put kernel direct mapping memory into one memory device, and
other memory into the other devices?
We cannot do that because in that way, we will lose NUMA performance.
If you know NUMA, you will understand the following example:
node0: node1:
cpu0~cpu15 cpu16~cpu31
memory0~memory511 memory512~memory1023
cpu16~cpu31 access memory16~memory1023 much faster than memory0~memory511.
If we set direct mapping area in node0, and movable area in node1, then
the kernel code running on cpu16~cpu31 will have to access
memory0~memory511.
This is a terrible performance down.
So if config NUMA, kernel memory will not be linear mapping anymore? For
example,
Node 0 Node 1
0 ~ 10G 11G~14G
kernel memory only at Node 0? Can part of kernel memory also at Node 1?
How big is kernel direct mapping memory in x86_64? Is there max limit?
It seems that only around 896MB on x86_32.
quoted
As you know x86_64 don't need
highmem, IIUC, all kernel memory will linear mapping in this case. Is my
idea available? If is correct, x86_32 can't implement in the same way
since highmem(kmap/kmap_atomic/vmalloc) can map any address, so it's
hard to focus kernel memory on single memory device.
Sorry, I'm not quite familiar with x86_32 box.
quoted
3. In current implementation, if memory hotplug just need memory
subsystem and ACPI codes support? Or also needs firmware take part in?
Hope you can explain in details, thanks in advance. :)
We need firmware take part in, such as SRAT in ACPI BIOS, or the firmware
based memory migration mentioned by Liu Jiang.
Is there any material about firmware based memory migration?
So far, I only know this. :)
quoted
4. What's the status of memory hotplug? Apart from can't remove kernel
memory, other things are fully implementation?
I think the main job is done for now. And there are still bugs to fix.
And this functionality is not stable.
Thanks. :)
Hi Tang,
On Thu, 2013-01-31 at 17:44 +0800, Tang Chen wrote:
quoted
Hi Simon,
On 01/31/2013 04:48 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Thu, 2013-01-31 at 15:10 +0800, Tang Chen wrote:
1. IIUC, there is a button on machine which supports hot-remove memory,
then what's the difference between press button and echo to /sys?
No important difference, I think. Since I don't have the machine you are
saying, I cannot surely answer you. :)
AFAIK, pressing the button means trigger the hotplug from hardware, sysfs
is just another entrance. At last, they will run into the same code.
quoted
2. Since kernel memory is linear mapping(I mean direct mapping part),
why can't put kernel direct mapping memory into one memory device, and
other memory into the other devices?
We cannot do that because in that way, we will lose NUMA performance.
If you know NUMA, you will understand the following example:
node0: node1:
cpu0~cpu15 cpu16~cpu31
memory0~memory511 memory512~memory1023
cpu16~cpu31 access memory16~memory1023 much faster than memory0~memory511.
If we set direct mapping area in node0, and movable area in node1, then
the kernel code running on cpu16~cpu31 will have to access
memory0~memory511.
This is a terrible performance down.
So if config NUMA, kernel memory will not be linear mapping anymore? For
example,
Node 0 Node 1
0 ~ 10G 11G~14G
kernel memory only at Node 0? Can part of kernel memory also at Node 1?
How big is kernel direct mapping memory in x86_64? Is there max limit?
Max kernel direct mapping memory in x86_64 is 64TB.
It seems that only around 896MB on x86_32.
quoted
quoted
As you know x86_64 don't need
highmem, IIUC, all kernel memory will linear mapping in this case. Is my
idea available? If is correct, x86_32 can't implement in the same way
since highmem(kmap/kmap_atomic/vmalloc) can map any address, so it's
hard to focus kernel memory on single memory device.
Sorry, I'm not quite familiar with x86_32 box.
quoted
3. In current implementation, if memory hotplug just need memory
subsystem and ACPI codes support? Or also needs firmware take part in?
Hope you can explain in details, thanks in advance. :)
We need firmware take part in, such as SRAT in ACPI BIOS, or the firmware
based memory migration mentioned by Liu Jiang.
Is there any material about firmware based memory migration?
quoted
So far, I only know this. :)
quoted
4. What's the status of memory hotplug? Apart from can't remove kernel
memory, other things are fully implementation?
I think the main job is done for now. And there are still bugs to fix.
And this functionality is not stable.
Thanks. :)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
.
From: Simon Jeons <hidden> Date: 2013-02-01 01:36:28
On Fri, 2013-02-01 at 09:32 +0800, Jianguo Wu wrote:
On 2013/1/31 18:38, Simon Jeons wrote:
quoted
Hi Tang,
On Thu, 2013-01-31 at 17:44 +0800, Tang Chen wrote:
quoted
Hi Simon,
On 01/31/2013 04:48 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Thu, 2013-01-31 at 15:10 +0800, Tang Chen wrote:
1. IIUC, there is a button on machine which supports hot-remove memory,
then what's the difference between press button and echo to /sys?
No important difference, I think. Since I don't have the machine you are
saying, I cannot surely answer you. :)
AFAIK, pressing the button means trigger the hotplug from hardware, sysfs
is just another entrance. At last, they will run into the same code.
quoted
2. Since kernel memory is linear mapping(I mean direct mapping part),
why can't put kernel direct mapping memory into one memory device, and
other memory into the other devices?
We cannot do that because in that way, we will lose NUMA performance.
If you know NUMA, you will understand the following example:
node0: node1:
cpu0~cpu15 cpu16~cpu31
memory0~memory511 memory512~memory1023
cpu16~cpu31 access memory16~memory1023 much faster than memory0~memory511.
If we set direct mapping area in node0, and movable area in node1, then
the kernel code running on cpu16~cpu31 will have to access
memory0~memory511.
This is a terrible performance down.
So if config NUMA, kernel memory will not be linear mapping anymore? For
example,
Node 0 Node 1
0 ~ 10G 11G~14G
kernel memory only at Node 0? Can part of kernel memory also at Node 1?
How big is kernel direct mapping memory in x86_64? Is there max limit?
Max kernel direct mapping memory in x86_64 is 64TB.
For example, I have 8G memory, all of them will be direct mapping for
kernel? then userspace memory allocated from where?
quoted
It seems that only around 896MB on x86_32.
quoted
quoted
As you know x86_64 don't need
highmem, IIUC, all kernel memory will linear mapping in this case. Is my
idea available? If is correct, x86_32 can't implement in the same way
since highmem(kmap/kmap_atomic/vmalloc) can map any address, so it's
hard to focus kernel memory on single memory device.
Sorry, I'm not quite familiar with x86_32 box.
quoted
3. In current implementation, if memory hotplug just need memory
subsystem and ACPI codes support? Or also needs firmware take part in?
Hope you can explain in details, thanks in advance. :)
We need firmware take part in, such as SRAT in ACPI BIOS, or the firmware
based memory migration mentioned by Liu Jiang.
Is there any material about firmware based memory migration?
quoted
So far, I only know this. :)
quoted
4. What's the status of memory hotplug? Apart from can't remove kernel
memory, other things are fully implementation?
I think the main job is done for now. And there are still bugs to fix.
And this functionality is not stable.
Thanks. :)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
.
On Fri, 2013-02-01 at 09:32 +0800, Jianguo Wu wrote:
quoted
quoted
So if config NUMA, kernel memory will not be linear mapping anymore? For
example,
Node 0 Node 1
0 ~ 10G 11G~14G
It has nothing to do with linear mapping, I think.
quoted
quoted
kernel memory only at Node 0? Can part of kernel memory also at Node 1?
Please refer to find_zone_movable_pfns_for_nodes().
The kernel is not only on node0. It uses all the online nodes evenly. :)
quoted
quoted
How big is kernel direct mapping memory in x86_64? Is there max limit?
Max kernel direct mapping memory in x86_64 is 64TB.
For example, I have 8G memory, all of them will be direct mapping for
kernel? then userspace memory allocated from where?
I think you misunderstood what Wu tried to say. :)
The kernel mapped that large space, it doesn't mean it is using that
large space.
The mapping is to make kernel be able to access all the memory, not for
the kernel
to use only. User space can also use the memory, but each process has
its own mapping.
For example:
64TB, what ever
xxxTB, what ever
logic address space: |_____kernel_______|_________user_________________|
\ \ / /
\ /\ /
physical address space: |___\/__\/_____________| 4GB or
8GB, what ever
*****
The ***** part physical is mapped to user space in the process' own
pagetable.
It is also direct mapped in kernel's pagetable. So the kernel can also
access it. :)
quoted
quoted
It seems that only around 896MB on x86_32.
quoted
We need firmware take part in, such as SRAT in ACPI BIOS, or the firmware
based memory migration mentioned by Liu Jiang.
Is there any material about firmware based memory migration?
No, I don't have any because this is a functionality of machine from HUAWEI.
I think you can ask Liu Jiang or Wu Jianguo to share some with you. :)
Thanks. :)
On Fri, 2013-02-01 at 09:32 +0800, Jianguo Wu wrote:
quoted
On 2013/1/31 18:38, Simon Jeons wrote:
quoted
Hi Tang,
On Thu, 2013-01-31 at 17:44 +0800, Tang Chen wrote:
quoted
Hi Simon,
On 01/31/2013 04:48 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Thu, 2013-01-31 at 15:10 +0800, Tang Chen wrote:
1. IIUC, there is a button on machine which supports hot-remove memory,
then what's the difference between press button and echo to /sys?
No important difference, I think. Since I don't have the machine you are
saying, I cannot surely answer you. :)
AFAIK, pressing the button means trigger the hotplug from hardware, sysfs
is just another entrance. At last, they will run into the same code.
quoted
2. Since kernel memory is linear mapping(I mean direct mapping part),
why can't put kernel direct mapping memory into one memory device, and
other memory into the other devices?
We cannot do that because in that way, we will lose NUMA performance.
If you know NUMA, you will understand the following example:
node0: node1:
cpu0~cpu15 cpu16~cpu31
memory0~memory511 memory512~memory1023
cpu16~cpu31 access memory16~memory1023 much faster than memory0~memory511.
If we set direct mapping area in node0, and movable area in node1, then
the kernel code running on cpu16~cpu31 will have to access
memory0~memory511.
This is a terrible performance down.
So if config NUMA, kernel memory will not be linear mapping anymore? For
example,
Node 0 Node 1
0 ~ 10G 11G~14G
kernel memory only at Node 0? Can part of kernel memory also at Node 1?
How big is kernel direct mapping memory in x86_64? Is there max limit?
Max kernel direct mapping memory in x86_64 is 64TB.
For example, I have 8G memory, all of them will be direct mapping for
kernel? then userspace memory allocated from where?
Direct mapping memory means you can use __va() and pa(), but not means that them
can be only used by kernel, them can be used by user-space too, as long as them are free.
quoted
quoted
It seems that only around 896MB on x86_32.
quoted
quoted
As you know x86_64 don't need
highmem, IIUC, all kernel memory will linear mapping in this case. Is my
idea available? If is correct, x86_32 can't implement in the same way
since highmem(kmap/kmap_atomic/vmalloc) can map any address, so it's
hard to focus kernel memory on single memory device.
Sorry, I'm not quite familiar with x86_32 box.
quoted
3. In current implementation, if memory hotplug just need memory
subsystem and ACPI codes support? Or also needs firmware take part in?
Hope you can explain in details, thanks in advance. :)
We need firmware take part in, such as SRAT in ACPI BIOS, or the firmware
based memory migration mentioned by Liu Jiang.
Is there any material about firmware based memory migration?
quoted
So far, I only know this. :)
quoted
4. What's the status of memory hotplug? Apart from can't remove kernel
memory, other things are fully implementation?
I think the main job is done for now. And there are still bugs to fix.
And this functionality is not stable.
Thanks. :)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
.
From: Simon Jeons <hidden> Date: 2013-02-01 02:06:58
Hi Jianguo,
On Fri, 2013-02-01 at 09:57 +0800, Jianguo Wu wrote:
On 2013/2/1 9:36, Simon Jeons wrote:
quoted
On Fri, 2013-02-01 at 09:32 +0800, Jianguo Wu wrote:
quoted
On 2013/1/31 18:38, Simon Jeons wrote:
quoted
Hi Tang,
On Thu, 2013-01-31 at 17:44 +0800, Tang Chen wrote:
quoted
Hi Simon,
On 01/31/2013 04:48 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Thu, 2013-01-31 at 15:10 +0800, Tang Chen wrote:
1. IIUC, there is a button on machine which supports hot-remove memory,
then what's the difference between press button and echo to /sys?
No important difference, I think. Since I don't have the machine you are
saying, I cannot surely answer you. :)
AFAIK, pressing the button means trigger the hotplug from hardware, sysfs
is just another entrance. At last, they will run into the same code.
quoted
2. Since kernel memory is linear mapping(I mean direct mapping part),
why can't put kernel direct mapping memory into one memory device, and
other memory into the other devices?
We cannot do that because in that way, we will lose NUMA performance.
If you know NUMA, you will understand the following example:
node0: node1:
cpu0~cpu15 cpu16~cpu31
memory0~memory511 memory512~memory1023
cpu16~cpu31 access memory16~memory1023 much faster than memory0~memory511.
If we set direct mapping area in node0, and movable area in node1, then
the kernel code running on cpu16~cpu31 will have to access
memory0~memory511.
This is a terrible performance down.
So if config NUMA, kernel memory will not be linear mapping anymore? For
example,
Node 0 Node 1
0 ~ 10G 11G~14G
kernel memory only at Node 0? Can part of kernel memory also at Node 1?
How big is kernel direct mapping memory in x86_64? Is there max limit?
Max kernel direct mapping memory in x86_64 is 64TB.
For example, I have 8G memory, all of them will be direct mapping for
kernel? then userspace memory allocated from where?
Direct mapping memory means you can use __va() and pa(), but not means that them
can be only used by kernel, them can be used by user-space too, as long as them are free.
IIUC, the benefit of va() and pa() is just for quick get
virtual/physical address, it takes advantage of linear mapping. But mmu
still need to go through pgd/pud/pmd/pte, correct?
quoted
quoted
quoted
It seems that only around 896MB on x86_32.
quoted
quoted
As you know x86_64 don't need
highmem, IIUC, all kernel memory will linear mapping in this case. Is my
idea available? If is correct, x86_32 can't implement in the same way
since highmem(kmap/kmap_atomic/vmalloc) can map any address, so it's
hard to focus kernel memory on single memory device.
Sorry, I'm not quite familiar with x86_32 box.
quoted
3. In current implementation, if memory hotplug just need memory
subsystem and ACPI codes support? Or also needs firmware take part in?
Hope you can explain in details, thanks in advance. :)
We need firmware take part in, such as SRAT in ACPI BIOS, or the firmware
based memory migration mentioned by Liu Jiang.
Is there any material about firmware based memory migration?
quoted
So far, I only know this. :)
quoted
4. What's the status of memory hotplug? Apart from can't remove kernel
memory, other things are fully implementation?
I think the main job is done for now. And there are still bugs to fix.
And this functionality is not stable.
Thanks. :)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
.
From: Simon Jeons <hidden> Date: 2013-02-01 02:17:30
Hi Tang,
On Fri, 2013-02-01 at 09:57 +0800, Tang Chen wrote:
On 02/01/2013 09:36 AM, Simon Jeons wrote:
quoted
On Fri, 2013-02-01 at 09:32 +0800, Jianguo Wu wrote:
quoted
quoted
So if config NUMA, kernel memory will not be linear mapping anymore? For
example,
Node 0 Node 1
0 ~ 10G 11G~14G
It has nothing to do with linear mapping, I think.
quoted
quoted
quoted
kernel memory only at Node 0? Can part of kernel memory also at Node 1?
Please refer to find_zone_movable_pfns_for_nodes().
I see, thanks. :)
The kernel is not only on node0. It uses all the online nodes evenly. :)
quoted
quoted
quoted
How big is kernel direct mapping memory in x86_64? Is there max limit?
Max kernel direct mapping memory in x86_64 is 64TB.
For example, I have 8G memory, all of them will be direct mapping for
kernel? then userspace memory allocated from where?
I think you misunderstood what Wu tried to say. :)
The kernel mapped that large space, it doesn't mean it is using that
large space.
The mapping is to make kernel be able to access all the memory, not for
the kernel
to use only. User space can also use the memory, but each process has
its own mapping.
For example:
64TB, what ever
xxxTB, what ever
logic address space: |_____kernel_______|_________user_________________|
\ \ / /
\ /\ /
physical address space: |___\/__\/_____________| 4GB or
8GB, what ever
*****
How much address space user process can have on x86_64? Also 8GB?
The ***** part physical is mapped to user space in the process' own
pagetable.
It is also direct mapped in kernel's pagetable. So the kernel can also
access it. :)
But how to protect user process not modify kernel memory?
quoted
quoted
quoted
It seems that only around 896MB on x86_32.
quoted
We need firmware take part in, such as SRAT in ACPI BIOS, or the firmware
based memory migration mentioned by Liu Jiang.
Is there any material about firmware based memory migration?
No, I don't have any because this is a functionality of machine from HUAWEI.
I think you can ask Liu Jiang or Wu Jianguo to share some with you. :)
Thanks. :)
Hi Jianguo,
On Fri, 2013-02-01 at 09:57 +0800, Jianguo Wu wrote:
quoted
On 2013/2/1 9:36, Simon Jeons wrote:
quoted
On Fri, 2013-02-01 at 09:32 +0800, Jianguo Wu wrote:
quoted
On 2013/1/31 18:38, Simon Jeons wrote:
quoted
Hi Tang,
On Thu, 2013-01-31 at 17:44 +0800, Tang Chen wrote:
quoted
Hi Simon,
On 01/31/2013 04:48 PM, Simon Jeons wrote:
quoted
Hi Tang,
On Thu, 2013-01-31 at 15:10 +0800, Tang Chen wrote:
1. IIUC, there is a button on machine which supports hot-remove memory,
then what's the difference between press button and echo to /sys?
No important difference, I think. Since I don't have the machine you are
saying, I cannot surely answer you. :)
AFAIK, pressing the button means trigger the hotplug from hardware, sysfs
is just another entrance. At last, they will run into the same code.
quoted
2. Since kernel memory is linear mapping(I mean direct mapping part),
why can't put kernel direct mapping memory into one memory device, and
other memory into the other devices?
We cannot do that because in that way, we will lose NUMA performance.
If you know NUMA, you will understand the following example:
node0: node1:
cpu0~cpu15 cpu16~cpu31
memory0~memory511 memory512~memory1023
cpu16~cpu31 access memory16~memory1023 much faster than memory0~memory511.
If we set direct mapping area in node0, and movable area in node1, then
the kernel code running on cpu16~cpu31 will have to access
memory0~memory511.
This is a terrible performance down.
So if config NUMA, kernel memory will not be linear mapping anymore? For
example,
Node 0 Node 1
0 ~ 10G 11G~14G
kernel memory only at Node 0? Can part of kernel memory also at Node 1?
How big is kernel direct mapping memory in x86_64? Is there max limit?
Max kernel direct mapping memory in x86_64 is 64TB.
For example, I have 8G memory, all of them will be direct mapping for
kernel? then userspace memory allocated from where?
Direct mapping memory means you can use __va() and pa(), but not means that them
can be only used by kernel, them can be used by user-space too, as long as them are free.
IIUC, the benefit of va() and pa() is just for quick get
virtual/physical address, it takes advantage of linear mapping. But mmu
still need to go through pgd/pud/pmd/pte, correct?
Yes.
quoted
quoted
quoted
quoted
It seems that only around 896MB on x86_32.
quoted
quoted
As you know x86_64 don't need
highmem, IIUC, all kernel memory will linear mapping in this case. Is my
idea available? If is correct, x86_32 can't implement in the same way
since highmem(kmap/kmap_atomic/vmalloc) can map any address, so it's
hard to focus kernel memory on single memory device.
Sorry, I'm not quite familiar with x86_32 box.
quoted
3. In current implementation, if memory hotplug just need memory
subsystem and ACPI codes support? Or also needs firmware take part in?
Hope you can explain in details, thanks in advance. :)
We need firmware take part in, such as SRAT in ACPI BIOS, or the firmware
based memory migration mentioned by Liu Jiang.
Is there any material about firmware based memory migration?
quoted
So far, I only know this. :)
quoted
4. What's the status of memory hotplug? Apart from can't remove kernel
memory, other things are fully implementation?
I think the main job is done for now. And there are still bugs to fix.
And this functionality is not stable.
Thanks. :)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
.
Hi Simon,
On 02/01/2013 10:17 AM, Simon Jeons wrote:
quoted
For example:
64TB, what ever
xxxTB, what ever
logic address space: |_____kernel_______|_________user_________________|
\ \ / /
\ /\ /
physical address space: |___\/__\/_____________| 4GB or
8GB, what ever
*****
How much address space user process can have on x86_64? Also 8GB?
Usually, we don't say that.
8GB is your physical memory, right ?
But kernel space and user space is the logic conception in OS. They are
in logic
address space.
So both the kernel space and the user space can use all the physical memory.
But if the page is already in use by either of them, the other one
cannot use it.
For example, some pages are direct mapped to kernel, and is in use by
kernel, the
user space cannot map it.
quoted
The ***** part physical is mapped to user space in the process' own
pagetable.
It is also direct mapped in kernel's pagetable. So the kernel can also
access it. :)
But how to protect user process not modify kernel memory?
This is the job of CPU. On intel cpus, user space code is running in
level 3, and
kernel space code is running in level 0. So the code in level 3 cannot
access the data
segment in level 0.
Thanks. :)
From: Simon Jeons <hidden> Date: 2013-02-01 03:06:38
Hi Tang,
On Fri, 2013-02-01 at 10:42 +0800, Tang Chen wrote:
I confuse!
Hi Simon,
On 02/01/2013 10:17 AM, Simon Jeons wrote:
quoted
quoted
For example:
64TB, what ever
xxxTB, what ever
logic address space: |_____kernel_______|_________user_________________|
\ \ / /
\ /\ /
physical address space: |___\/__\/_____________| 4GB or
8GB, what ever
*****
How much address space user process can have on x86_64? Also 8GB?
Usually, we don't say that.
8GB is your physical memory, right ?
But kernel space and user space is the logic conception in OS. They are
in logic
address space.
So both the kernel space and the user space can use all the physical memory.
But if the page is already in use by either of them, the other one
cannot use it.
For example, some pages are direct mapped to kernel, and is in use by
kernel, the
user space cannot map it.
How can distinguish map and use? I mean how can confirm memory is used
by kernel instead of map?
quoted
quoted
The ***** part physical is mapped to user space in the process' own
pagetable.
It is also direct mapped in kernel's pagetable. So the kernel can also
access it. :)
But how to protect user process not modify kernel memory?
This is the job of CPU. On intel cpus, user space code is running in
level 3, and
kernel space code is running in level 0. So the code in level 3 cannot
access the data
segment in level 0.
1) If user process and kenel map to same physical memory, user process
will get SIGSEGV during #PF if access to this memory, but If user proces
s will map to the same memory which kernel map? Why? It can't access it.
2) If two user processes map to same physical memory, what will happen
if one process access the memory?
Hi Simon,
On 02/01/2013 11:06 AM, Simon Jeons wrote:
How can distinguish map and use? I mean how can confirm memory is used
by kernel instead of map?
If the page is free, for example, it is in the buddy system, it is not
in use.
Even if it is direct mapped by kernel, the kernel logic should not to
access it
because you didn't allocate it. This is the kernel's logic. Of course
the hardware
and the user will not know this.
You want to access some memory, you should first have a logic address,
right?
So how can you get a logic address ? You call alloc api.
For example, when you are coding, of course you write:
p = alloc_xxx(); ---- allocate memory, now, it is in use, alloc_xxx()
makes kernel know it.
*p = ...... ---- use the memory
You won't write:
p = 0xFFFF8745; ---- if so, kernel doesn't know it is in use
*p = ...... ---- wrong...
right ?
The kernel mapped a page, it doesn't mean it is using the page. You
should allocate it.
That is just the kernel's allocating logic.
Well, I think I can only give you this answer now. If you want something
deeper, I think
you need to read how the kernel manage the physical pages. :)
1) If user process and kenel map to same physical memory, user process
will get SIGSEGV during #PF if access to this memory, but If user proces
s will map to the same memory which kernel map? Why? It can't access it.
When you call malloc() to allocate memory in user space, the OS logic will
assure that you won't map a page that has already been used by kernel.
A page is mapped by kernel, but not used by kernel (not allocated, like
above),
malloc() could allocate it, and map it to user space. This is the situation
you are talking about, right ?
Now it is mapped by kernel and user, but it is only allocated by user.
So the kernel
will not use it. When the kernel wants some memory, it will allocate
some other memory.
This is just the kernel logic. This is what memory management subsystem
does.
I think I cannot answer more because I'm also a student in memory
management.
This is just my understanding. And I hope it is helpful. :)
2) If two user processes map to same physical memory, what will happen
if one process access the memory?
Obviously you don't need to worry about this situation. We can swap the page
used by process 1 out, and process 2 can use the same page. When process
1 wants
to access it again, we swap it in. This only happens when the physical
memory
is not enough to use. :)
And also, if you are using shared memory in user space, like
shmget(), shmat()......
it is the shared memory, both processes can use it at the same time.
Thanks. :)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2013-02-04 23:04:24
On Wed, 9 Jan 2013 17:32:32 +0800
Tang Chen [off-list ref] wrote:
+static void __meminit
+remove_pagetable(unsigned long start, unsigned long end, bool direct)
+{
+ unsigned long next;
+ pgd_t *pgd;
+ pud_t *pud;
+ bool pgd_changed = false;
+
+ for (; start < end; start = next) {
+ pgd = pgd_offset_k(start);
+ if (!pgd_present(*pgd))
+ continue;
+
+ next = pgd_addr_end(start, end);
+
+ pud = (pud_t *)map_low_page((pud_t *)pgd_page_vaddr(*pgd));
+ remove_pud_table(pud, start, next, direct);
+ if (free_pud_table(pud, pgd))
+ pgd_changed = true;
+ unmap_low_page(pud);
+ }
+
+ if (pgd_changed)
+ sync_global_pgds(start, end - 1);
+
+ flush_tlb_all();
+}
This generates a compiler warning saying that `next' may be used
uninitialised.
The warning is correct. If we take that `continue' on the first pass
through the loop, the "start = next" will copy uninitialised data into
`start'.
Is this the correct fix?