--- /dev/null
+From 8380ce479010f2f779587b462a9b4681934297c3 Mon Sep 17 00:00:00 2001
+From: Roman Gushchin <guro@fb.com>
+Date: Sat, 28 Mar 2020 19:17:25 -0700
+Subject: mm: fork: fix kernel_stack memcg stats for various stack implementations
+
+From: Roman Gushchin <guro@fb.com>
+
+commit 8380ce479010f2f779587b462a9b4681934297c3 upstream.
+
+Depending on CONFIG_VMAP_STACK and the THREAD_SIZE / PAGE_SIZE ratio the
+space for task stacks can be allocated using __vmalloc_node_range(),
+alloc_pages_node() and kmem_cache_alloc_node().
+
+In the first and the second cases page->mem_cgroup pointer is set, but
+in the third it's not: memcg membership of a slab page should be
+determined using the memcg_from_slab_page() function, which looks at
+page->slab_cache->memcg_params.memcg . In this case, using
+mod_memcg_page_state() (as in account_kernel_stack()) is incorrect:
+page->mem_cgroup pointer is NULL even for pages charged to a non-root
+memory cgroup.
+
+It can lead to kernel_stack per-memcg counters permanently showing 0 on
+some architectures (depending on the configuration).
+
+In order to fix it, let's introduce a mod_memcg_obj_state() helper,
+which takes a pointer to a kernel object as a first argument, uses
+mem_cgroup_from_obj() to get a RCU-protected memcg pointer and calls
+mod_memcg_state(). It allows to handle all possible configurations
+(CONFIG_VMAP_STACK and various THREAD_SIZE/PAGE_SIZE values) without
+spilling any memcg/kmem specifics into fork.c .
+
+Note: This is a special version of the patch created for stable
+backports. It contains code from the following two patches:
+ - mm: memcg/slab: introduce mem_cgroup_from_obj()
+ - mm: fork: fix kernel_stack memcg stats for various stack implementations
+
+[guro@fb.com: introduce mem_cgroup_from_obj()]
+ Link: http://lkml.kernel.org/r/20200324004221.GA36662@carbon.dhcp.thefacebook.com
+Fixes: 4d96ba353075 ("mm: memcg/slab: stop setting page->mem_cgroup pointer for slab pages")
+Signed-off-by: Roman Gushchin <guro@fb.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Reviewed-by: Shakeel Butt <shakeelb@google.com>
+Acked-by: Johannes Weiner <hannes@cmpxchg.org>
+Cc: Michal Hocko <mhocko@kernel.org>
+Cc: Bharata B Rao <bharata@linux.ibm.com>
+Cc: Shakeel Butt <shakeelb@google.com>
+Cc: <stable@vger.kernel.org>
+Link: http://lkml.kernel.org/r/20200303233550.251375-1-guro@fb.com
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/linux/memcontrol.h | 12 ++++++++++++
+ kernel/fork.c | 4 ++--
+ mm/memcontrol.c | 38 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 52 insertions(+), 2 deletions(-)
+
+--- a/include/linux/memcontrol.h
++++ b/include/linux/memcontrol.h
+@@ -695,6 +695,7 @@ static inline unsigned long lruvec_page_
+ void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
+ int val);
+ void __mod_lruvec_slab_state(void *p, enum node_stat_item idx, int val);
++void mod_memcg_obj_state(void *p, int idx, int val);
+
+ static inline void mod_lruvec_state(struct lruvec *lruvec,
+ enum node_stat_item idx, int val)
+@@ -1123,6 +1124,10 @@ static inline void __mod_lruvec_slab_sta
+ __mod_node_page_state(page_pgdat(page), idx, val);
+ }
+
++static inline void mod_memcg_obj_state(void *p, int idx, int val)
++{
++}
++
+ static inline
+ unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
+ gfp_t gfp_mask,
+@@ -1427,6 +1432,8 @@ static inline int memcg_cache_id(struct
+ return memcg ? memcg->kmemcg_id : -1;
+ }
+
++struct mem_cgroup *mem_cgroup_from_obj(void *p);
++
+ #else
+
+ static inline int memcg_kmem_charge(struct page *page, gfp_t gfp, int order)
+@@ -1468,6 +1475,11 @@ static inline void memcg_put_cache_ids(v
+ {
+ }
+
++static inline struct mem_cgroup *mem_cgroup_from_obj(void *p)
++{
++ return NULL;
++}
++
+ #endif /* CONFIG_MEMCG_KMEM */
+
+ #endif /* _LINUX_MEMCONTROL_H */
+--- a/kernel/fork.c
++++ b/kernel/fork.c
+@@ -397,8 +397,8 @@ static void account_kernel_stack(struct
+ mod_zone_page_state(page_zone(first_page), NR_KERNEL_STACK_KB,
+ THREAD_SIZE / 1024 * account);
+
+- mod_memcg_page_state(first_page, MEMCG_KERNEL_STACK_KB,
+- account * (THREAD_SIZE / 1024));
++ mod_memcg_obj_state(stack, MEMCG_KERNEL_STACK_KB,
++ account * (THREAD_SIZE / 1024));
+ }
+ }
+
+--- a/mm/memcontrol.c
++++ b/mm/memcontrol.c
+@@ -777,6 +777,17 @@ void __mod_lruvec_slab_state(void *p, en
+ rcu_read_unlock();
+ }
+
++void mod_memcg_obj_state(void *p, int idx, int val)
++{
++ struct mem_cgroup *memcg;
++
++ rcu_read_lock();
++ memcg = mem_cgroup_from_obj(p);
++ if (memcg)
++ mod_memcg_state(memcg, idx, val);
++ rcu_read_unlock();
++}
++
+ /**
+ * __count_memcg_events - account VM events in a cgroup
+ * @memcg: the memory cgroup
+@@ -2661,6 +2672,33 @@ static void commit_charge(struct page *p
+ }
+
+ #ifdef CONFIG_MEMCG_KMEM
++/*
++ * Returns a pointer to the memory cgroup to which the kernel object is charged.
++ *
++ * The caller must ensure the memcg lifetime, e.g. by taking rcu_read_lock(),
++ * cgroup_mutex, etc.
++ */
++struct mem_cgroup *mem_cgroup_from_obj(void *p)
++{
++ struct page *page;
++
++ if (mem_cgroup_disabled())
++ return NULL;
++
++ page = virt_to_head_page(p);
++
++ /*
++ * Slab pages don't have page->mem_cgroup set because corresponding
++ * kmem caches can be reparented during the lifetime. That's why
++ * memcg_from_slab_page() should be used instead.
++ */
++ if (PageSlab(page))
++ return memcg_from_slab_page(page);
++
++ /* All other pages use page->mem_cgroup */
++ return page->mem_cgroup;
++}
++
+ static int memcg_alloc_cache_id(void)
+ {
+ int id, size;