From: Srinivasulu Thanneeru <sthanneeru.opensrc@xxxxxxxxxx> This patch introduces a new memtier_override sysfs. memtier_override is the current memory tier of the node. To migrate, replace it with the id of the desired memory tier. adistance_offset is the required offset from memtype to move the node to the target memory tier(i.e, memtier_override). Signed-off-by: Srinivasulu Thanneeru <sthanneeru.opensrc@xxxxxxxxxx> Signed-off-by: Ravi Jonnalagadda <ravis.opensrc@xxxxxxxxxx> --- Documentation/ABI/stable/sysfs-devices-node | 7 ++++ drivers/base/node.c | 41 +++++++++++++++++++++ include/linux/memory-tiers.h | 6 +++ include/linux/node.h | 6 +++ mm/memory-tiers.c | 19 +++++++++- 5 files changed, 78 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/stable/sysfs-devices-node b/Documentation/ABI/stable/sysfs-devices-node index 402af4b2b905..447a599cc536 100644 --- a/Documentation/ABI/stable/sysfs-devices-node +++ b/Documentation/ABI/stable/sysfs-devices-node @@ -70,6 +70,13 @@ Description: Distance between the node and all the other nodes in the system. +What: /sys/devices/system/node/nodeX/memtier_overwrite +Date: December 2023 +Contact: Srinivasulu Thanneeru <sthanneeru.opensrc@xxxxxxxxxx> +Description: + The current memory tier of the node. + To migrate, replace it with the id of the desired memory tier. + What: /sys/devices/system/node/nodeX/vmstat Date: October 2002 Contact: Linux Memory Management list <linux-mm@xxxxxxxxx> diff --git a/drivers/base/node.c b/drivers/base/node.c index 493d533f8375..788176b3585a 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -7,6 +7,7 @@ #include <linux/init.h> #include <linux/mm.h> #include <linux/memory.h> +#include <linux/memory-tiers.h> #include <linux/vmstat.h> #include <linux/notifier.h> #include <linux/node.h> @@ -569,11 +570,49 @@ static ssize_t node_read_distance(struct device *dev, } static DEVICE_ATTR(distance, 0444, node_read_distance, NULL); +static ssize_t memtier_override_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int nid = dev->id; + int len = 0; + + len += sysfs_emit(buf, "memory_tier%d\n", node_devices[nid]->memtier); + return len; +} + +static ssize_t memtier_override_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int nid = dev->id; + int ret, memtier; + + ret = kstrtoint(buf, 0, &memtier); + + if (ret) + return ret; + if (memtier < 0 || memtier > MAX_MEMTIERID) + return -EINVAL; + if (node_devices[nid]->memtier == memtier) + return size; + ret = get_memtier_adistance_offset(nid, memtier); + node_devices[nid]->adistance_offset = ret; + + return size; +} +static DEVICE_ATTR_RW(memtier_override); + +void set_node_memtierid(int node, int memtierid) +{ + node_devices[node]->memtier = memtierid; +} + static struct attribute *node_dev_attrs[] = { &dev_attr_meminfo.attr, &dev_attr_numastat.attr, &dev_attr_distance.attr, &dev_attr_vmstat.attr, + &dev_attr_memtier_override.attr, NULL }; @@ -883,6 +922,8 @@ int __register_one_node(int nid) INIT_LIST_HEAD(&node_devices[nid]->access_list); node_init_caches(nid); + node_devices[nid]->memtier = 0; + node_devices[nid]->adistance_offset = 0; return error; } diff --git a/include/linux/memory-tiers.h b/include/linux/memory-tiers.h index 1e39d27bee41..0dba8027e785 100644 --- a/include/linux/memory-tiers.h +++ b/include/linux/memory-tiers.h @@ -20,6 +20,11 @@ */ #define MEMTIER_ADISTANCE_DRAM ((4 * MEMTIER_CHUNK_SIZE) + (MEMTIER_CHUNK_SIZE >> 1)) +/* + * Memory tier id is derived from abstract distance(signed 32bits) + */ +#define MAX_MEMTIERID (0xFFFFFFFF >> (MEMTIER_CHUNK_BITS + 1)) + struct memory_tier; struct memory_dev_type { /* list of memory types that are part of same tier as this type */ @@ -48,6 +53,7 @@ int mt_calc_adistance(int node, int *adist); int mt_set_default_dram_perf(int nid, struct node_hmem_attrs *perf, const char *source); int mt_perf_to_adistance(struct node_hmem_attrs *perf, int *adist); +int get_memtier_adistance_offset(int node, int memtier); #ifdef CONFIG_MIGRATION int next_demotion_node(int node); void node_get_allowed_targets(pg_data_t *pgdat, nodemask_t *targets); diff --git a/include/linux/node.h b/include/linux/node.h index 427a5975cf40..1c4f4be39db4 100644 --- a/include/linux/node.h +++ b/include/linux/node.h @@ -83,6 +83,8 @@ static inline void node_set_perf_attrs(unsigned int nid, struct node { struct device dev; struct list_head access_list; + int memtier; + int adistance_offset; #ifdef CONFIG_HMEM_REPORTING struct list_head cache_attrs; struct device *cache_dev; @@ -138,6 +140,7 @@ extern void unregister_memory_block_under_nodes(struct memory_block *mem_blk); extern int register_memory_node_under_compute_node(unsigned int mem_nid, unsigned int cpu_nid, unsigned access); +extern void set_node_memtierid(int node, int memtierid); #else static inline void node_dev_init(void) { @@ -165,6 +168,9 @@ static inline int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) static inline void unregister_memory_block_under_nodes(struct memory_block *mem_blk) { } +static inline void set_node_memtierid(int node, int memtierid) +{ +} #endif #define to_node(device) container_of(device, struct node, dev) diff --git a/mm/memory-tiers.c b/mm/memory-tiers.c index 8d5291add2bc..31ed3c577836 100644 --- a/mm/memory-tiers.c +++ b/mm/memory-tiers.c @@ -167,6 +167,21 @@ static const struct attribute_group *memtier_dev_groups[] = { NULL }; +int get_memtier_adistance_offset(int node, int memtier) +{ + struct memory_dev_type *memtype; + int adistance_offset; + + memtype = node_memory_types[node].memtype; + /* + * Calculate the adistance offset required from memtype + * to move node to target memory tier. + */ + adistance_offset = (memtier << MEMTIER_CHUNK_BITS) - + memtype->adistance; + return adistance_offset; +} + static struct memory_tier *find_create_memory_tier(struct memory_dev_type *memtype) { int ret; @@ -497,8 +512,10 @@ static struct memory_tier *set_node_memory_tier(int node) memtype = node_memory_types[node].memtype; node_set(node, memtype->nodes); memtier = find_create_memory_tier(memtype); - if (!IS_ERR(memtier)) + if (!IS_ERR(memtier)) { rcu_assign_pointer(pgdat->memtier, memtier); + set_node_memtierid(node, memtier->dev.id); + } return memtier; } -- 2.25.1