[RHEL7,COMMIT] mm/workingset: fix workingset_activation() with memcgroups enabled

Submitted by Konstantin Khorenko on May 21, 2019, 3:34 p.m.

Details

Message ID 201905211534.x4LFYujZ026102@finist-ce7.sw.ru
State New
Series "Series without cover letter"
Headers show

Commit Message

Konstantin Khorenko May 21, 2019, 3:34 p.m.
The commit is pushed to "branch-rh7-3.10.0-957.12.2.vz7.96.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-957.12.2.vz7.96.1
------>
commit d58a73c5986e66b0b9ee2ef6da500d3d43d92a45
Author: Andrey Ryabinin <aryabinin@virtuozzo.com>
Date:   Tue May 21 18:34:55 2019 +0300

    mm/workingset: fix workingset_activation() with memcgroups enabled
    
    workingset_activation() mistakenly does nothing when memory cgroups are
    enabled. Commit f6a8b015027e ("ms/mm: workingset: per-cgroup cache
    thrash detection") also changed mem_cgroup_begin_update_page_stat()
    to return memcg. But commit didn't make it right, memcg returns only
    when memcg is moving and NULL otherwise. Instead of mocking with
    mem_cgroup_begin_update_page_stat() obtain memcg from page in
    workingset_activation() directly.
    
    Fixes: f6a8b015027e ("ms/mm: workingset: per-cgroup cache thrash detection")
    Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
---
 include/linux/memcontrol.h | 10 +++++-----
 mm/memcontrol.c            |  9 +++++----
 mm/workingset.c            | 17 ++++++++++-------
 3 files changed, 20 insertions(+), 16 deletions(-)

Patch hide | download patch | download mbox

diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 575584dc1651..aa8cef097055 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -181,21 +181,21 @@  static inline void mem_cgroup_put(struct mem_cgroup *memcg)
 	css_put(mem_cgroup_css(memcg));
 }
 
-struct mem_cgroup *__mem_cgroup_begin_update_page_stat(struct page *page, bool *locked,
+void __mem_cgroup_begin_update_page_stat(struct page *page, bool *locked,
 					 unsigned long *flags);
 
 extern atomic_t memcg_moving;
 
-static inline struct mem_cgroup *mem_cgroup_begin_update_page_stat(struct page *page,
+static inline void mem_cgroup_begin_update_page_stat(struct page *page,
 					bool *locked, unsigned long *flags)
 {
 	if (mem_cgroup_disabled())
-		return NULL;
+		return;
+
 	rcu_read_lock();
 	*locked = false;
 	if (atomic_read(&memcg_moving))
-		return __mem_cgroup_begin_update_page_stat(page, locked, flags);
-	return NULL;
+		__mem_cgroup_begin_update_page_stat(page, locked, flags);
 }
 
 void __mem_cgroup_end_update_page_stat(struct page *page,
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index cd31ec167f13..91fb5ee896f5 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2703,7 +2703,7 @@  bool mem_cgroup_oom_synchronize(bool handle)
  * account and taking the move_lock in the slowpath.
  */
 
-struct mem_cgroup *__mem_cgroup_begin_update_page_stat(struct page *page,
+void __mem_cgroup_begin_update_page_stat(struct page *page,
 				bool *locked, unsigned long *flags)
 {
 	struct mem_cgroup *memcg;
@@ -2713,7 +2713,8 @@  struct mem_cgroup *__mem_cgroup_begin_update_page_stat(struct page *page,
 again:
 	memcg = pc->mem_cgroup;
 	if (unlikely(!memcg || !PageCgroupUsed(pc)))
-		return NULL;
+		return;
+
 	/*
 	 * If this memory cgroup is not under account moving, we don't
 	 * need to take move_lock_mem_cgroup(). Because we already hold
@@ -2721,7 +2722,7 @@  struct mem_cgroup *__mem_cgroup_begin_update_page_stat(struct page *page,
 	 * rcu_read_unlock() if mem_cgroup_stolen() == true.
 	 */
 	if (!mem_cgroup_stolen(memcg))
-		return NULL;
+		return;
 
 	move_lock_mem_cgroup(memcg, flags);
 	if (memcg != pc->mem_cgroup || !PageCgroupUsed(pc)) {
@@ -2729,7 +2730,7 @@  struct mem_cgroup *__mem_cgroup_begin_update_page_stat(struct page *page,
 		goto again;
 	}
 	*locked = true;
-	return memcg;
+	return;
 }
 
 void __mem_cgroup_end_update_page_stat(struct page *page, unsigned long *flags)
diff --git a/mm/workingset.c b/mm/workingset.c
index 1d7bdbf7a5d6..1598d2b02314 100644
--- a/mm/workingset.c
+++ b/mm/workingset.c
@@ -315,11 +315,17 @@  bool workingset_refault(void *shadow)
  */
 void workingset_activation(struct page *page)
 {
-	struct mem_cgroup *memcg;
+	struct mem_cgroup *memcg = NULL;
+	struct page_cgroup *pc;
 	struct lruvec *lruvec;
 	bool locked;
 	unsigned long flags;
 
+	mem_cgroup_begin_update_page_stat(page, &locked, &flags);
+	pc = lookup_page_cgroup(page);
+	if (likely(PageCgroupUsed(pc)))
+		memcg = pc->mem_cgroup;
+
 	/*
 	 * Filter non-memcg pages here, e.g. unmap can call
 	 * mark_page_accessed() on VDSO pages.
@@ -327,15 +333,12 @@  void workingset_activation(struct page *page)
 	 * XXX: See workingset_refault() - this should return
 	 * root_mem_cgroup even for !CONFIG_MEMCG.
 	 */
-	if (!mem_cgroup_disabled())
-		return;
-
-	memcg = mem_cgroup_begin_update_page_stat(page, &locked, &flags);
-	if (!memcg)
-		return;
+	if (!mem_cgroup_disabled() && !memcg)
+		goto out;
 
 	lruvec = mem_cgroup_zone_lruvec(page_zone(page), memcg);
 	atomic_long_inc(&lruvec->inactive_age);
+out:
 	mem_cgroup_end_update_page_stat(page, &locked, &flags);
 }