If the new NUMA node onlined doesn't have a abstract distance assigned, the kernel adds the NUMA node to default memory tier. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@xxxxxxxxxxxxx> --- include/linux/memory-tiers.h | 1 + mm/memory-tiers.c | 83 ++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/include/linux/memory-tiers.h b/include/linux/memory-tiers.h index b85901c0caba..976f43a5e3be 100644 --- a/include/linux/memory-tiers.h +++ b/include/linux/memory-tiers.h @@ -13,6 +13,7 @@ #define MEMTIER_ADISTANCE_DRAM (1 << (MEMTIER_CHUNK_BITS + 2)) /* leave one tier below this slow pmem */ #define MEMTIER_ADISTANCE_PMEM (1 << MEMTIER_CHUNK_BITS) +#define MEMTIER_HOTPLUG_PRIO 100 #ifdef CONFIG_NUMA #include <linux/types.h> diff --git a/mm/memory-tiers.c b/mm/memory-tiers.c index 03e43f3dc942..c9854a394d9b 100644 --- a/mm/memory-tiers.c +++ b/mm/memory-tiers.c @@ -3,6 +3,7 @@ #include <linux/nodemask.h> #include <linux/slab.h> #include <linux/lockdep.h> +#include <linux/memory.h> #include <linux/memory-tiers.h> struct memory_tier { @@ -83,6 +84,87 @@ static struct memory_tier *find_create_memory_tier(struct memory_dev_type *memty return new_memtier; } +static struct memory_tier *__node_get_memory_tier(int node) +{ + struct memory_dev_type *memtype; + + memtype = node_memory_types[node]; + if (memtype) + return memtype->memtier; + return NULL; +} + +static void init_node_memory_tier(int node) +{ + struct memory_tier *memtier; + + mutex_lock(&memory_tier_lock); + + memtier = __node_get_memory_tier(node); + if (!memtier) { + struct memory_dev_type *memtype; + + if (!node_memory_types[node]) { + node_memory_types[node] = &default_dram_type; + node_set(node, default_dram_type.nodes); + } + memtype = node_memory_types[node]; + memtier = find_create_memory_tier(memtype); + } + mutex_unlock(&memory_tier_lock); +} + +static void destroy_memory_tier(struct memory_tier *memtier) +{ + list_del(&memtier->list); + kfree(memtier); +} + +static void clear_node_memory_tier(int node) +{ + struct memory_tier *current_memtier; + + mutex_lock(&memory_tier_lock); + current_memtier = __node_get_memory_tier(node); + if (current_memtier) { + struct memory_dev_type *memtype; + + memtype = node_memory_types[node]; + node_clear(node, memtype->nodes); + if (nodes_empty(memtype->nodes)) { + list_del(&memtype->tier_sibiling); + memtype->memtier = NULL; + if (list_empty(¤t_memtier->memory_types)) + destroy_memory_tier(current_memtier); + } + } + mutex_unlock(&memory_tier_lock); +} + +static int __meminit memtier_hotplug_callback(struct notifier_block *self, + unsigned long action, void *_arg) +{ + struct memory_notify *arg = _arg; + + /* + * Only update the node migration order when a node is + * changing status, like online->offline. + */ + if (arg->status_change_nid < 0) + return notifier_from_errno(0); + + switch (action) { + case MEM_OFFLINE: + clear_node_memory_tier(arg->status_change_nid); + break; + case MEM_ONLINE: + init_node_memory_tier(arg->status_change_nid); + break; + } + + return notifier_from_errno(0); +} + static int __init memory_tier_init(void) { struct memory_tier *memtier; @@ -97,6 +179,7 @@ static int __init memory_tier_init(void) __func__, PTR_ERR(memtier)); mutex_unlock(&memory_tier_lock); + hotplug_memory_notifier(memtier_hotplug_callback, MEMTIER_HOTPLUG_PRIO); return 0; } subsys_initcall(memory_tier_init); -- 2.37.1