Arrange hotpluggable memory as ZONE_MOVABLE
Subsystems (11)
v2 cover Arrange hotpluggable memory as ZONE_MOVABLE
Hello guys, this is the part2 of our memory hotplug work. This part is based on the part1:
"x86, memblock: Allocate memory near kernel image before SRAT parsed"
which is base on 3.12-rc4.
You could refer part1 from: https://lkml.org/lkml/2013/10/10/644
Any comments are welcome! Thanks!
[Problem]
The current Linux cannot migrate pages used by the kerenl because of the kernel direct mapping. In Linux kernel space, va = pa + PAGE_OFFSET. When the pa is changed, we cannot simply update the pagetable and keep the va unmodified. So the kernel pages are not migratable.
There are also some other issues will cause the kernel pages not migratable. For example, the physical address may be cached somewhere and will be used. It is not to update all the caches.
When doing memory hotplug in Linux, we first migrate all the pages in one memory device somewhere else, and then remove the device. But if pages are used by the kernel, they are not migratable. As a result, memory used by the kernel cannot be hot-removed.
Modifying the kernel direct mapping mechanism is too difficult to do. And it may cause the kernel performance down and unstable. So we use the following way to do memory hotplug.
[What we are doing]
In Linux, memory in one numa node is divided into several zones. One of the zones is ZONE_MOVABLE, which the kernel won't use.
In order to implement memory hotplug in Linux, we are going to arrange all hotpluggable memory in ZONE_MOVABLE so that the kernel won't use these memory.
To do this, we need ACPI's help.
[How we do this]
In ACPI, SRAT(System Resource Affinity Table) contains NUMA info. The memory affinities in SRAT record every memory range in the system, and also, flags specifying if the memory range is hotpluggable.
(Please refer to ACPI spec 5.0 5.2.16)
With the help of SRAT, we have to do the following two things to achieve our goal:
1. When doing memory hot-add, allow the users arranging hotpluggable as ZONE_MOVABLE.
(This has been done by the MOVABLE_NODE functionality in Linux.)
2. when the system is booting, prevent bootmem allocator from allocating hotpluggable memory for the kernel before the memory initialization finishes.
(This is what we are going to do. See below.)
[About this patch-set]
In previous part's patches, we have made the kernel allocate memory near kernel image before SRAT parsed to avoid allocating hotpluggable memory for kernel. So this patch-set does the following things:
1. Improve memblock to support flags, which are used to indicate different memory type.
2. Mark all hotpluggable memory in memblock.memory[].
3. Make the default memblock allocator skip hotpluggable memory.
4. Improve "movable_node" boot option to have higher priority of movablecore and kernelcore boot option.
Change log v1 -> v2:
1. Rebase this part on the v7 version of part1
2. Fix bug: If movable_node boot option not specified, memblock still checks hotpluggable memory when allocating memory.
Tang Chen (7):
memblock, numa: Introduce flag into memblock
memblock, mem_hotplug: Introduce MEMBLOCK_HOTPLUG flag to mark
hotpluggable regions
memblock: Make memblock_set_node() support different memblock_type acpi, numa, mem_hotplug: Mark hotpluggable memory in memblock acpi, numa, mem_hotplug: Mark all nodes the kernel resides
un-hotpluggable
memblock, mem_hotplug: Make memblock skip hotpluggable regions if
needed
x86, numa, acpi, memory-hotplug: Make movable_node have higher
priority
Yasuaki Ishimatsu (1):
x86: get pg_data_t's memory from other node
arch/metag/mm/init.c | 3 +- arch/metag/mm/numa.c | 3 +- arch/microblaze/mm/init.c | 3 +- arch/powerpc/mm/mem.c | 2 +- arch/powerpc/mm/numa.c | 8 ++- arch/sh/kernel/setup.c | 4 +- arch/sparc/mm/init_64.c | 5 +- arch/x86/mm/init_32.c | 2 +- arch/x86/mm/init_64.c | 2 +- arch/x86/mm/numa.c | 63 +++++++++++++++++++++-- arch/x86/mm/srat.c | 5 ++ include/linux/memblock.h | 39 ++++++++++++++- mm/memblock.c | 123 ++++++++++++++++++++++++++++++++++++++------- mm/memory_hotplug.c | 1 + mm/page_alloc.c | 28 ++++++++++- 15 files changed, 252 insertions(+), 39 deletions(-)
PATCH v2 1/8 x86: get pg_data_t's memory from other node
From: Yasuaki Ishimatsu <[email protected]>
If system can create movable node which all memory of the node is allocated as ZONE_MOVABLE, setup_node_data() cannot allocate memory for the node's pg_data_t. So, invoke memblock_alloc_nid(...MAX_NUMNODES) again to retry when the first allocation fails. Otherwise, the system could failed to boot. (We don't use memblock_alloc_try_nid() to retry because in this function, if the allocation fails, it will panic the system.)
The node_data could be on hotpluggable node. And so could pagetable and vmemmap. But for now, doing so will break memory hot-remove path.
A node could have several memory devices. And the device who holds node data should be hot-removed in the last place. But in NUMA level, we don't know which memory_block (/sys/devices/system/node/nodeX/memoryXXX) belongs to which memory device. We only have node. So we can only do node hotplug.
But in virtualization, developers are now developing memory hotplug in qemu, which support a single memory device hotplug. So a whole node hotplug will not satisfy virtualization users.
So at last, we concluded that we'd better do memory hotplug and local node things (local node node data, pagetable, vmemmap, ...) in two steps. Please refer to https://lkml.org/lkml/2013/6/19/73
For now, we put node_data of movable node to another node, and then improve it in the future.
--- arch/x86/mm/numa.c | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-)
arch/x86/mm/numa.c +8 -3
@@ -211,9 +211,14 @@ static void __init setup_node_data(int nid, u64 start, u64 end)*/ nd_pa =memblock_alloc_nid (nd_size,SMP_CACHE_BYTES , nid);if (!nd_pa) { -pr_err ("Cannot find %zu bytes in node %d\n" , - nd_size, nid); -return ; +pr_warn ("Cannot find %zu bytes in node %d, so try other nodes" , + nd_size, nid); + nd_pa =memblock_alloc_nid (nd_size,SMP_CACHE_BYTES , +MAX_NUMNODES ); +if (!nd_pa) { +pr_err ("Cannot find %zu bytes in any node\n" , nd_size); +return ; + } } nd =__va (nd_pa);
Signature · 1 line
1.7.1
PATCH v2 2/8 memblock, numa: Introduce flag into memblock
In reply to Zhang YanfeiFrom: Tang Chen <[email protected]>
There is no flag in memblock to describe what type the memory is. Sometimes, we may use memblock to reserve some memory for special usage. And we want to know what kind of memory it is. So we need a way to differentiate memory for different usage.
In hotplug environment, we want to reserve hotpluggable memory so the kernel won't be able to use it. And when the system is up, we have to free these hotpluggable memory to buddy. So we need to mark these memory first.
In order to do so, we need to mark out these special memory in memblock. In this patch, we introduce a new "flags" member into memblock_region:
struct memblock_region {
phys_addr_t base;
phys_addr_t size;
unsigned long flags; /* This is new. */
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
int nid; #endif
};
This patch does the following things:
1) Add "flags" member to memblock_region.
2) Modify the following APIs' prototype:
memblock_add_region()
memblock_insert_region()
3) Add memblock_reserve_region() to support reserve memory with flags, and keep memblock_reserve()'s prototype unmodified.
4) Modify other APIs to support flags, but keep their prototype unmodified.
The idea is from Wen Congyang <[email protected]> and Liu Jiang <[email protected]>.
v1 -> v2:
As tj suggested, a zero flag MEMBLK_DEFAULT will make users confused. If we want to specify any other flag, such MEMBLK_HOTPLUG, users don't know to use MEMBLK_DEFAULT | MEMBLK_HOTPLUG or just MEMBLK_HOTPLUG. So remove MEMBLK_DEFAULT (which is 0), and just use 0 by default to avoid confusions to users.
--- include/linux/memblock.h | 1 + mm/memblock.c | 53 +++++++++++++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 15 deletions(-)
include/linux/memblock.h +1 -0
@@ -22,6 +22,7 @@struct memblock_region {phys_addr_t base;phys_addr_t size; +unsigned long flags;#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP int nid;#endif
mm/memblock.c +38 -15
164 lines not on this page · raw message
Signature · 1 line
1.7.1
PATCH v2 3/8 memblock, mem_hotplug: Introduce MEMBLOCK_HOTPLUG flag to mark hotpluggable regions
In reply to Zhang YanfeiFrom: Tang Chen <[email protected]>
In find_hotpluggable_memory, once we find out a memory region which is hotpluggable, we want to mark them in memblock.memory. So that we could control memblock allocator not to allocte hotpluggable memory for the kernel later.
To achieve this goal, we introduce MEMBLOCK_HOTPLUG flag to indicate the hotpluggable memory regions in memblock and a function memblock_mark_hotplug() to mark hotpluggable memory if we find one.
--- include/linux/memblock.h | 17 +++++++++++++++ mm/memblock.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 0 deletions(-)
include/linux/memblock.h +17 -0
@@ -19,6 +19,9 @@#define INIT_MEMBLOCK_REGIONS 128 +/* Definition of memblock flags. */ +#define MEMBLOCK_HOTPLUG 0x1/* hotpluggable region */ +struct memblock_region {phys_addr_t base;phys_addr_t size;
@@ -60,6 +63,8 @@ int memblock_remove(phys_addr_t base, phys_addr_t size);int memblock_free (phys_addr_t base,phys_addr_t size);int memblock_reserve (phys_addr_t base,phys_addr_t size);void memblock_trim_memory (phys_addr_t align); +int memblock_mark_hotplug (phys_addr_t base,phys_addr_t size); +int memblock_clear_hotplug (phys_addr_t base,phys_addr_t size);#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn,
@@ -122,6 +127,18 @@ void __next_free_mem_range_rev(u64 *idx, int nid, phys_addr_t *out_start, i != (u64 )ULLONG_MAX ; \ __next_free_mem_range_rev(&i, nid, p_start, p_end, p_nid)) +static inline void memblock_set_region_flags (struct memblock_region *r, +unsigned long flags) +{ + r->flags |= flags; +} + +static inline void memblock_clear_region_flags (struct memblock_region *r, +unsigned long flags) +{ + r->flags &= ~flags; +} +#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP int memblock_set_node (phys_addr_t base,phys_addr_t size,int nid);
mm/memblock.c +52 -0
58 lines not on this page · raw message
Signature · 1 line
1.7.1
PATCH v2 4/8 memblock: Make memblock_set_node() support different memblock_type
In reply to Zhang YanfeiFrom: Tang Chen <[email protected]>
--- arch/metag/mm/init.c | 3 ++- arch/metag/mm/numa.c | 3 ++- arch/microblaze/mm/init.c | 3 ++- arch/powerpc/mm/mem.c | 2 +- arch/powerpc/mm/numa.c | 8 +++++--- arch/sh/kernel/setup.c | 4 ++-- arch/sparc/mm/init_64.c | 5 +++-- arch/x86/mm/init_32.c | 2 +- arch/x86/mm/init_64.c | 2 +- arch/x86/mm/numa.c | 6 ++++-- include/linux/memblock.h | 3 ++- mm/memblock.c | 6 +++--- 12 files changed, 28 insertions(+), 19 deletions(-)
arch/metag/mm/init.c +2 -1
@@ -205,7 +205,8 @@ static void __init do_init_bootmem(void) start_pfn =memblock_region_memory_base_pfn (reg); end_pfn =memblock_region_memory_end_pfn (reg);memblock_set_node (PFN_PHYS (start_pfn), -PFN_PHYS (end_pfn - start_pfn),0 ); +PFN_PHYS (end_pfn - start_pfn), + &memblock.memory,0 ); }/* All of system RAM sits in node 0 for the non-NUMA case */
arch/metag/mm/numa.c +2 -1
@@ -42,7 +42,8 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)memblock_add (start, end - start);memblock_set_node (PFN_PHYS (start_pfn), -PFN_PHYS (end_pfn - start_pfn), nid); +PFN_PHYS (end_pfn - start_pfn), + &memblock.memory, nid);/* Node-local pgdat */ pgdat_paddr = memblock_alloc_base(sizeof(struct pglist_data),
arch/microblaze/mm/init.c +2 -1
@@ -192,7 +192,8 @@ void __init setup_memory(void) start_pfn =memblock_region_memory_base_pfn (reg); end_pfn =memblock_region_memory_end_pfn (reg);memblock_set_node (start_pfn <<PAGE_SHIFT , - (end_pfn - start_pfn) <<PAGE_SHIFT ,0 ); + (end_pfn - start_pfn) <<PAGE_SHIFT , + &memblock.memory,0 ); }/* free bootmem is whole main memory */
arch/powerpc/mm/mem.c +1 -1
@@ -209,7 +209,7 @@ void __init do_init_bootmem(void)/* Place all memblock_regions in the same node and merge contiguous * memblock_regions */ -memblock_set_node (0 , (phys_addr_t )ULLONG_MAX ,0 ); +memblock_set_node (0 , (phys_addr_t )ULLONG_MAX , &memblock_memory,0 );/* Add all physical memory to the bootmem map, mark each area * present.
arch/powerpc/mm/numa.c +5 -3
@@ -670,7 +670,8 @@ static void __init parse_drconf_memory(struct device_node *memory)node_set_online (nid); sz =numa_enforce_memory_limit (base, size);if (sz) -memblock_set_node (base, sz, nid); +memblock_set_node (base, sz, + &memblock.memory, nid); }while (--ranges); } }
@@ -760,7 +761,7 @@ new_range:continue ; } -memblock_set_node (start, size, nid); +memblock_set_node (start, size, &memblock.memory, nid);if (--ranges) goto new_range;
@@ -797,7 +798,8 @@ static void __init setup_nonnuma(void)fake_numa_create_new_node (end_pfn, &nid);memblock_set_node (PFN_PHYS (start_pfn), -PFN_PHYS (end_pfn - start_pfn), nid); +PFN_PHYS (end_pfn - start_pfn), + &memblock.memory, nid);node_set_online (nid); } }
arch/sh/kernel/setup.c +2 -2
@@ -230,8 +230,8 @@ void __init __add_active_range(unsigned int nid, unsigned long start_pfn,pmb_bolt_mapping ((unsigned long )__va (start), start, end - start,PAGE_KERNEL ); -memblock_set_node (PFN_PHYS (start_pfn), -PFN_PHYS (end_pfn - start_pfn), nid); +memblock_set_node (PFN_PHYS (start_pfn),PFN_PHYS (end_pfn - start_pfn), + &memblock.memory, nid); }void __init __weak plat_early_device_setup (void )
arch/sparc/mm/init_64.c +3 -2
@@ -1021,7 +1021,8 @@ static void __init add_node_ranges(void)"start[%lx] end[%lx]\n" , nid, start, this_end); -memblock_set_node (start, this_end - start, nid); +memblock_set_node (start, this_end - start, + &memblock.memory, nid); start = this_end; } }
@@ -1325,7 +1326,7 @@ static void __init bootmem_init_nonnuma(void) (top_of_ram - total_ram) >> 20);init_node_masks_nonnuma (); -memblock_set_node (0 , (phys_addr_t )ULLONG_MAX ,0 ); +memblock_set_node (0 , (phys_addr_t )ULLONG_MAX , &memblock.memory,0 );allocate_node_data (0 );node_set_online (0 ); }
arch/x86/mm/init_32.c +1 -1
@@ -665,7 +665,7 @@ void __init initmem_init(void) high_memory = (void *)__va (max_low_pfn *PAGE_SIZE -1 ) +1 ;#endif -memblock_set_node (0 , (phys_addr_t )ULLONG_MAX ,0 ); +memblock_set_node (0 , (phys_addr_t )ULLONG_MAX , &memblock.memory,0 );sparse_memory_present_with_active_regions (0 );#ifdef CONFIG_FLATMEM
arch/x86/mm/init_64.c +1 -1
@@ -643,7 +643,7 @@ kernel_physical_mapping_init(unsigned long start,#ifndef CONFIG_NUMA void __init initmem_init (void ) { -memblock_set_node (0 , (phys_addr_t )ULLONG_MAX ,0 ); +memblock_set_node (0 , (phys_addr_t )ULLONG_MAX , &memblock.memory,0 ); }#endif
arch/x86/mm/numa.c +4 -2
@@ -492,7 +492,8 @@ static int __init numa_register_memblks(struct numa_meminfo *mi)for (i =0 ; i < mi->nr_blks; i++) {struct numa_memblk *mb = &mi->blk[i]; -memblock_set_node (mb->start, mb->end - mb->start, mb->nid); +memblock_set_node (mb->start, mb->end - mb->start, + &memblock.memory, mb->nid); }/*
@@ -566,7 +567,8 @@ static int __init numa_init(int (*init_func)(void))nodes_clear (node_possible_map);nodes_clear (node_online_map);memset (&numa_meminfo,0 ,sizeof (numa_meminfo)); -WARN_ON (memblock_set_node (0 ,ULLONG_MAX ,MAX_NUMNODES )); +WARN_ON (memblock_set_node (0 ,ULLONG_MAX , &memblock.memory, +MAX_NUMNODES ));numa_reset_distance (); ret =init_func ();
include/linux/memblock.h +2 -1
@@ -140,7 +140,8 @@ static inline void memblock_clear_region_flags(struct memblock_region *r, }#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP -int memblock_set_node (phys_addr_t base,phys_addr_t size,int nid); +int memblock_set_node (phys_addr_t base,phys_addr_t size, +struct memblock_type *type,int nid);static inline void memblock_set_region_node (struct memblock_region *r,int nid) {
mm/memblock.c +3 -3
@@ -910,18 +910,18 @@ void __init_memblock __next_mem_pfn_range(int *idx, int nid,* memblock_set_node - set node ID on memblock regions * @base: base of area to set node ID for * @size: size of area to set node ID for +* @type: memblock type to set node ID for * @nid: node ID to set * -* Set the nid of memblock memory regions in [@base,@base+@size) to @nid. +* Set the nid of memblock @type regions in [@base,@base+@size) to @nid. * Regions which cross the area boundaries are split as necessary. * * RETURNS: * 0 on success, -errno on failure. */ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size, -int nid) +struct memblock_type *type,int nid) { -struct memblock_type *type = &memblock.memory;int start_rgn, end_rgn;int i, ret;
Signature · 1 line
1.7.1
PATCH v2 5/8 acpi, numa, mem_hotplug: Mark hotpluggable memory in memblock
In reply to Zhang YanfeiFrom: Tang Chen <[email protected]>
When parsing SRAT, we know that which memory area is hotpluggable. So we invoke function memblock_mark_hotplug() introduced by previous patch to mark hotpluggable memory in memblock.
--- arch/x86/mm/numa.c | 2 ++ arch/x86/mm/srat.c | 5 +++++ 2 files changed, 7 insertions(+), 0 deletions(-)
arch/x86/mm/numa.c +2 -0
@@ -569,6 +569,8 @@ static int __init numa_init(int (*init_func)(void))memset (&numa_meminfo,0 ,sizeof (numa_meminfo));WARN_ON (memblock_set_node (0 ,ULLONG_MAX , &memblock.memory,MAX_NUMNODES )); +/* In case that parsing SRAT failed. */ +WARN_ON (memblock_clear_hotplug (0 ,ULLONG_MAX ));numa_reset_distance (); ret =init_func ();
arch/x86/mm/srat.c +5 -0
@@ -181,6 +181,11 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) (unsigned long long ) start, (unsigned long long ) end -1 , hotpluggable ? " hotplug" : ""); +/* Mark hotplug range in memblock. */ +if (hotpluggable &&memblock_mark_hotplug (start, ma->length)) +pr_warn ("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n" , + (unsigned long long ) start, (unsigned long long ) end -1 ); +return 0 ; out_err_bad_srat:bad_srat ();
Signature · 1 line
1.7.1
PATCH v2 6/8 acpi, numa, mem_hotplug: Mark all nodes the kernel resides un-hotpluggable
In reply to Zhang YanfeiFrom: Tang Chen <[email protected]>
At very early time, the kernel have to use some memory such as loading the kernel image. We cannot prevent this anyway. So any node the kernel resides in should be un-hotpluggable.
--- arch/x86/mm/numa.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-)
arch/x86/mm/numa.c +44 -0
@@ -494,6 +494,14 @@ static int __init numa_register_memblks(struct numa_meminfo *mi)struct numa_memblk *mb = &mi->blk[i];memblock_set_node (mb->start, mb->end - mb->start, &memblock.memory, mb->nid); + +/* +* At this time, all memory regions reserved by memblock are +* used by the kernel. Set the nid in memblock.reserved will +* mark out all the nodes the kernel resides in. +*/ +memblock_set_node (mb->start, mb->end - mb->start, + &memblock.reserved, mb->nid); }/*
@@ -555,6 +563,30 @@ static void __init numa_init_array(void) } } +static void __init numa_clear_kernel_node_hotplug (void ) +{ +int i, nid; +nodemask_t numa_kernel_nodes; +unsigned long start, end; +struct memblock_type *type = &memblock.reserved; + +/* Mark all kernel nodes. */ +for (i =0 ; i < type->cnt; i++) +node_set (type->regions[i].nid, numa_kernel_nodes); + +/* Clear MEMBLOCK_HOTPLUG flag for memory in kernel nodes. */ +for (i =0 ; i < numa_meminfo.nr_blks; i++) { + nid = numa_meminfo.blk[i].nid; +if (!node_isset (nid, numa_kernel_nodes)) +continue ; + + start = numa_meminfo.blk[i].start; + end = numa_meminfo.blk[i].end; + +memblock_clear_hotplug (start, end - start); + } +} +static int __init numa_init (int (*init_func)(void )) {int i;
@@ -569,6 +601,8 @@ static int __init numa_init(int (*init_func)(void))memset (&numa_meminfo,0 ,sizeof (numa_meminfo));WARN_ON (memblock_set_node (0 ,ULLONG_MAX , &memblock.memory,MAX_NUMNODES )); +WARN_ON (memblock_set_node (0 ,ULLONG_MAX , &memblock.reserved, +MAX_NUMNODES ));/* In case that parsing SRAT failed. */ WARN_ON (memblock_clear_hotplug (0 ,ULLONG_MAX ));numa_reset_distance ();
@@ -606,6 +640,16 @@ static int __init numa_init(int (*init_func)(void))numa_clear_node (i); }numa_init_array (); + +/* +* At very early time, the kernel have to use some memory such as +* loading the kernel image. We cannot prevent this anyway. So any +* node the kernel resides in should be un-hotpluggable. +* +* And when we come here, numa_init() won't fail. +*/ +numa_clear_kernel_node_hotplug (); +return 0 ; }
Signature · 1 line
1.7.1
PATCH v2 7/8 memblock, mem_hotplug: Make memblock skip hotpluggable regions if needed
In reply to Zhang YanfeiFrom: Tang Chen <[email protected]>
Linux kernel cannot migrate pages used by the kernel. As a result, hotpluggable memory used by the kernel won't be able to be hot-removed. To solve this problem, the basic idea is to prevent memblock from allocating hotpluggable memory for the kernel at early time, and arrange all hotpluggable memory in ACPI SRAT(System Resource Affinity Table) as ZONE_MOVABLE when initializing zones.
In the previous patches, we have marked hotpluggable memory regions with MEMBLOCK_HOTPLUG flag in memblock.memory.
In this patch, we make memblock skip these hotpluggable memory regions in the default top-down allocation function if movable_node boot option is specified.
--- include/linux/memblock.h | 18 ++++++++++++++++++ mm/memblock.c | 12 ++++++++++++ mm/memory_hotplug.c | 1 + 3 files changed, 31 insertions(+), 0 deletions(-)
include/linux/memblock.h +18 -0
@@ -47,6 +47,10 @@ struct memblock {extern struct memblock memblock;extern int memblock_debug; +#ifdef CONFIG_MOVABLE_NODE +/* If movable_node boot option specified */ +extern bool movable_node_enabled; +#endif /* CONFIG_MOVABLE_NODE */ #define memblock_dbg (fmt, ...) \ if (memblock_debug) printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
@@ -65,6 +69,20 @@ int memblock_reserve(phys_addr_t base, phys_addr_t size);void memblock_trim_memory (phys_addr_t align);int memblock_mark_hotplug (phys_addr_t base,phys_addr_t size);int memblock_clear_hotplug (phys_addr_t base,phys_addr_t size); +#ifdef CONFIG_MOVABLE_NODE +static inline bool memblock_is_hotpluggable (struct memblock_region *m) +{ +return m->flags &MEMBLOCK_HOTPLUG ; +} + +static inline bool movable_node_is_enabled (void ) +{ +return movable_node_enabled; +} +#else +static inline bool memblock_is_hotpluggable (struct memblock_region *m){return false; } +static inline bool movable_node_is_enabled (void ) {return false; } +#endif #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn,
mm/memblock.c +12 -0
@@ -39,6 +39,9 @@ struct memblock memblock __initdata_memblock = { }; int memblock_debug __initdata_memblock; +#ifdef CONFIG_MOVABLE_NODE +bool movable_node_enabled __initdata_memblock = false; +#endif static int memblock_can_resize __initdata_memblock; static int memblock_memory_in_slab __initdata_memblock = 0; static int memblock_reserved_in_slab __initdata_memblock = 0;
@@ -819,6 +822,11 @@ void __init_memblock __next_free_mem_range(u64 *idx, int nid,* @out_nid: ptr to int for nid of the range, can be %NULL * * Reverse of __next_free_mem_range(). +* +* Linux kernel cannot migrate pages used by itself. Memory hotplug users won't +* be able to hot-remove hotpluggable memory used by the kernel. So this +* function skip hotpluggable regions if needed when allocating memory for the +* kernel. */ void __init_memblock __next_free_mem_range_rev(u64 *idx, int nid, phys_addr_t *out_start,
@@ -843,6 +851,10 @@ void __init_memblock __next_free_mem_range_rev(u64 *idx, int nid,if (nid !=MAX_NUMNODES && nid !=memblock_get_region_node (m))continue ; +/* skip hotpluggable memory regions if needed */ +if (movable_node_is_enabled () &&memblock_is_hotpluggable (m)) +continue ; +/* scan areas before each reservation for intersection */ for ( ; ri >=0 ; ri--) {struct memblock_region *r = &rsv->regions[ri];
mm/memory_hotplug.c +1 -0
@@ -1436,6 +1436,7 @@ static int __init cmdline_parse_movable_node(char *p)* the kernel away from hotpluggable memory. */ memblock_set_bottom_up (true); + movable_node_enabled = true;#else pr_warn ("movable_node option not supported\n" );#endif
Signature · 7 lines
1.7.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v2 8/8 x86, numa, acpi, memory-hotplug: Make movable_node have higher priority
In reply to Zhang YanfeiFrom: Tang Chen <[email protected]>
If users specify the original movablecore=nn@ss boot option, the kernel will arrange [ss, ss+nn) as ZONE_MOVABLE. The kernelcore=nn@ss boot option is similar except it specifies ZONE_NORMAL ranges.
Now, if users specify "movable_node" in kernel commandline, the kernel will arrange hotpluggable memory in SRAT as ZONE_MOVABLE. And if users do this, all the other movablecore=nn@ss and kernelcore=nn@ss options should be ignored.
For those who don't want this, just specify nothing. The kernel will act as before.
--- mm/page_alloc.c | 28 ++++++++++++++++++++++++++-- 1 files changed, 26 insertions(+), 2 deletions(-)
mm/page_alloc.c +26 -2
@@ -5021,9 +5021,33 @@ static void __init find_zone_movable_pfns_for_nodes(void)nodemask_t saved_node_state = node_states[N_MEMORY ];unsigned long totalpages =early_calculate_totalpages ();int usable_nodes =nodes_weight (node_states[N_MEMORY ]); +struct memblock_type *type = &memblock.memory; + +/* Need to find movable_zone earlier when movable_node is specified. */ +find_usable_zone_for_movable (); + +/* +* If movable_node is specified, ignore kernelcore and movablecore +* options. +*/ +if (movable_node_is_enabled ()) { +for (i =0 ; i < type->cnt; i++) { +if (!memblock_is_hotpluggable (&type->regions[i])) +continue ; + + nid = type->regions[i].nid; + + usable_startpfn =PFN_DOWN (type->regions[i].base); + zone_movable_pfn[nid] = zone_movable_pfn[nid] ? +min (usable_startpfn, zone_movable_pfn[nid]) : + usable_startpfn; + } + + goto out2; + }/* -* If movablecore was specified, calculate what size of +* If movablecore=nn[KMG] was specified, calculate what size of * kernelcore that corresponds so that memory usable for * any allocation type is evenly spread. If both kernelcore * and movablecore are specified, then the value of kernelcore
@@ -5049,7 +5073,6 @@ static void __init find_zone_movable_pfns_for_nodes(void) goto out;/* usable_startpfn is the lowest possible pfn ZONE_MOVABLE can be at */ -find_usable_zone_for_movable (); usable_startpfn = arch_zone_lowest_possible_pfn[movable_zone]; restart:
@@ -5140,6 +5163,7 @@ restart:if (usable_nodes && required_kernelcore > usable_nodes) goto restart; +out2:/* Align start of ZONE_MOVABLE on all nids to MAX_ORDER_NR_PAGES */ for (nid =0 ; nid <MAX_NUMNODES ; nid++) zone_movable_pfn[nid] =
Signature · 1 line
1.7.1
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
Hello tejun,
Quoted 43 lines · Tejun Heo
Hey,
Quoted 9 lines · Zhang Yanfei
a little difference here, consider a 16-GB node. If we parse SRAT earlier, and still use the top-down allocation, and kernel image is loaded at 16MB, we reserve other nodes but this 16GB node that kernel resides in is used for boot-up allocation. So the page table is allocated from 16GB to 0. The page table is allocated on top of the the memory as possible.
But if we use this approach, no matter how large the page table is, we allocate the page table in low memory which is the case that hpa concerns about the DMA.
Yeah, sure there will be cases where parsing SRAT would be better.
4k mapping is in use, which is mostly for debugging && memory map is composed such that the highest non-hotpluggable address is high enough.
It's going in circles again but my point has always been that the above in itself don't seem to be substantial enough to justify putting, say, initrd loading before page table init.
Later some argued that bringing SRAT parsing earlier could help implementing finer grained hotplug, which would be an acceptable path to follow; however, that doesn't turn out to be true either.
* Again, it matter if and only if 4k mapping is in use. Do we even care?
* SRAT isn't enough. The whole device tree needs to be parsed to put page tables into local device. It's a lot of churn, including major updates to page table allocation, just to support debug 4k mapping cases. Doesn't make much sense to me.
So, SRAT's usefulness seems extremely limited - it helps if the user wants to use debug features along with memory hotplug on an extreme large machine with devices which have low DMA limit, and that's it. To me, it seems to be a poor argument. Just declaring memory hotplug works iff large kernel mapping is in use feels like a pretty good trade-off to me, and I have no idea why I have to repeat all this, which I've written multiple times already, in a private thread again.
Quoted 8 lines
If the thread is to make progress, one has to provide counter arguments to the points raised. It feels like I'm going in circle again. The exact same content I wrote above has been repeated multiple times in the past discussions and I'm getting tired of doing it without getting any actual response.
When replying, please restore cc's and keep the whole body.
Thanks for the whole explanation again. I was just raising some argument that other guys raised before. I agree with what you said above and already put some of them into the patch 4 description in v7 version.
Now could you please help reviewing the part2? As I said before, no matter how we implement the part1, part2 is kind of independent.
Signature · 2 lines
Thanks. Zhang Yanfei
Quoted 51 lines · Zhang Yanfei
Hello tejun,
Quoted 48 lines · Tejun Heo
Hey,
Quoted 9 lines · Zhang Yanfei
a little difference here, consider a 16-GB node. If we parse SRAT earlier, and still use the top-down allocation, and kernel image is loaded at 16MB, we reserve other nodes but this 16GB node that kernel resides in is used for boot-up allocation. So the page table is allocated from 16GB to 0. The page table is allocated on top of the the memory as possible.
But if we use this approach, no matter how large the page table is, we allocate the page table in low memory which is the case that hpa concerns about the DMA.
Yeah, sure there will be cases where parsing SRAT would be better.
4k mapping is in use, which is mostly for debugging && memory map is composed such that the highest non-hotpluggable address is high enough.
It's going in circles again but my point has always been that the above in itself don't seem to be substantial enough to justify putting, say, initrd loading before page table init.
Later some argued that bringing SRAT parsing earlier could help implementing finer grained hotplug, which would be an acceptable path to follow; however, that doesn't turn out to be true either.
* Again, it matter if and only if 4k mapping is in use. Do we even care?
* SRAT isn't enough. The whole device tree needs to be parsed to put page tables into local device. It's a lot of churn, including major updates to page table allocation, just to support debug 4k mapping cases. Doesn't make much sense to me.
So, SRAT's usefulness seems extremely limited - it helps if the user wants to use debug features along with memory hotplug on an extreme large machine with devices which have low DMA limit, and that's it. To me, it seems to be a poor argument. Just declaring memory hotplug works iff large kernel mapping is in use feels like a pretty good trade-off to me, and I have no idea why I have to repeat all this, which I've written multiple times already, in a private thread again.
If the thread is to make progress, one has to provide counter arguments to the points raised. It feels like I'm going in circle again. The exact same content I wrote above has been repeated multiple times in the past discussions and I'm getting tired of doing it without getting any actual response.
The points for parsing SRAT early instead of Yanfei/Tang v7:
1. We just reached one unified path to setup page tables for 32bit, 64bit and xen or non xen after several years. We should not have add another path for system
that support hotplug.
2. also we should avoid adding "movable_nodes" command line.
3. debug mapping 4k, and it is working all the way, why breaking it even for memory hotplug path?
4. numa_meminfo now is static structure.
we have no reason that we can not parse SRAT etc to fill that struct.
5. for device tree, i assume that we could do same like srat parsing to find out numa to fill the numa_meminfo early. or with help of BRK.
6. in the long run, We should rework our NUMA booting:
a. boot system with boot numa nodes early only.
b. in later init stage or user space, init other nodes RAM/CPU/PCI...in parallel.
that will reduce boot time for 8 sockets/32 sockets dramatically.
We will need to parse srat table early so could avoid init memory for non-boot nodes.
Yinghai
Hello, Yinghai.
Quoted 6 lines · Yinghai Lu
The points for parsing SRAT early instead of Yanfei/Tang v7:
1. We just reached one unified path to setup page tables for 32bit, 64bit and xen or non xen after several years. We should not have add another path for system
that support hotplug.
The separate code path we're talking about is tiny. It's just an extra function for page table allocation and another for memblock allocation which is symmetric to the existing one. Sure, there are benefits to not diverging code paths but these are fairly trivial in terms of maintenance overhead and test coverage.
Quoted 1 line
2. also we should avoid adding "
movable_nodes" command line.
Can we? What about the pgdat? We're allocating them off-node with movable_nodes which can't be the default behavior.
Quoted 2 lines
3. debug mapping 4k, and it is working all the way, why breaking it even for memory hotplug path?
If it comes for free, sure, no reason to break it. On the other hand, if maintaining it fully with a niche feature costs overhead, it's somethinig to be traded-off. It's not like using 4k page mapping with bottom-up allocation will be immediately broken either. It might affect devices which can't DMA to higher addresses on gigantic machines under debug configs. It's quite a corner case.
Quoted 2 lines
4.
numa_meminfonow is static structure.
we have no reason that we can not parse SRAT etc to fill that struct.
Sure, there's no reason we can't. The whole point is that the benefits arent' strong enough. We don't do things just because we can.
Quoted 2 lines
5. for device tree, i assume that we could do same like srat parsing to find out numa to fill the
numa_meminfoearly. or with help of BRK.
Digesting device tree involves a lot more complexity. The whole reason why things like SRAT are broken into tables in the first place. We'll be basically pulling in huge chunk of ACPICA into early boot. Again, justfications. The *only* thing which may benefit from that are debug setups. We'll have to pull in a lot of complexity before page table setup and modify page table allocation to be memory-device-specific just for debug configs, which is not a good trade-off. Benefit / cost ratio doesn't make any sense.
Quoted 8 lines
6. in the long run, We should rework our NUMA booting:
a. boot system with boot numa nodes early only.
b. in later init stage or user space, init other nodes RAM/CPU/PCI...in parallel.
that will reduce boot time for 8 sockets/32 sockets dramatically.We will need to parse srat table early so could avoid init memory for non-boot nodes.
Among the six you listed, this one sounds somewhat valid but still assuming huge page, what difference does it make? We're just talking about page table alloc / init and ACPI init. If you wanna speed up huge NUMA machine booting and chop down memory init per-NUMA, sure, move those pieces to later stages. You can init the amount necessary during early boot and then bring up the rest later on. I don't see why that'd require parsing SRAT. In fact, I think there'll be more cases where you want to actively ignore NUMA mapping during early boot. What if the system maps low memory to a non-boot numa node?
Optimizing NUMA boot just requires moving the heavy lifting to appropriate NUMA nodes. It doesn't require that early boot phase should strictly follow NUMA node boundaries.
Thanks.
Signature · 1 line
tejun
Quoted 9 lines · Tejun Heo
Quoted 8 lines
6. in the long run, We should rework our NUMA booting:
a. boot system with boot numa nodes early only.
b. in later init stage or user space, init other nodes RAM/CPU/PCI...in parallel.
that will reduce boot time for 8 sockets/32 sockets dramatically.We will need to parse srat table early so could avoid init memory for non-boot nodes.
Quoted 7 lines
Among the six you listed, this one sounds somewhat valid but still assuming huge page, what difference does it make? We're just talking about page table alloc / init and ACPI init. If you wanna speed up huge NUMA machine booting and chop down memory init per-NUMA, sure, move those pieces to later stages. You can init the amount necessary during early boot and then bring up the rest later on. I don't see why that'd require parsing SRAT.
The problem is how to define "amount necessary". If we can parse srat early, then we could just map RAM for all boot nodes one time, instead of try some small and then after SRAT table, expand it cover non-boot nodes.
To keep non-boot numa node hot-removable. we need to page table (and other that we allocate during boot stage) on ram of non boot nodes, or their local node ram. (share page table always should be on boot nodes).
Quoted 3 lines
In fact, I think there'll be more
cases where you want to actively ignore NUMA mapping during early boot. What if the system maps low memory to a non-boot numa node?
Then we treat that non-boot numa node as one of boot nodes, and it could not be hot removed.
Actually that is BIOS or Firmware bug, they should set memory address decoder correctly.
Quoted 4 lines
Optimizing NUMA boot just requires moving the heavy lifting to appropriate NUMA nodes. It doesn't require that early boot phase should strictly follow NUMA node boundaries.
At end of day, I like to see all numa system (ram/cpu/pci) could have non boot nodes to be hot-removed logically. with any boot command line.
Thanks
Yinghai
H. Peter Anvin
reviewerQuoted 9 lines · Yinghai Lu
Quoted 4 lines
Optimizing NUMA boot just requires moving the heavy lifting to appropriate NUMA nodes. It doesn't require that early boot phase should strictly follow NUMA node boundaries.
At end of day, I like to see all numa system (ram/cpu/pci) could have non boot nodes to be hot-removed logically. with any boot command line.
I don't think that is realistic without hardware support, simply because all it takes is a single page of kernel locked memory to prevent a page from being removed. The only realistic way around that, I believe, is to remove the identity-mapping in the kernel, but it still has all kinds of funnies involving devices and DMA.
-hpa
Quoted 11 lines · H. Peter Anvin
Quoted 9 lines · Yinghai Lu
Quoted 4 lines
Optimizing NUMA boot just requires moving the heavy lifting to appropriate NUMA nodes. It doesn't require that early boot phase should strictly follow NUMA node boundaries.
At end of day, I like to see all numa system (ram/cpu/pci) could have non boot nodes to be hot-removed logically. with any boot command line.
Quoted 5 lines
I don't think that is realistic without hardware support, simply because all it takes is a single page of kernel locked memory to prevent a page from being removed. The only realistic way around that, I believe, is to remove the identity-mapping in the kernel, but it still has all kinds of funnies involving devices and DMA.
We played with virtual kernel memory a decade ago and it's doable. The only complication was DMA from the kernel stack - that was done with some really broken old ISA drivers IIRC. Those should be a distant memory, in terms of practical impact.
So if anyone can implement it using huge pages, with a really fast __va() and __pa() implementation, then it might be possible. But that's a pretty major surgery on x86.
Thanks,
Ingo
H. Peter Anvin
reviewerQuoted 5 lines · Ingo Molnar
So if anyone can implement it using huge pages, with a really fast
__va()and__pa()implementation, then it might be possible. But that's a pretty major surgery on x86.
Well, we already *have* a way to deal with that for Xen (by inserting an otherwise nonexistent logical level.) I'm wondering if those interfaces could be (ab)used for this as well, or if that is functionally equivalent to saying that this should be done in a hypervisor.
-hpa
Quoted 10 lines · H. Peter Anvin
Quoted 4 lines · Ingo Molnar
So if anyone can implement it using huge pages, with a really fast
__va()and__pa()implementation, then it might be possible. But that's a pretty major surgery on x86.Well, we already *have* a way to deal with that for Xen (by inserting an otherwise nonexistent logical level.) I'm wondering if those interfaces could be (ab)used for this as well, or if that is functionally equivalent to saying that this should be done in a hypervisor.
It's not _that_ complex, and it does not need a separate security layer.
I have this distinct memory that I saw working patches that have paged all of the kernel's data, more than a decade ago. It was all rather disgusting, because those patches worked on the 4K level - but if a 2MB granular solution can be found in an elegant fashion then I think we could reconsider.
It definitely wasn't hypervisor thick. It probably needs a good hash for virtual address transformations, and all DMA has to be managed [these days we do that via the IOMMU anyway] but that's pretty much all - kernel virtual memory is reconfigured extremely rarely, so all that could be sped up for reads and mirrored per node and kept lockless, etc. etc. [Plus a metric ton of details.]
Thanks,
Ingo
Hello,
Quoted 3 lines · Yinghai Lu
The problem is how to define "amount necessary". If we can parse srat early, then we could just map RAM for all boot nodes one time, instead of try some small and then after SRAT table, expand it cover non-boot nodes.
Wouldn't that amount be fairly static and restricted? If you wanna chunk memory init anyway, there's no reason to init more than necessary until smp stage is reached. The more you do early, the more serialized you're, so wouldn't the goal naturally be initing the minimum possible?
Quoted 3 lines
To keep non-boot numa node hot-removable. we need to page table (and other that we allocate during boot stage) on ram of non boot nodes, or their local node ram. (share page table always should be on boot nodes).
The above assumes the followings,
* 4k page mappings. It'd be nice to keep everything working for 4k but just following SRAT isn't enough. What if the non-hotpluggable boot node doesn't stretch high enough and page table reaches down too far? This won't be an optional behavior, so it is actually *likely* to happen on certain setups.
* Memory hotplug is at NUMA node granularity instead of device.
Quoted 7 lines
Quoted 3 lines
Optimizing NUMA boot just requires moving the heavy lifting to appropriate NUMA nodes. It doesn't require that early boot phase should strictly follow NUMA node boundaries.
At end of day, I like to see all numa system (ram/cpu/pci) could have non boot nodes to be hot-removed logically. with any boot command line.
I suppose you mean "without any boot command line"? Sure, but, first of all, there is a clear performance trade-off, and, secondly, don't we want something finer grained? Why would we want to that per-NUMA node, which is extremely coarse?
Thanks.
Signature · 1 line
tejun
Hello tejun, peter and yinghai
Quoted 31 lines · Tejun Heo
Hello,
Quoted 3 lines · Yinghai Lu
The problem is how to define "amount necessary". If we can parse srat early, then we could just map RAM for all boot nodes one time, instead of try some small and then after SRAT table, expand it cover non-boot nodes.
Wouldn't that amount be fairly static and restricted? If you wanna chunk memory init anyway, there's no reason to init more than necessary until smp stage is reached. The more you do early, the more serialized you're, so wouldn't the goal naturally be initing the minimum possible?
Quoted 3 lines
To keep non-boot numa node hot-removable. we need to page table (and other that we allocate during boot stage) on ram of non boot nodes, or their local node ram. (share page table always should be on boot nodes).
The above assumes the followings,
* 4k page mappings. It'd be nice to keep everything working for 4k but just following SRAT isn't enough. What if the non-hotpluggable boot node doesn't stretch high enough and page table reaches down too far? This won't be an optional behavior, so it is actually *likely* to happen on certain setups.
* Memory hotplug is at NUMA node granularity instead of device.
Quoted 4 lines
Quoted 3 lines
Optimizing NUMA boot just requires moving the heavy lifting to appropriate NUMA nodes. It doesn't require that early boot phase should strictly follow NUMA node boundaries.
Quoted 9 lines
Quoted 3 lines
At end of day, I like to see all numa system (ram/cpu/pci) could have non boot nodes to be hot-removed logically. with any boot command line.
I suppose you mean "without any boot command line"? Sure, but, first of all, there is a clear performance trade-off, and, secondly, don't we want something finer grained? Why would we want to that per-NUMA node, which is extremely coarse?
Both ways seem ok enough *currently*. But what tejun always emphasizes is the trade-off, or benefit / cost ratio.
Yinghai and peter insist on the long-term plan. But it seems currently no actual requirements and plans that *must* parse SRAT earlier comparing to the current approach in this patchset, right?
Should we follow "Make it work first and optimize/beautify it later"? I think if we have the scene that must parse SRAT earlier, I think tejun will have no objection to it.
Signature · 2 lines
Thanks. Zhang Yanfei
Quoted 7 lines · Tejun Heo
Hello,
Quoted 3 lines · Yinghai Lu
The problem is how to define "amount necessary". If we can parse srat early, then we could just map RAM for all boot nodes one time, instead of try some small and then after SRAT table, expand it cover non-boot nodes.
Quoted 5 lines
Wouldn't that amount be fairly static and restricted? If you wanna chunk memory init anyway, there's no reason to init more than necessary until smp stage is reached. The more you do early, the more serialized you're, so wouldn't the goal naturally be initing the minimum possible?
Even we try to go minimum range instead of range that whole range on boot node, without parsing srat at first, the minimum range could be crossed the boundary of nodes.
Quoted 5 lines
Quoted 4 lines
To keep non-boot numa node hot-removable. we need to page table (and other that we allocate during boot stage) on ram of non boot nodes, or their local node ram. (share page table always should be on boot nodes).
Quoted 7 lines
The above assumes the followings,
* 4k page mappings. It'd be nice to keep everything working for 4k but just following SRAT isn't enough. What if the non-hotpluggable boot node doesn't stretch high enough and page table reaches down too far? This won't be an optional behavior, so it is actually *likely* to happen on certain setups.
no, do not assume 4k page. even we are using 1GB mapping, we will still have chance to have one node to take 512G RAM, that means we can have one 4k page on local node ram.
Quoted 2 lines
* Memory hotplug is at NUMA node granularity instead of device.
Yes.
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
Optimizing NUMA boot just requires moving the heavy lifting to appropriate NUMA nodes. It doesn't require that early boot phase should strictly follow NUMA node boundaries.
Quoted 8 lines
Quoted 3 lines
At end of day, I like to see all numa system (ram/cpu/pci) could have non boot nodes to be hot-removed logically. with any boot command line.
I suppose you mean "without any boot command line"? Sure, but, first of all, there is a clear performance trade-off, and, secondly, don't we want something finer grained? Why would we want to that per-NUMA node, which is extremely coarse?
On x86 system with intel new cpus there is memory controller built-in., could have hotplug modules (with socket and memory) and those hotplug modules will be serviced as one single point. Just nowadays like we have pcie card hotplugable.
I don't see where is the " a clear performance trade-off".
Yinghai
Hello, Yinghai.
Quoted 9 lines · Yinghai Lu
Quoted 5 lines
Wouldn't that amount be fairly static and restricted? If you wanna chunk memory init anyway, there's no reason to init more than necessary until smp stage is reached. The more you do early, the more serialized you're, so wouldn't the goal naturally be initing the minimum possible?
Even we try to go minimum range instead of range that whole range on boot node, without parsing srat at first, the minimum range could be crossed the boundary of nodes.
I guess it depends on how much is the minimum we're talking about, but let's say it isn't multiple orders of magnitude larger than the kernel image. That shouldn't be a problem then, no?
The thing is I don't really see how SRAT would help much. I don't know how the existing systems are configured but it's natural to assume that hardware-wise per-stick removal will be supported, right? There's no reason for memory sticks of the first numa node can't be hotunplugged. Likely we'll end up with SRAT map which splits the first node into two pieces - the first smaller part which can't be removed because firmwares and stuff depend on them and the larger tailing chunk which can be removed. Allocating early non-migratable stuff near the kernel image, which can't be moved without an additional layer of indirection anyway would be fairly good choice regardless, right?
Even if we parse SRAT early, we can't unconditionally make the kernel allocate early stuff from node0. We do not know how SRAT will look like in future configurations. If what the hotplug people are saying is true, the first non-hotpluggable node being relatively small seems actually quite likely. I don't think we want to factor all those variables into very early bootstrap stages and it's not like we're talking about gigabytes of memory. e.g. bring up the first half or one gig and go from there. That part of memory is highly unlikely to be unpluggable anyway.
Quoted 9 lines
Quoted 5 lines
* 4k page mappings. It'd be nice to keep everything working for 4k but just following SRAT isn't enough. What if the non-hotpluggable boot node doesn't stretch high enough and page table reaches down too far? This won't be an optional behavior, so it is actually *likely* to happen on certain setups.
no, do not assume 4k page. even we are using 1GB mapping, we will still have chance to have one node to take 512G RAM, that means we can have one 4k page on local node ram.
Sure, the kernel image can also be located such that the last page spills over to the next node too. No matter what we do, without an extra layer of indirection, this can't be a complete solution. Think about the usual node configuration and where kernel image is usually loaded. As long as page table is relatively small, it is highly unlikely to increase the chance of such issues.
Again, it's all about benefit and cost. Sure, parsing SRAT early will definitely decrease the chance of such issues. However, as long as the size of page table is small enough, just allocating those on top of the kernel isn't significantly worse. Also, following SRAT earlier not only increases complexity in vulnerable stages of boot but also carries higher risk with the existing and future configurations depending on how their SRAT looks like if the new behavior is applied unconditionally. If we decide to make early SRAT usage conditional, that a *LOT* more conditional code than what's added by bottom-up allocation.
Quoted 6 lines
On x86 system with intel new cpus there is memory controller built-in., could have hotplug modules (with socket and memory) and those hotplug modules will be serviced as one single point. Just nowadays like we have pcie card hotplugable.
I don't see where is the " a clear performance trade-off".
Because kernel data structures have to be allocated off-node.
Thanks.
Signature · 1 line
tejun
H. Peter Anvin
reviewerQuoted 18 lines · Yinghai Lu
The points for parsing SRAT early instead of Yanfei/Tang v7:
1. We just reached one unified path to setup page tables for 32bit, 64bit and xen or non xen after several years. We should not have add another path for system
that support hotplug.2. also we should avoid adding "
movable_nodes" command line.3. debug mapping 4k, and it is working all the way, why breaking it even for memory hotplug path?
4.
numa_meminfonow is static structure.
we have no reason that we can not parse SRAT etc to fill that struct.5. for device tree, i assume that we could do same like srat parsing to find out numa to fill the
numa_meminfoearly. or with help of BRK.
Quoted 9 lines
6. in the long run, We should rework our NUMA booting:
a. boot system with boot numa nodes early only.
b. in later init stage or user space, init other nodes RAM/CPU/PCI...in parallel.
that will reduce boot time for 8 sockets/32 sockets dramatically.We will need to parse srat table early so could avoid init memory for non-boot nodes.
I really like the long-term plan (and, I might want to add, the above writeup.)
However, I don't understand how we can avoid #2, given that it is fundamentally a sysadmin-driven tradeoff between performance and reliability.
-hpa
On Mon, Oct 14, 2013 at 1:35 PM, H. Peter Anvin <[email protected]> wrote:
...
Quoted 1 line
Quoted 1 line
2. also we should avoid adding "
movable_nodes" command line.
...
Quoted 10 lines
Quoted 9 lines
6. in the long run, We should rework our NUMA booting:
a. boot system with boot numa nodes early only.
b. in later init stage or user space, init other nodes RAM/CPU/PCI...in parallel.
that will reduce boot time for 8 sockets/32 sockets dramatically.We will need to parse srat table early so could avoid init memory for non-boot nodes.
Quoted 6 lines
I really like the long-term plan (and, I might want to add, the above writeup.)
However, I don't understand how we can avoid #2, given that it is fundamentally a sysadmin-driven tradeoff between performance and reliability.
If we make all numa systems support nodes hot-remove logically. like we boot system with node0, and hot add other nodes one by one, we should hot remove them later.
Thanks
Yinghai
H. Peter Anvin
reviewerQuoted 9 lines · Yinghai Lu
Quoted 4 lines
However, I don't understand how we can avoid #2, given that it is fundamentally a sysadmin-driven tradeoff between performance and reliability.
If we make all numa systems support nodes hot-remove logically. like we boot system with node0, and hot add other nodes one by one, we should hot remove them later.
No, it doesn't work that way for memory. You can't do nonmovable allocations from a node that you may need to yank, unless you can migrate that memory node transparently (which hardware can do.)
-hpa
Hello guys,
Could anyone help reviewing this part?
The first part has been merged into linus's tree. And I've tried to apply this part to today's linus tree:
commit 42a2d923cc349583ebf6fdd52a7d35e1c2f7e6bd
Merge: 5cbb3d2 75ecab1
Author: Linus Torvalds <[email protected]>
Date: Wed Nov 13 17:40:34 2013 +0900
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
No conflict, no compiling error and it works well.
Tejun, any comments?
Quoted 115 lines · Zhang Yanfei
Hello guys, this is the part2 of our memory hotplug work. This part is based on the part1:
"x86, memblock: Allocate memory near kernel image before SRAT parsed"
which is base on 3.12-rc4.You could refer part1 from: https://lkml.org/lkml/2013/10/10/644
Any comments are welcome! Thanks!
[Problem]
The current Linux cannot migrate pages used by the kerenl because of the kernel direct mapping. In Linux kernel space, va = pa +
PAGE_OFFSET. When the pa is changed, we cannot simply update the pagetable and keep the va unmodified. So the kernel pages are not migratable.There are also some other issues will cause the kernel pages not migratable. For example, the physical address may be cached somewhere and will be used. It is not to update all the caches.
When doing memory hotplug in Linux, we first migrate all the pages in one memory device somewhere else, and then remove the device. But if pages are used by the kernel, they are not migratable. As a result, memory used by the kernel cannot be hot-removed.
Modifying the kernel direct mapping mechanism is too difficult to do. And it may cause the kernel performance down and unstable. So we use the following way to do memory hotplug.
[What we are doing]
In Linux, memory in one numa node is divided into several zones. One of the zones is
ZONE_MOVABLE, which the kernel won't use.In order to implement memory hotplug in Linux, we are going to arrange all hotpluggable memory in
ZONE_MOVABLEso that the kernel won't use these memory.To do this, we need ACPI's help.
[How we do this]
In ACPI, SRAT(System Resource Affinity Table) contains NUMA info. The memory affinities in SRAT record every memory range in the system, and also, flags specifying if the memory range is hotpluggable.
(Please refer to ACPI spec 5.0 5.2.16)With the help of SRAT, we have to do the following two things to achieve our goal:
1. When doing memory hot-add, allow the users arranging hotpluggable as
ZONE_MOVABLE.
(This has been done by theMOVABLE_NODEfunctionality in Linux.)2. when the system is booting, prevent bootmem allocator from allocating hotpluggable memory for the kernel before the memory initialization finishes.
(This is what we are going to do. See below.)[About this patch-set]
In previous part's patches, we have made the kernel allocate memory near kernel image before SRAT parsed to avoid allocating hotpluggable memory for kernel. So this patch-set does the following things:
1. Improve memblock to support flags, which are used to indicate different memory type.
2. Mark all hotpluggable memory in memblock.memory[].
3. Make the default memblock allocator skip hotpluggable memory.
4. Improve "
movable_node" boot option to have higher priority of movablecore and kernelcore boot option.Change log v1 -> v2:
1. Rebase this part on the v7 version of part1
2. Fix bug: Ifmovable_nodeboot option not specified, memblock still checks hotpluggable memory when allocating memory.Tang Chen (7):
memblock, numa: Introduce flag into memblock
memblock,mem_hotplug: IntroduceMEMBLOCK_HOTPLUGflag to mark
hotpluggable regions
memblock: Makememblock_set_node()support differentmemblock_typeacpi, numa,mem_hotplug: Mark hotpluggable memory in memblock acpi, numa,mem_hotplug: Mark all nodes the kernel resides
un-hotpluggable
memblock,mem_hotplug: Make memblock skip hotpluggable regions if
needed
x86, numa, acpi, memory-hotplug: Makemovable_nodehave higher
priorityYasuaki Ishimatsu (1):
x86: get pg_data_t's memory from other nodearch/metag/mm/init.c | 3 +- arch/metag/mm/numa.c | 3 +- arch/microblaze/mm/init.c | 3 +- arch/powerpc/mm/mem.c | 2 +- arch/powerpc/mm/numa.c | 8 ++- arch/sh/kernel/setup.c | 4 +- arch/sparc/mm/init_64.c | 5 +- arch/x86/mm/init_32.c | 2 +- arch/x86/mm/init_64.c | 2 +- arch/x86/mm/numa.c | 63 +++++++++++++++++++++-- arch/x86/mm/srat.c | 5 ++ include/linux/memblock.h | 39 ++++++++++++++- mm/memblock.c | 123 ++++++++++++++++++++++++++++++++++++++------- mm/memory_hotplug.c | 1 + mm/page_alloc.c | 28 ++++++++++- 15 files changed, 252 insertions(+), 39 deletions(-)
Signature · 8 lines
Thanks. Zhang Yanfei -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
ping...
Quoted 136 lines · Zhang Yanfei
Hello guys,
Could anyone help reviewing this part?
The first part has been merged into linus's tree. And I've tried to apply this part to today's linus tree:
commit
42a2d923cc349583ebf6fdd52a7d35e1c2f7e6bd
Merge: 5cbb3d2 75ecab1
Author: Linus Torvalds <[email protected]>
Date: Wed Nov 13 17:40:34 2013 +0900Merge
git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-nextNo conflict, no compiling error and it works well.
Tejun, any comments?
Quoted 115 lines · Zhang Yanfei
Hello guys, this is the part2 of our memory hotplug work. This part is based on the part1:
"x86, memblock: Allocate memory near kernel image before SRAT parsed"
which is base on 3.12-rc4.You could refer part1 from: https://lkml.org/lkml/2013/10/10/644
Any comments are welcome! Thanks!
[Problem]
The current Linux cannot migrate pages used by the kerenl because of the kernel direct mapping. In Linux kernel space, va = pa +
PAGE_OFFSET. When the pa is changed, we cannot simply update the pagetable and keep the va unmodified. So the kernel pages are not migratable.There are also some other issues will cause the kernel pages not migratable. For example, the physical address may be cached somewhere and will be used. It is not to update all the caches.
When doing memory hotplug in Linux, we first migrate all the pages in one memory device somewhere else, and then remove the device. But if pages are used by the kernel, they are not migratable. As a result, memory used by the kernel cannot be hot-removed.
Modifying the kernel direct mapping mechanism is too difficult to do. And it may cause the kernel performance down and unstable. So we use the following way to do memory hotplug.
[What we are doing]
In Linux, memory in one numa node is divided into several zones. One of the zones is
ZONE_MOVABLE, which the kernel won't use.In order to implement memory hotplug in Linux, we are going to arrange all hotpluggable memory in
ZONE_MOVABLEso that the kernel won't use these memory.To do this, we need ACPI's help.
[How we do this]
In ACPI, SRAT(System Resource Affinity Table) contains NUMA info. The memory affinities in SRAT record every memory range in the system, and also, flags specifying if the memory range is hotpluggable.
(Please refer to ACPI spec 5.0 5.2.16)With the help of SRAT, we have to do the following two things to achieve our goal:
1. When doing memory hot-add, allow the users arranging hotpluggable as
ZONE_MOVABLE.
(This has been done by theMOVABLE_NODEfunctionality in Linux.)2. when the system is booting, prevent bootmem allocator from allocating hotpluggable memory for the kernel before the memory initialization finishes.
(This is what we are going to do. See below.)[About this patch-set]
In previous part's patches, we have made the kernel allocate memory near kernel image before SRAT parsed to avoid allocating hotpluggable memory for kernel. So this patch-set does the following things:
1. Improve memblock to support flags, which are used to indicate different memory type.
2. Mark all hotpluggable memory in memblock.memory[].
3. Make the default memblock allocator skip hotpluggable memory.
4. Improve "
movable_node" boot option to have higher priority of movablecore and kernelcore boot option.Change log v1 -> v2:
1. Rebase this part on the v7 version of part1
2. Fix bug: Ifmovable_nodeboot option not specified, memblock still checks hotpluggable memory when allocating memory.Tang Chen (7):
memblock, numa: Introduce flag into memblock
memblock,mem_hotplug: IntroduceMEMBLOCK_HOTPLUGflag to mark
hotpluggable regions
memblock: Makememblock_set_node()support differentmemblock_typeacpi, numa,mem_hotplug: Mark hotpluggable memory in memblock acpi, numa,mem_hotplug: Mark all nodes the kernel resides
un-hotpluggable
memblock,mem_hotplug: Make memblock skip hotpluggable regions if
needed
x86, numa, acpi, memory-hotplug: Makemovable_nodehave higher
priorityYasuaki Ishimatsu (1):
x86: get pg_data_t's memory from other nodearch/metag/mm/init.c | 3 +- arch/metag/mm/numa.c | 3 +- arch/microblaze/mm/init.c | 3 +- arch/powerpc/mm/mem.c | 2 +- arch/powerpc/mm/numa.c | 8 ++- arch/sh/kernel/setup.c | 4 +- arch/sparc/mm/init_64.c | 5 +- arch/x86/mm/init_32.c | 2 +- arch/x86/mm/init_64.c | 2 +- arch/x86/mm/numa.c | 63 +++++++++++++++++++++-- arch/x86/mm/srat.c | 5 ++ include/linux/memblock.h | 39 ++++++++++++++- mm/memblock.c | 123 ++++++++++++++++++++++++++++++++++++++------- mm/memory_hotplug.c | 1 + mm/page_alloc.c | 28 ++++++++++- 15 files changed, 252 insertions(+), 39 deletions(-)
Signature · 8 lines
Thanks. Zhang Yanfei -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>