[rh7,v3,7/7] ms/mm: workingset: make shadow node shrinker memcg aware

Submitted by Andrey Ryabinin on Feb. 27, 2019, 4:40 p.m.

Details

Message ID 20190227164005.26009-7-aryabinin@virtuozzo.com
State New
Series "Series without cover letter"
Headers show

Commit Message

Andrey Ryabinin Feb. 27, 2019, 4:40 p.m.
From: Vladimir Davydov <vdavydov@virtuozzo.com>

Workingset code was recently made memcg aware, but shadow node shrinker
is still global.  As a result, one small cgroup can consume all memory
available for shadow nodes, possibly hurting other cgroups by reclaiming
their shadow nodes, even though reclaim distances stored in its shadow
nodes have no effect.  To avoid this, we need to make shadow node
shrinker memcg aware.

Signed-off-by: Vladimir Davydov <vdavydov@virtuozzo.com>

Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

https://pmc.acronis.com/browse/VSTOR-19037
(cherry picked from commit 0a6b76dd23fa08c5fd7b68acdb55018a37afd4aa)
Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
---
 include/linux/memcontrol.h | 10 ++++++++++
 mm/memcontrol.c            |  2 +-
 mm/workingset.c            | 24 +++++++++++++++---------
 3 files changed, 26 insertions(+), 10 deletions(-)

Patch hide | download patch | download mbox

diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 3e309ff5c3a7..575584dc1651 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -138,6 +138,9 @@  extern void mem_cgroup_note_oom_kill(struct mem_cgroup *memcg,
 extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
 					struct task_struct *p);
 
+unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
+					   int nid, unsigned int lru_mask);
+
 static inline void mem_cgroup_oom_enable(void)
 {
 	WARN_ON(current->memcg_oom.may_oom);
@@ -426,6 +429,13 @@  static inline unsigned long mem_cgroup_overdraft(struct mem_cgroup *memcg)
 	return 0;
 }
 
+static inline unsigned long
+mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
+			     int nid, unsigned int lru_mask)
+{
+	return 0;
+}
+
 static inline void
 mem_cgroup_note_oom_kill(struct mem_cgroup *memcg, struct task_struct *task)
 {
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 2985022c4f2a..391ccf8e8699 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1305,7 +1305,7 @@  mem_cgroup_zone_nr_lru_pages(struct mem_cgroup *memcg, int nid, int zid,
 	return ret;
 }
 
-static unsigned long
+unsigned long
 mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
 			int nid, unsigned int lru_mask)
 {
diff --git a/mm/workingset.c b/mm/workingset.c
index 485bbd84b230..1168cc122828 100644
--- a/mm/workingset.c
+++ b/mm/workingset.c
@@ -208,7 +208,7 @@  static void unpack_shadow(void *shadow, int *memcgidp, struct zone **zonep,
  */
 void *workingset_eviction(struct address_space *mapping, struct page *page)
 {
-	struct mem_cgroup *memcg;
+	struct mem_cgroup *memcg = NULL;
 	struct zone *zone = page_zone(page);
 	struct page_cgroup *pc;
 	unsigned long eviction;
@@ -219,11 +219,13 @@  void *workingset_eviction(struct address_space *mapping, struct page *page)
 	VM_BUG_ON_PAGE(page_count(page), page);
 	VM_BUG_ON_PAGE(!PageLocked(page), page);
 
-	pc = lookup_page_cgroup(page);
-	if (PageCgroupUsed(pc))
-		memcg = pc->mem_cgroup;
-	else
-		memcg = root_mem_cgroup;
+	if (!mem_cgroup_disabled()) {
+		pc = lookup_page_cgroup(page);
+		if (PageCgroupUsed(pc))
+			memcg = pc->mem_cgroup;
+		else
+			memcg = root_mem_cgroup;
+	}
 	lruvec = mem_cgroup_zone_lruvec(zone, memcg);
 	eviction = atomic_long_inc_return(&lruvec->inactive_age);
 	return pack_shadow(mem_cgroup_id(memcg), zone, eviction);
@@ -384,8 +386,12 @@  static unsigned long count_shadow_nodes(struct shrinker *shrinker,
 	 *
 	 * PAGE_SIZE / radix_tree_nodes / node_entries * 8 / PAGE_SIZE
 	 */
-	cache = node_page_state(sc->nid, NR_ACTIVE_FILE) +
-		node_page_state(sc->nid, NR_INACTIVE_FILE);
+	if (memcg_kmem_enabled())
+		cache = mem_cgroup_node_nr_lru_pages(sc->memcg, sc->nid,
+						     LRU_ALL_FILE);
+	else
+		cache = node_page_state(sc->nid, NR_ACTIVE_FILE) +
+			node_page_state(sc->nid, NR_INACTIVE_FILE);
 
 	max_nodes =  cache >> (RADIX_TREE_MAP_SHIFT - 3);
 
@@ -483,7 +489,7 @@  static struct shrinker workingset_shadow_shrinker = {
 	.count_objects = count_shadow_nodes,
 	.scan_objects = scan_shadow_nodes,
 	.seeks = DEFAULT_SEEKS,
-	.flags = SHRINKER_NUMA_AWARE,
+	.flags = SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE,
 };
 
 /*