On 20.09.2019 15:29, Cyrill Gorcunov wrote: > Currently there is a small gap between fetching pointer, calling > kvfree and assign its value to nil. In current callgraph it is > not a problem (since memcg_free_shrinker_maps is running from > memcg_alloc_shrinker_maps and mem_cgroup_css_free only) still > this looks suspicious and we can easily eliminate the gap at all. > > Cc: Johannes Weiner <hannes@xxxxxxxxxxx> > Cc: Michal Hocko <mhocko@xxxxxxxxxx> > Cc: Vladimir Davydov <vdavydov.dev@xxxxxxxxx> > Cc: Kirill Tkhai <ktkhai@xxxxxxxxxxxxx> > Signed-off-by: Cyrill Gorcunov <gorcunov@xxxxxxxxx> > --- > mm/memcontrol.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > Index: linux-tip.git/mm/memcontrol.c > =================================================================== > --- linux-tip.git.orig/mm/memcontrol.c > +++ linux-tip.git/mm/memcontrol.c > @@ -364,9 +364,9 @@ static void memcg_free_shrinker_maps(str > for_each_node(nid) { > pn = mem_cgroup_nodeinfo(memcg, nid); > map = rcu_dereference_protected(pn->shrinker_map, true); > + rcu_assign_pointer(pn->shrinker_map, NULL); > if (map) > kvfree(map); > - rcu_assign_pointer(pn->shrinker_map, NULL); > } > } The current scheme is following. We allocate shrinker_map in css_online, while normal freeing happens in css_free. The NULLifying of pointer is needed in case of "abnormal freeing", when memcg_free_shrinker_maps() is called from memcg_alloc_shrinker_maps(). The NULLifying guarantees, we won't free pn->shrinker_map twice. There are no races or problems with kvfree() and rcu_assign_pointer() order, because of nobody can reference shrinker_map before memcg is online. In case of this rcu_assign_pointer() confuses, we may just remove is from the function, and call it only on css_free. Something like the below: diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 1c4c08b45e44..454303c3aa0f 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -372,7 +372,6 @@ static void memcg_free_shrinker_maps(struct mem_cgroup *memcg) map = rcu_dereference_protected(pn->shrinker_map, true); if (map) kvfree(map); - rcu_assign_pointer(pn->shrinker_map, NULL); } } @@ -389,7 +388,6 @@ static int memcg_alloc_shrinker_maps(struct mem_cgroup *memcg) for_each_node(nid) { map = kvzalloc(sizeof(*map) + size, GFP_KERNEL); if (!map) { - memcg_free_shrinker_maps(memcg); ret = -ENOMEM; break; }