]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.5-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 30 Mar 2020 13:21:21 +0000 (15:21 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 30 Mar 2020 13:21:21 +0000 (15:21 +0200)
added patches:
mm-fork-fix-kernel_stack-memcg-stats-for-various-stack-implementations.patch

queue-5.5/mm-fork-fix-kernel_stack-memcg-stats-for-various-stack-implementations.patch [new file with mode: 0644]
queue-5.5/series

diff --git a/queue-5.5/mm-fork-fix-kernel_stack-memcg-stats-for-various-stack-implementations.patch b/queue-5.5/mm-fork-fix-kernel_stack-memcg-stats-for-various-stack-implementations.patch
new file mode 100644 (file)
index 0000000..139e24e
--- /dev/null
@@ -0,0 +1,166 @@
+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;
index 9d4c14ba6e57a732fda52461a8a39c1459f2dad2..9f067439184cb3fab57b6138a401261f9fe3e21c 100644 (file)
@@ -111,3 +111,4 @@ mac80211-mark-station-unauthorized-before-key-removal.patch
 mm-swapfile.c-move-inode_lock-out-of-claim_swapfile.patch
 drivers-base-memory.c-indicate-all-memory-blocks-as-removable.patch
 mm-sparse-fix-kernel-crash-with-pfn_section_valid-check.patch
+mm-fork-fix-kernel_stack-memcg-stats-for-various-stack-implementations.patch