From: Srinivasulu Thanneeru <sthanneeru.opensrc@xxxxxxxxxx> This patch introduces a new attribute called adistance_offset to the node_devices structure. Using adistance_offset, a node can be migrated to a targeted tier. Target tier's adjacent distance(adistance) is calculated by taking the adistance offset into account. Signed-off-by: Srinivasulu Thanneeru <sthanneeru.opensrc@xxxxxxxxxx> Signed-off-by: Ravi Jonnalagadda <ravis.opensrc@xxxxxxxxxx> --- drivers/base/node.c | 45 ++++++++++++++++++++++++++++++++++++ include/linux/memory-tiers.h | 6 +++++ include/linux/node.h | 1 + mm/memory-tiers.c | 14 +++++++++++ 4 files changed, 66 insertions(+) diff --git a/drivers/base/node.c b/drivers/base/node.c index 493d533f8375..1e63c692977b 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,54 @@ static ssize_t node_read_distance(struct device *dev, } static DEVICE_ATTR(distance, 0444, node_read_distance, NULL); +static ssize_t adistance_offset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int nid = dev->id; + int len = 0; + + /* + * buf is currently PAGE_SIZE in length and each node needs 4 chars + * at the most (distance + space or newline). + */ + BUILD_BUG_ON(MAX_NUMNODES * 4 > PAGE_SIZE); + + len += sysfs_emit(buf, "%d\n", node_devices[nid]->adistance_offset); + return len; +} + +static ssize_t adistance_offset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int nid = dev->id; + int value, ret; + + ret = kstrtoint(buf, 0, &value); + + if (ret) + return ret; + if (node_devices[nid]->adistance_offset == value) + return size; + /* + * Request from a node to migrate to a memtier with negative + * adistance is not valid. + */ + ret = get_target_memtier_adistance(nid, value); + if (ret < 0) + return -EINVAL; + + node_devices[nid]->adistance_offset = value; + return size; +} +static DEVICE_ATTR_RW(adistance_offset); + static struct attribute *node_dev_attrs[] = { &dev_attr_meminfo.attr, &dev_attr_numastat.attr, &dev_attr_distance.attr, &dev_attr_vmstat.attr, + &dev_attr_adistance_offset.attr, NULL }; @@ -883,6 +927,7 @@ int __register_one_node(int nid) INIT_LIST_HEAD(&node_devices[nid]->access_list); node_init_caches(nid); + node_devices[nid]->adistance_offset = 0; return error; } diff --git a/include/linux/memory-tiers.h b/include/linux/memory-tiers.h index 1e39d27bee41..ff4e7136ab40 100644 --- a/include/linux/memory-tiers.h +++ b/include/linux/memory-tiers.h @@ -48,6 +48,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_target_memtier_adistance(int node, int adistance_offset); #ifdef CONFIG_MIGRATION int next_demotion_node(int node); void node_get_allowed_targets(pg_data_t *pgdat, nodemask_t *targets); @@ -136,5 +137,10 @@ static inline int mt_perf_to_adistance(struct node_hmem_attrs *perf, int *adist) { return -EIO; } + +static int get_target_memtier_adistance(int node, int adistance_offset) +{ + return 0; +} #endif /* CONFIG_NUMA */ #endif /* _LINUX_MEMORY_TIERS_H */ diff --git a/include/linux/node.h b/include/linux/node.h index 427a5975cf40..fd0f4f3177f8 100644 --- a/include/linux/node.h +++ b/include/linux/node.h @@ -83,6 +83,7 @@ static inline void node_set_perf_attrs(unsigned int nid, struct node { struct device dev; struct list_head access_list; + int adistance_offset; #ifdef CONFIG_HMEM_REPORTING struct list_head cache_attrs; struct device *cache_dev; diff --git a/mm/memory-tiers.c b/mm/memory-tiers.c index 8d5291add2bc..a40d4d4383d7 100644 --- a/mm/memory-tiers.c +++ b/mm/memory-tiers.c @@ -167,6 +167,20 @@ static const struct attribute_group *memtier_dev_groups[] = { NULL }; +int get_target_memtier_adistance(int node, int adistance_offset) +{ + struct memory_dev_type *memtype; + int node_adistance; + + memtype = node_memory_types[node].memtype; + /* + * Calculate the targeted memtier abstract distance from + * memtype adistance and node adistance offset. + */ + node_adistance = memtype->adistance + adistance_offset; + return node_adistance; +} + static struct memory_tier *find_create_memory_tier(struct memory_dev_type *memtype) { int ret; -- 2.25.1