Skip to content

Commit

Permalink
mm/demotion: add pg_data_t member to track node memory tier details
Browse files Browse the repository at this point in the history
Also update different helpes to use NODE_DATA()->memtier.  Since node
specific memtier can change based on the reassignment of NUMA node to a
different memory tiers, accessing NODE_DATA()->memtier needs to happen
under an rcu read lock or memory_tier_lock.

Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Aneesh Kumar K.V <[email protected]>
Reviewed-by: "Huang, Ying" <[email protected]>
Acked-by: Wei Xu <[email protected]>
Cc: Alistair Popple <[email protected]>
Cc: Bharata B Rao <[email protected]>
Cc: Dan Williams <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: Davidlohr Bueso <[email protected]>
Cc: Hesham Almatary <[email protected]>
Cc: Jagdish Gediya <[email protected]>
Cc: Johannes Weiner <[email protected]>
Cc: Jonathan Cameron <[email protected]>
Cc: Michal Hocko <[email protected]>
Cc: Tim Chen <[email protected]>
Cc: Yang Shi <[email protected]>
Cc: SeongJae Park <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
  • Loading branch information
kvaneesh authored and akpm00 committed Sep 27, 2022
1 parent 6c542ab commit 7766cf7
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 5 deletions.
3 changes: 3 additions & 0 deletions include/linux/mmzone.h
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,9 @@ typedef struct pglist_data {
/* Per-node vmstats */
struct per_cpu_nodestat __percpu *per_cpu_nodestats;
atomic_long_t vm_stat[NR_VM_NODE_STAT_ITEMS];
#ifdef CONFIG_NUMA
struct memory_tier __rcu *memtier;
#endif
} pg_data_t;

#define node_present_pages(nid) (NODE_DATA(nid)->node_present_pages)
Expand Down
40 changes: 35 additions & 5 deletions mm/memory-tiers.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <linux/sysfs.h>
#include <linux/kobject.h>
#include <linux/memory.h>
#include <linux/mmzone.h>
#include <linux/memory-tiers.h>

#include "internal.h"
Expand Down Expand Up @@ -141,12 +142,18 @@ static struct memory_tier *find_create_memory_tier(struct memory_dev_type *memty

static struct memory_tier *__node_get_memory_tier(int node)
{
struct memory_dev_type *memtype;
pg_data_t *pgdat;

memtype = node_memory_types[node];
if (memtype && node_isset(node, memtype->nodes))
return memtype->memtier;
return NULL;
pgdat = NODE_DATA(node);
if (!pgdat)
return NULL;
/*
* Since we hold memory_tier_lock, we can avoid
* RCU read locks when accessing the details. No
* parallel updates are possible here.
*/
return rcu_dereference_check(pgdat->memtier,
lockdep_is_held(&memory_tier_lock));
}

#ifdef CONFIG_MIGRATION
Expand Down Expand Up @@ -309,6 +316,8 @@ static struct memory_tier *set_node_memory_tier(int node)
{
struct memory_tier *memtier;
struct memory_dev_type *memtype;
pg_data_t *pgdat = NODE_DATA(node);


lockdep_assert_held_once(&memory_tier_lock);

Expand All @@ -320,24 +329,45 @@ 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))
rcu_assign_pointer(pgdat->memtier, memtier);
return memtier;
}

static void destroy_memory_tier(struct memory_tier *memtier)
{
list_del(&memtier->list);
/*
* synchronize_rcu in clear_node_memory_tier makes sure
* we don't have rcu access to this memory tier.
*/
kfree(memtier);
}

static bool clear_node_memory_tier(int node)
{
bool cleared = false;
pg_data_t *pgdat;
struct memory_tier *memtier;

pgdat = NODE_DATA(node);
if (!pgdat)
return false;

/*
* Make sure that anybody looking at NODE_DATA who finds
* a valid memtier finds memory_dev_types with nodes still
* linked to the memtier. We achieve this by waiting for
* rcu read section to finish using synchronize_rcu.
* This also enables us to free the destroyed memory tier
* with kfree instead of kfree_rcu
*/
memtier = __node_get_memory_tier(node);
if (memtier) {
struct memory_dev_type *memtype;

rcu_assign_pointer(pgdat->memtier, NULL);
synchronize_rcu();
memtype = node_memory_types[node].memtype;
node_clear(node, memtype->nodes);
if (nodes_empty(memtype->nodes)) {
Expand Down

0 comments on commit 7766cf7

Please sign in to comment.