mm/page_owner: print memcg information
authorWaiman Long <longman@redhat.com>
Fri, 25 Mar 2022 01:09:08 +0000 (18:09 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 Mar 2022 02:06:44 +0000 (19:06 -0700)
It was found that a number of offline memcgs were not freed because they
were pinned by some charged pages that were present.  Even "echo 1 >
/proc/sys/vm/drop_caches" wasn't able to free those pages.  These
offline but not freed memcgs tend to increase in number over time with
the side effect that percpu memory consumption as shown in /proc/meminfo
also increases over time.

In order to find out more information about those pages that pin offline
memcgs, the page_owner feature is extended to print memory cgroup
information especially whether the cgroup is offline or not.  RCU read
lock is taken when memcg is being accessed to make sure that it won't be
freed.

Link: https://lkml.kernel.org/r/20220202203036.744010-4-longman@redhat.com
Signed-off-by: Waiman Long <longman@redhat.com>
Acked-by: David Rientjes <rientjes@google.com>
Acked-by: Roman Gushchin <guro@fb.com>
Acked-by: Rafael Aquini <aquini@redhat.com>
Acked-by: Mike Rapoport <rppt@linux.ibm.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Ira Weiny <ira.weiny@intel.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Sergey Senozhatsky <senozhatsky@chromium.org>
Cc: Steven Rostedt (Google) <rostedt@goodmis.org>
Cc: Vladimir Davydov <vdavydov.dev@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
mm/page_owner.c

index 28dac73e0542dcb4bff051b0646063dd9fa07bd1..f7820357e4d4c7a1861cf95ea38693d0d449dbc2 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/migrate.h>
 #include <linux/stackdepot.h>
 #include <linux/seq_file.h>
+#include <linux/memcontrol.h>
 #include <linux/sched/clock.h>
 
 #include "internal.h"
@@ -325,6 +326,45 @@ void pagetypeinfo_showmixedcount_print(struct seq_file *m,
        seq_putc(m, '\n');
 }
 
+/*
+ * Looking for memcg information and print it out
+ */
+static inline int print_page_owner_memcg(char *kbuf, size_t count, int ret,
+                                        struct page *page)
+{
+#ifdef CONFIG_MEMCG
+       unsigned long memcg_data;
+       struct mem_cgroup *memcg;
+       bool online;
+       char name[80];
+
+       rcu_read_lock();
+       memcg_data = READ_ONCE(page->memcg_data);
+       if (!memcg_data)
+               goto out_unlock;
+
+       if (memcg_data & MEMCG_DATA_OBJCGS)
+               ret += scnprintf(kbuf + ret, count - ret,
+                               "Slab cache page\n");
+
+       memcg = page_memcg_check(page);
+       if (!memcg)
+               goto out_unlock;
+
+       online = (memcg->css.flags & CSS_ONLINE);
+       cgroup_name(memcg->css.cgroup, name, sizeof(name));
+       ret += scnprintf(kbuf + ret, count - ret,
+                       "Charged %sto %smemcg %s\n",
+                       PageMemcgKmem(page) ? "(via objcg) " : "",
+                       online ? "" : "offline ",
+                       name);
+out_unlock:
+       rcu_read_unlock();
+#endif /* CONFIG_MEMCG */
+
+       return ret;
+}
+
 static ssize_t
 print_page_owner(char __user *buf, size_t count, unsigned long pfn,
                struct page *page, struct page_owner *page_owner,
@@ -365,6 +405,8 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn,
                        migrate_reason_names[page_owner->last_migrate_reason]);
        }
 
+       ret = print_page_owner_memcg(kbuf, count, ret, page);
+
        ret += snprintf(kbuf + ret, count - ret, "\n");
        if (ret >= count)
                goto err;