Commit 8965aa28 authored by Shakeel Butt's avatar Shakeel Butt Committed by Linus Torvalds

memcg: css_tryget_online cleanups

Currently multiple locations in memcg code, css_tryget_online() is being
used. However it doesn't matter whether the cgroup is online for the
callers. Online used to matter when we had reparenting on offlining and
we needed a way to prevent new ones from showing up.

The failure case for couple of these css_tryget_online usage is to
fallback to root_mem_cgroup which kind of make bypassing the memcg
limits possible for some workloads. For example creating an inotify
group in a subcontainer and then deleting that container after moving the
process to a different container will make all the event objects
allocated for that group to the root_mem_cgroup. So, using
css_tryget_online() is dangerous for such cases.

Two locations still use the online version. The swapin of offlined
memcg's pages and the memcg kmem cache creation. The kmem cache indeed
needs the online version as the kernel does the reparenting of memcg
kmem caches. For the swapin case, it has been left for later as the
fallback is not really that concerning.

With swap accounting enabled, if the memcg of the swapped out page is
not online then the memcg extracted from the given 'mm' will be charged
and if 'mm' is NULL then root memcg will be charged.  However I could
not find a code path where the given 'mm' will be NULL for swap-in
case.
Signed-off-by: default avatarShakeel Butt <shakeelb@google.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Acked-by: default avatarMichal Hocko <mhocko@suse.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Vladimir Davydov <vdavydov.dev@gmail.com>
Cc: Roman Gushchin <guro@fb.com>
Link: http://lkml.kernel.org/r/20200302203109.179417-1-shakeelb@google.comSigned-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8a931f80
...@@ -656,7 +656,7 @@ __mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_node *mctz) ...@@ -656,7 +656,7 @@ __mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_node *mctz)
*/ */
__mem_cgroup_remove_exceeded(mz, mctz); __mem_cgroup_remove_exceeded(mz, mctz);
if (!soft_limit_excess(mz->memcg) || if (!soft_limit_excess(mz->memcg) ||
!css_tryget_online(&mz->memcg->css)) !css_tryget(&mz->memcg->css))
goto retry; goto retry;
done: done:
return mz; return mz;
...@@ -972,7 +972,8 @@ struct mem_cgroup *get_mem_cgroup_from_page(struct page *page) ...@@ -972,7 +972,8 @@ struct mem_cgroup *get_mem_cgroup_from_page(struct page *page)
return NULL; return NULL;
rcu_read_lock(); rcu_read_lock();
if (!memcg || !css_tryget_online(&memcg->css)) /* Page should not get uncharged and freed memcg under us. */
if (!memcg || WARN_ON_ONCE(!css_tryget(&memcg->css)))
memcg = root_mem_cgroup; memcg = root_mem_cgroup;
rcu_read_unlock(); rcu_read_unlock();
return memcg; return memcg;
...@@ -985,10 +986,13 @@ EXPORT_SYMBOL(get_mem_cgroup_from_page); ...@@ -985,10 +986,13 @@ EXPORT_SYMBOL(get_mem_cgroup_from_page);
static __always_inline struct mem_cgroup *get_mem_cgroup_from_current(void) static __always_inline struct mem_cgroup *get_mem_cgroup_from_current(void)
{ {
if (unlikely(current->active_memcg)) { if (unlikely(current->active_memcg)) {
struct mem_cgroup *memcg = root_mem_cgroup; struct mem_cgroup *memcg;
rcu_read_lock(); rcu_read_lock();
if (css_tryget_online(&current->active_memcg->css)) /* current->active_memcg must hold a ref. */
if (WARN_ON_ONCE(!css_tryget(&current->active_memcg->css)))
memcg = root_mem_cgroup;
else
memcg = current->active_memcg; memcg = current->active_memcg;
rcu_read_unlock(); rcu_read_unlock();
return memcg; return memcg;
...@@ -6789,7 +6793,7 @@ void mem_cgroup_sk_alloc(struct sock *sk) ...@@ -6789,7 +6793,7 @@ void mem_cgroup_sk_alloc(struct sock *sk)
goto out; goto out;
if (!cgroup_subsys_on_dfl(memory_cgrp_subsys) && !memcg->tcpmem_active) if (!cgroup_subsys_on_dfl(memory_cgrp_subsys) && !memcg->tcpmem_active)
goto out; goto out;
if (css_tryget_online(&memcg->css)) if (css_tryget(&memcg->css))
sk->sk_memcg = memcg; sk->sk_memcg = memcg;
out: out:
rcu_read_unlock(); rcu_read_unlock();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment