Message ID | 1439781546-7217-10-git-send-email-jiang.liu@linux.intel.com (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
Hi Liu, On 08/17/2015 11:19 AM, Jiang Liu wrote: > ...... > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig > index b3a1a5d77d92..5d7ad70ace0d 100644 > --- a/arch/x86/Kconfig > +++ b/arch/x86/Kconfig > @@ -2069,6 +2069,9 @@ config USE_PERCPU_NUMA_NODE_ID > def_bool y > depends on NUMA > > +config HAVE_MEMORYLESS_NODES > + def_bool NUMA > + > config ARCH_ENABLE_SPLIT_PMD_PTLOCK > def_bool y > depends on X86_64 || X86_PAE > diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c > index 07930e1d2fe9..3403f1f0f28d 100644 > --- a/arch/x86/kernel/acpi/boot.c > +++ b/arch/x86/kernel/acpi/boot.c > @@ -711,6 +711,7 @@ static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) > } > set_apicid_to_node(physid, nid); > numa_set_node(cpu, nid); > + set_cpu_numa_mem(cpu, local_memory_node(nid)); > } > #endif > } > @@ -743,9 +744,10 @@ int acpi_unmap_cpu(int cpu) > { > #ifdef CONFIG_ACPI_NUMA > set_apicid_to_node(per_cpu(x86_cpu_to_apicid, cpu), NUMA_NO_NODE); > + set_cpu_numa_mem(cpu, NUMA_NO_NODE); > #endif > > - per_cpu(x86_cpu_to_apicid, cpu) = -1; > + per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID; > set_cpu_present(cpu, false); > num_processors--; > > diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c > index b1f3ed9c7a9e..aeec91ac6fd4 100644 > --- a/arch/x86/kernel/smpboot.c > +++ b/arch/x86/kernel/smpboot.c > @@ -162,6 +162,8 @@ static void smp_callin(void) > */ > phys_id = read_apic_id(); > > + set_numa_mem(local_memory_node(cpu_to_node(cpuid))); > + > /* > * the boot CPU has finished the init stage and is spinning > * on callin_map until we finish. We are free to set up this > diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c > index 08860bdf5744..f2a4e23bd14d 100644 > --- a/arch/x86/mm/numa.c > +++ b/arch/x86/mm/numa.c > @@ -22,6 +22,7 @@ > > int __initdata numa_off; > nodemask_t numa_nodes_parsed __initdata; > +static nodemask_t numa_nodes_empty __initdata; > > struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; > EXPORT_SYMBOL(node_data); > @@ -560,17 +561,16 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) > end = max(mi->blk[i].end, end); > } > > - if (start >= end) > - continue; > - > /* > * Don't confuse VM with a node that doesn't have the > * minimum amount of memory: > */ > - if (end && (end - start) < NODE_MIN_SIZE) > - continue; > - > - alloc_node_data(nid); > + if (start < end && (end - start) >= NODE_MIN_SIZE) { > + alloc_node_data(nid); > + } else if (IS_ENABLED(CONFIG_HAVE_MEMORYLESS_NODES)) { > + alloc_node_data(nid); > + node_set(nid, numa_nodes_empty); Seeing from here, I think numa_nodes_empty represents all memory-less nodes. So, since we still have cpu-less nodes out there, shall we rename it to numa_nodes_memoryless or something similar ? And BTW, does x86 support cpu-less node after these patches ? Since I don't have any memory-less or cpu-less node on my box, I cannot tell it clearly. A node is brought online when is has memory in original kernel. So I think it is supported. > + } > } > > /* Dump memblock with node info and return. */ > @@ -587,14 +587,18 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) > */ > static void __init numa_init_array(void) > { > - int rr, i; > + int i, rr = MAX_NUMNODES; > > - rr = first_node(node_online_map); > for (i = 0; i < nr_cpu_ids; i++) { > + /* Search for an onlined node with memory */ > + do { > + if (rr != MAX_NUMNODES) > + rr = next_node(rr, node_online_map); > + if (rr == MAX_NUMNODES) > + rr = first_node(node_online_map); > + } while (node_isset(rr, numa_nodes_empty)); > + > numa_set_node(i, rr); > - rr = next_node(rr, node_online_map); > - if (rr == MAX_NUMNODES) > - rr = first_node(node_online_map); > } > } > > @@ -696,9 +700,12 @@ static __init int find_near_online_node(int node) > { > int n, val; > int min_val = INT_MAX; > - int best_node = -1; > + int best_node = NUMA_NO_NODE; > > for_each_online_node(n) { > + if (node_isset(n, numa_nodes_empty)) > + continue; > + > val = node_distance(node, n); > > if (val < min_val) { > @@ -739,6 +746,22 @@ void __init init_cpu_to_node(void) > if (!node_online(node)) > node = find_near_online_node(node); > numa_set_node(cpu, node); So, CPUs are still mapped to online near node, right ? I was expecting CPUs on a memory-less node are mapped to the node they belong to. If so, the current memory allocator may fail because they assume each online node has memory. I was trying to do this in my patch. https://lkml.org/lkml/2015/7/7/205 Of course, my patch is not to support memory-less node, just run into this problem. > + if (node_spanned_pages(node)) > + set_cpu_numa_mem(cpu, node); > + if (IS_ENABLED(CONFIG_HAVE_MEMORYLESS_NODES)) > + node_clear(node, numa_nodes_empty); And since we are supporting memory-less node, it's better to provide a for_each_memoryless_node() wrapper. > + } > + > + /* Destroy empty nodes */ > + if (IS_ENABLED(CONFIG_HAVE_MEMORYLESS_NODES)) { > + int nid; > + const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE); > + > + for_each_node_mask(nid, numa_nodes_empty) { > + node_set_offline(nid); > + memblock_free(__pa(node_data[nid]), nd_size); > + node_data[nid] = NULL; So, memory-less nodes are set offline finally. It's a little different from what I thought. I was expecting that both memory-less and cpu-less nodes could also be online after this patch, which would be very helpful to me. But actually, they are just exist temporarily, used to set _numa_mem_ so that cpu_to_mem() is able to work, right ? Thanks. > + } > } > } > -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
* Jiang Liu <jiang.liu@linux.intel.com> wrote: > With current implementation, all CPUs within a NUMA node will be > assocaited with another NUMA node if the node has no memory installed. typo. > > For example, on a four-node system, CPUs on node 2 and 3 are associated > with node 0 when are no memory install on node 2 and 3, which may > confuse users. > > root@bkd01sdp:~# numactl --hardware > available: 2 nodes (0-1) > node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 > node 0 size: 15602 MB > node 0 free: 15014 MB > node 1 cpus: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 > node 1 size: 15985 MB > node 1 free: 15686 MB > node distances: > node 0 1 > 0: 10 21 > 1: 21 10 > > To be worse, the CPU affinity relationship won't get fixed even after > memory has been added to those nodes. After memory hot-addition to > node 2, CPUs on node 2 are still associated with node 0. This may cause > sub-optimal performance. > root@bkd01sdp:/sys/devices/system/node/node2# numactl --hardware > available: 3 nodes (0-2) > node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 > node 0 size: 15602 MB > node 0 free: 14743 MB > node 1 cpus: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 > node 1 size: 15985 MB > node 1 free: 15715 MB > node 2 cpus: > node 2 size: 128 MB > node 2 free: 128 MB > node distances: > node 0 1 2 > 0: 10 21 21 > 1: 21 10 21 > 2: 21 21 10 > > With support of memoryless node enabled, it will correctly report system > hardware topology for nodes without memory installed. > root@bkd01sdp:~# numactl --hardware > available: 4 nodes (0-3) > node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 > node 0 size: 15725 MB > node 0 free: 15129 MB > node 1 cpus: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 > node 1 size: 15862 MB > node 1 free: 15627 MB > node 2 cpus: 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 > node 2 size: 0 MB > node 2 free: 0 MB > node 3 cpus: 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 > node 3 size: 0 MB > node 3 free: 0 MB > node distances: > node 0 1 2 3 > 0: 10 21 21 21 > 1: 21 10 21 21 > 2: 21 21 10 21 > 3: 21 21 21 10 > > With memoryless node enabled, CPUs are correctly associated with node 2 > after memory hot-addition to node 2. > root@bkd01sdp:/sys/devices/system/node/node2# numactl --hardware > available: 4 nodes (0-3) > node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 > node 0 size: 15725 MB > node 0 free: 14872 MB > node 1 cpus: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 > node 1 size: 15862 MB > node 1 free: 15641 MB > node 2 cpus: 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 > node 2 size: 128 MB > node 2 free: 127 MB > node 3 cpus: 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 > node 3 size: 0 MB > node 3 free: 0 MB > node distances: > node 0 1 2 3 > 0: 10 21 21 21 > 1: 21 10 21 21 > 2: 21 21 10 21 > 3: 21 21 21 10 > > Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> > --- > arch/x86/Kconfig | 3 +++ > arch/x86/kernel/acpi/boot.c | 4 +++- > arch/x86/kernel/smpboot.c | 2 ++ > arch/x86/mm/numa.c | 49 +++++++++++++++++++++++++++++++------------ > 4 files changed, 44 insertions(+), 14 deletions(-) > > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig > index b3a1a5d77d92..5d7ad70ace0d 100644 > --- a/arch/x86/Kconfig > +++ b/arch/x86/Kconfig > @@ -2069,6 +2069,9 @@ config USE_PERCPU_NUMA_NODE_ID > def_bool y > depends on NUMA > > +config HAVE_MEMORYLESS_NODES > + def_bool NUMA > + > config ARCH_ENABLE_SPLIT_PMD_PTLOCK > def_bool y > depends on X86_64 || X86_PAE > diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c > index 07930e1d2fe9..3403f1f0f28d 100644 > --- a/arch/x86/kernel/acpi/boot.c > +++ b/arch/x86/kernel/acpi/boot.c > @@ -711,6 +711,7 @@ static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) > } > set_apicid_to_node(physid, nid); > numa_set_node(cpu, nid); > + set_cpu_numa_mem(cpu, local_memory_node(nid)); > } > #endif > } > @@ -743,9 +744,10 @@ int acpi_unmap_cpu(int cpu) > { > #ifdef CONFIG_ACPI_NUMA > set_apicid_to_node(per_cpu(x86_cpu_to_apicid, cpu), NUMA_NO_NODE); > + set_cpu_numa_mem(cpu, NUMA_NO_NODE); > #endif > > - per_cpu(x86_cpu_to_apicid, cpu) = -1; > + per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID; > set_cpu_present(cpu, false); > num_processors--; > > diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c > index b1f3ed9c7a9e..aeec91ac6fd4 100644 > --- a/arch/x86/kernel/smpboot.c > +++ b/arch/x86/kernel/smpboot.c > @@ -162,6 +162,8 @@ static void smp_callin(void) > */ > phys_id = read_apic_id(); > > + set_numa_mem(local_memory_node(cpu_to_node(cpuid))); > + > /* > * the boot CPU has finished the init stage and is spinning > * on callin_map until we finish. We are free to set up this > diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c > index 08860bdf5744..f2a4e23bd14d 100644 > --- a/arch/x86/mm/numa.c > +++ b/arch/x86/mm/numa.c > @@ -22,6 +22,7 @@ > > int __initdata numa_off; > nodemask_t numa_nodes_parsed __initdata; > +static nodemask_t numa_nodes_empty __initdata; > > struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; > EXPORT_SYMBOL(node_data); > @@ -560,17 +561,16 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) > end = max(mi->blk[i].end, end); > } > > - if (start >= end) > - continue; > - > /* > * Don't confuse VM with a node that doesn't have the > * minimum amount of memory: > */ > - if (end && (end - start) < NODE_MIN_SIZE) > - continue; > - > - alloc_node_data(nid); > + if (start < end && (end - start) >= NODE_MIN_SIZE) { > + alloc_node_data(nid); > + } else if (IS_ENABLED(CONFIG_HAVE_MEMORYLESS_NODES)) { > + alloc_node_data(nid); > + node_set(nid, numa_nodes_empty); > + } > } > > /* Dump memblock with node info and return. */ > @@ -587,14 +587,18 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) > */ > static void __init numa_init_array(void) > { > - int rr, i; > + int i, rr = MAX_NUMNODES; > > - rr = first_node(node_online_map); > for (i = 0; i < nr_cpu_ids; i++) { > + /* Search for an onlined node with memory */ > + do { > + if (rr != MAX_NUMNODES) > + rr = next_node(rr, node_online_map); > + if (rr == MAX_NUMNODES) > + rr = first_node(node_online_map); > + } while (node_isset(rr, numa_nodes_empty)); > + > numa_set_node(i, rr); > - rr = next_node(rr, node_online_map); > - if (rr == MAX_NUMNODES) > - rr = first_node(node_online_map); > } > } > > @@ -696,9 +700,12 @@ static __init int find_near_online_node(int node) > { > int n, val; > int min_val = INT_MAX; > - int best_node = -1; > + int best_node = NUMA_NO_NODE; > > for_each_online_node(n) { > + if (node_isset(n, numa_nodes_empty)) > + continue; > + > val = node_distance(node, n); > > if (val < min_val) { > @@ -739,6 +746,22 @@ void __init init_cpu_to_node(void) > if (!node_online(node)) > node = find_near_online_node(node); > numa_set_node(cpu, node); > + if (node_spanned_pages(node)) > + set_cpu_numa_mem(cpu, node); > + if (IS_ENABLED(CONFIG_HAVE_MEMORYLESS_NODES)) > + node_clear(node, numa_nodes_empty); > + } > + > + /* Destroy empty nodes */ > + if (IS_ENABLED(CONFIG_HAVE_MEMORYLESS_NODES)) { > + int nid; > + const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE); > + > + for_each_node_mask(nid, numa_nodes_empty) { > + node_set_offline(nid); > + memblock_free(__pa(node_data[nid]), nd_size); > + node_data[nid] = NULL; > + } > } > } So this patch makes messy code even messier. I'd like to see the fixes, but this really needs to be done cleaner. There are several problems: 1) the naming is not clear enough between VM and scheduling nodes and their masks. For example we are mixing uses of 'numa_nodes_empty' (a memory space concept), 'node_online_map' (a scheduling concept), which makes the code hard to read. To add insult to injury, 'numa_nodes_empty' is added with zero comments: > +static nodemask_t numa_nodes_empty __initdata; To resolve this the names should be clearer I think. Something like numa_nomem_mask or so. 2) the existing code is (unfortunately) confusing to begin with. For example what does find_near_online_node() do? It's not commented. init_cpu_to_node() has comments but it's mostly implementational gibberish that does not answer the question of what the function's main, high level purpose is. I'm uneasy about modifying code that is hard to read - it should be improved first. 3) So I'm wondering about logic like this: > + if (node_spanned_pages(node)) > + set_cpu_numa_mem(cpu, node); So first we link the node in the _numa_mem_ array if the node has memory (?). > + if (IS_ENABLED(CONFIG_HAVE_MEMORYLESS_NODES)) > + node_clear(node, numa_nodes_empty); But we unconditionally clear it in the numa_nodes_empty - i.e. it has memory? Shouldn't the node_clear() be inside the 'has memory' condition? 4) Bits like this are confusing: > + /* Destroy empty nodes */ > + if (IS_ENABLED(CONFIG_HAVE_MEMORYLESS_NODES)) { > + int nid; > + const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE); Why do we 'destroy' them? What does 'destroy' mean here? So I think this series should first make the whole code readable and understandable - then fix the bugs as gradually as possible: one bug one patch. Thanks, Ingo -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 08/18/2015 02:59 PM, Jiang Liu wrote: > > ... >>> } >>> @@ -739,6 +746,22 @@ void __init init_cpu_to_node(void) >>> if (!node_online(node)) >>> node = find_near_online_node(node); Hi Liu, If cpu-less, memory-less and normal node will all be online anyway, I think we don't need to find_near_online_node() any more for CPUs on offline nodes. Or is there any other case ? Thanks. -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b3a1a5d77d92..5d7ad70ace0d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2069,6 +2069,9 @@ config USE_PERCPU_NUMA_NODE_ID def_bool y depends on NUMA +config HAVE_MEMORYLESS_NODES + def_bool NUMA + config ARCH_ENABLE_SPLIT_PMD_PTLOCK def_bool y depends on X86_64 || X86_PAE diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 07930e1d2fe9..3403f1f0f28d 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -711,6 +711,7 @@ static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) } set_apicid_to_node(physid, nid); numa_set_node(cpu, nid); + set_cpu_numa_mem(cpu, local_memory_node(nid)); } #endif } @@ -743,9 +744,10 @@ int acpi_unmap_cpu(int cpu) { #ifdef CONFIG_ACPI_NUMA set_apicid_to_node(per_cpu(x86_cpu_to_apicid, cpu), NUMA_NO_NODE); + set_cpu_numa_mem(cpu, NUMA_NO_NODE); #endif - per_cpu(x86_cpu_to_apicid, cpu) = -1; + per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID; set_cpu_present(cpu, false); num_processors--; diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index b1f3ed9c7a9e..aeec91ac6fd4 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -162,6 +162,8 @@ static void smp_callin(void) */ phys_id = read_apic_id(); + set_numa_mem(local_memory_node(cpu_to_node(cpuid))); + /* * the boot CPU has finished the init stage and is spinning * on callin_map until we finish. We are free to set up this diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 08860bdf5744..f2a4e23bd14d 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -22,6 +22,7 @@ int __initdata numa_off; nodemask_t numa_nodes_parsed __initdata; +static nodemask_t numa_nodes_empty __initdata; struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; EXPORT_SYMBOL(node_data); @@ -560,17 +561,16 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) end = max(mi->blk[i].end, end); } - if (start >= end) - continue; - /* * Don't confuse VM with a node that doesn't have the * minimum amount of memory: */ - if (end && (end - start) < NODE_MIN_SIZE) - continue; - - alloc_node_data(nid); + if (start < end && (end - start) >= NODE_MIN_SIZE) { + alloc_node_data(nid); + } else if (IS_ENABLED(CONFIG_HAVE_MEMORYLESS_NODES)) { + alloc_node_data(nid); + node_set(nid, numa_nodes_empty); + } } /* Dump memblock with node info and return. */ @@ -587,14 +587,18 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) */ static void __init numa_init_array(void) { - int rr, i; + int i, rr = MAX_NUMNODES; - rr = first_node(node_online_map); for (i = 0; i < nr_cpu_ids; i++) { + /* Search for an onlined node with memory */ + do { + if (rr != MAX_NUMNODES) + rr = next_node(rr, node_online_map); + if (rr == MAX_NUMNODES) + rr = first_node(node_online_map); + } while (node_isset(rr, numa_nodes_empty)); + numa_set_node(i, rr); - rr = next_node(rr, node_online_map); - if (rr == MAX_NUMNODES) - rr = first_node(node_online_map); } } @@ -696,9 +700,12 @@ static __init int find_near_online_node(int node) { int n, val; int min_val = INT_MAX; - int best_node = -1; + int best_node = NUMA_NO_NODE; for_each_online_node(n) { + if (node_isset(n, numa_nodes_empty)) + continue; + val = node_distance(node, n); if (val < min_val) { @@ -739,6 +746,22 @@ void __init init_cpu_to_node(void) if (!node_online(node)) node = find_near_online_node(node); numa_set_node(cpu, node); + if (node_spanned_pages(node)) + set_cpu_numa_mem(cpu, node); + if (IS_ENABLED(CONFIG_HAVE_MEMORYLESS_NODES)) + node_clear(node, numa_nodes_empty); + } + + /* Destroy empty nodes */ + if (IS_ENABLED(CONFIG_HAVE_MEMORYLESS_NODES)) { + int nid; + const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE); + + for_each_node_mask(nid, numa_nodes_empty) { + node_set_offline(nid); + memblock_free(__pa(node_data[nid]), nd_size); + node_data[nid] = NULL; + } } }
With current implementation, all CPUs within a NUMA node will be assocaited with another NUMA node if the node has no memory installed. For example, on a four-node system, CPUs on node 2 and 3 are associated with node 0 when are no memory install on node 2 and 3, which may confuse users. root@bkd01sdp:~# numactl --hardware available: 2 nodes (0-1) node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 node 0 size: 15602 MB node 0 free: 15014 MB node 1 cpus: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 node 1 size: 15985 MB node 1 free: 15686 MB node distances: node 0 1 0: 10 21 1: 21 10 To be worse, the CPU affinity relationship won't get fixed even after memory has been added to those nodes. After memory hot-addition to node 2, CPUs on node 2 are still associated with node 0. This may cause sub-optimal performance. root@bkd01sdp:/sys/devices/system/node/node2# numactl --hardware available: 3 nodes (0-2) node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 node 0 size: 15602 MB node 0 free: 14743 MB node 1 cpus: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 node 1 size: 15985 MB node 1 free: 15715 MB node 2 cpus: node 2 size: 128 MB node 2 free: 128 MB node distances: node 0 1 2 0: 10 21 21 1: 21 10 21 2: 21 21 10 With support of memoryless node enabled, it will correctly report system hardware topology for nodes without memory installed. root@bkd01sdp:~# numactl --hardware available: 4 nodes (0-3) node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 node 0 size: 15725 MB node 0 free: 15129 MB node 1 cpus: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 node 1 size: 15862 MB node 1 free: 15627 MB node 2 cpus: 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 node 2 size: 0 MB node 2 free: 0 MB node 3 cpus: 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 node 3 size: 0 MB node 3 free: 0 MB node distances: node 0 1 2 3 0: 10 21 21 21 1: 21 10 21 21 2: 21 21 10 21 3: 21 21 21 10 With memoryless node enabled, CPUs are correctly associated with node 2 after memory hot-addition to node 2. root@bkd01sdp:/sys/devices/system/node/node2# numactl --hardware available: 4 nodes (0-3) node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 node 0 size: 15725 MB node 0 free: 14872 MB node 1 cpus: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 node 1 size: 15862 MB node 1 free: 15641 MB node 2 cpus: 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 node 2 size: 128 MB node 2 free: 127 MB node 3 cpus: 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 node 3 size: 0 MB node 3 free: 0 MB node distances: node 0 1 2 3 0: 10 21 21 21 1: 21 10 21 21 2: 21 21 10 21 3: 21 21 21 10 Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> --- arch/x86/Kconfig | 3 +++ arch/x86/kernel/acpi/boot.c | 4 +++- arch/x86/kernel/smpboot.c | 2 ++ arch/x86/mm/numa.c | 49 +++++++++++++++++++++++++++++++------------ 4 files changed, 44 insertions(+), 14 deletions(-)