From: Bingfang Guo mem_cgroup_from_private_id() looks up the objcg that owns the id and returns the objcg's current memcg. After reparenting, that memcg can differ from the one the id originally belonged to. Callers such as the list lru and workingset refault code expect to get back exactly the memcg referred to by the memcgid, so check that the returned memcg still owns the id and return NULL otherwise. In this case, make list_lru just skip and workingset tests use the root (as the comments said in workingset.c:460). Signed-off-by: Bingfang Guo --- mm/list_lru.c | 2 +- mm/memcontrol.c | 9 ++++++++- mm/workingset.c | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mm/list_lru.c b/mm/list_lru.c index 36662d02ff963..bc956267f6835 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -428,7 +428,7 @@ unsigned long list_lru_walk_node(struct list_lru *lru, int nid, xa_for_each(&lru->xa, index, mlru) { rcu_read_lock(); memcg = mem_cgroup_from_private_id(index); - if (!mem_cgroup_tryget(memcg)) { + if (!memcg || !mem_cgroup_tryget(memcg)) { rcu_read_unlock(); continue; } diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 38d2b00657a7a..84dcab3acb8a2 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4112,17 +4112,24 @@ struct mem_cgroup *mem_cgroup_private_id_get_online(struct mem_cgroup *memcg, un * @id: the memcg id to look up * * Caller must hold rcu_read_lock(). + * + * @return: the memcg, or NULL if the memcg is already reparented. */ struct mem_cgroup *mem_cgroup_from_private_id(unsigned short id) { struct obj_cgroup *objcg; + struct mem_cgroup *memcg; WARN_ON_ONCE(!rcu_read_lock_held()); objcg = xa_load(&mem_cgroup_private_ids, id); if (!objcg) return NULL; - return obj_cgroup_memcg(objcg); + memcg = obj_cgroup_memcg(objcg); + if (mem_cgroup_private_id(memcg) != id) + return NULL; + + return memcg; } struct mem_cgroup *mem_cgroup_get_from_id(u64 id) diff --git a/mm/workingset.c b/mm/workingset.c index 7ac2b88c80ae5..4e9b7b163c01e 100644 --- a/mm/workingset.c +++ b/mm/workingset.c @@ -470,7 +470,7 @@ bool workingset_test_recent(void *shadow, bool file, bool *workingset, * configurations instead. */ eviction_memcg = mem_cgroup_from_private_id(memcgid); - if (!mem_cgroup_tryget(eviction_memcg)) + if (eviction_memcg && !mem_cgroup_tryget(eviction_memcg)) eviction_memcg = NULL; rcu_read_unlock(); -- 2.43.7