[RFC PATCH 1/8] mm/memory-tiers: add node_to_tier_id and tier_id_to_nodemask

From: liuqiqi

Date: Mon Aug 17 2026 - 22:35:36 EST


From: Qiqi Liu <liuqiqi@xxxxxxxxxx>

Add two helpers to bridge NUMA nodes and memory tiers:

- node_to_tier_id(node):
Returns the tier ID for a given node, derived from its abstract
distance (adistance_start >> MEMTIER_CHUNK_BITS). The lookup is
lockless and low-cost, safe from any context including the memcg
charge fast path. Returns -1 if the node is not associated with
a memory tier.

- tier_id_to_nodemask(tier_id, nodes):
Resolves the nodemask belonging to a given tier. This operation
is sleepable (takes the tier mutex) and must not be called from
contexts that disallow blocking, such as the memcg charge fast
path. Suitable for reclaim and other sleepable contexts.

These helpers will be used by subsequent patches to implement per-tier
memcg accounting and reclaim.

Signed-off-by: Qiqi Liu <liuqiqi@xxxxxxxxxx>
---
include/linux/memory-tiers.h | 12 ++++++++
mm/memory-tiers.c | 58 ++++++++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+)

diff --git a/include/linux/memory-tiers.h b/include/linux/memory-tiers.h
index 7999c58629ee..7277a08b97c9 100644
--- a/include/linux/memory-tiers.h
+++ b/include/linux/memory-tiers.h
@@ -52,6 +52,8 @@ int mt_perf_to_adistance(struct access_coordinate *perf, int *adist);
struct memory_dev_type *mt_find_alloc_memory_type(int adist,
struct list_head *memory_types);
void mt_put_memory_types(struct list_head *memory_types);
+int node_to_tier_id(int node);
+int tier_id_to_nodemask(int tier_id, nodemask_t *nodes);
#ifdef CONFIG_NUMA_MIGRATION
int next_demotion_node(int node, const nodemask_t *allowed_mask);
void node_get_allowed_targets(pg_data_t *pgdat, nodemask_t *targets);
@@ -151,5 +153,15 @@ static inline struct memory_dev_type *mt_find_alloc_memory_type(int adist,
static inline void mt_put_memory_types(struct list_head *memory_types)
{
}
+
+static inline int node_to_tier_id(int node)
+{
+ return -1;
+}
+
+static inline int tier_id_to_nodemask(int tier_id, nodemask_t *nodes)
+{
+ return -ENOENT;
+}
#endif /* CONFIG_NUMA */
#endif /* _LINUX_MEMORY_TIERS_H */
diff --git a/mm/memory-tiers.c b/mm/memory-tiers.c
index 54851d8a195b..896d23ac7a01 100644
--- a/mm/memory-tiers.c
+++ b/mm/memory-tiers.c
@@ -156,6 +156,64 @@ static __always_inline nodemask_t get_memtier_nodemask(struct memory_tier *memti
return nodes;
}

+/**
+ * node_to_tier_id() - Get the memory tier id of a node
+ * @node: The node to look up
+ *
+ * Cheap, lockless lookup safe for the memcg charge hot path. The tier id is
+ * the memory tier's device id, i.e. adistance_start >> MEMTIER_CHUNK_BITS.
+ *
+ * Return: the tier id, or -1 if the node has no memory tier.
+ */
+int node_to_tier_id(int node)
+{
+ pg_data_t *pgdat;
+ struct memory_tier *memtier;
+ int tier_id = -1;
+
+ pgdat = NODE_DATA(node);
+ if (!pgdat)
+ return -1;
+
+ rcu_read_lock();
+ memtier = rcu_dereference(pgdat->memtier);
+ if (memtier)
+ tier_id = memtier->dev.id;
+ rcu_read_unlock();
+ return tier_id;
+}
+EXPORT_SYMBOL_GPL(node_to_tier_id);
+
+/**
+ * tier_id_to_nodemask() - Get the set of nodes belonging to a memory tier
+ * @tier_id: The tier id to look up
+ * @nodes: Output nodemask, cleared and filled on success
+ *
+ * Takes the memory tier mutex, so callers must be in a sleepable context.
+ * The memcg charge path calls this only after its gfp-allow-blocking check
+ * (i.e., only when about to reclaim), never on the charge fast path.
+ *
+ * Return: 0 on success, -ENOENT if no tier with the given id exists.
+ */
+int tier_id_to_nodemask(int tier_id, nodemask_t *nodes)
+{
+ struct memory_tier *memtier;
+ int ret = -ENOENT;
+
+ nodes_clear(*nodes);
+ mutex_lock(&memory_tier_lock);
+ list_for_each_entry(memtier, &memory_tiers, list) {
+ if (memtier->dev.id == tier_id) {
+ *nodes = get_memtier_nodemask(memtier);
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&memory_tier_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tier_id_to_nodemask);
+
static void memory_tier_device_release(struct device *dev)
{
struct memory_tier *tier = to_memory_tier(dev);
--
2.43.0