memcg, kmem: fix reference count handling on the error path
[platform/adaptation/renesas_rcar/renesas_kernel.git] / mm / memcontrol.c
index 2e851f4..bdeb82c 100644 (file)
@@ -187,10 +187,6 @@ struct mem_cgroup_per_node {
        struct mem_cgroup_per_zone zoneinfo[MAX_NR_ZONES];
 };
 
-struct mem_cgroup_lru_info {
-       struct mem_cgroup_per_node *nodeinfo[0];
-};
-
 /*
  * Cgroups above their limits are maintained in a RB-Tree, independent of
  * their hierarchy representation
@@ -366,14 +362,8 @@ struct mem_cgroup {
        atomic_t        numainfo_updating;
 #endif
 
-       /*
-        * Per cgroup active and inactive list, similar to the
-        * per zone LRU lists.
-        *
-        * WARNING: This has to be the last element of the struct. Don't
-        * add new fields after this point.
-        */
-       struct mem_cgroup_lru_info info;
+       struct mem_cgroup_per_node *nodeinfo[0];
+       /* WARNING: nodeinfo must be the last member here */
 };
 
 static size_t memcg_size(void)
@@ -683,7 +673,7 @@ static struct mem_cgroup_per_zone *
 mem_cgroup_zoneinfo(struct mem_cgroup *memcg, int nid, int zid)
 {
        VM_BUG_ON((unsigned)nid >= nr_node_ids);
-       return &memcg->info.nodeinfo[nid]->zoneinfo[zid];
+       return &memcg->nodeinfo[nid]->zoneinfo[zid];
 }
 
 struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *memcg)
@@ -3647,6 +3637,34 @@ __memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **_memcg, int order)
        int ret;
 
        *_memcg = NULL;
+
+       /*
+        * Disabling accounting is only relevant for some specific memcg
+        * internal allocations. Therefore we would initially not have such
+        * check here, since direct calls to the page allocator that are marked
+        * with GFP_KMEMCG only happen outside memcg core. We are mostly
+        * concerned with cache allocations, and by having this test at
+        * memcg_kmem_get_cache, we are already able to relay the allocation to
+        * the root cache and bypass the memcg cache altogether.
+        *
+        * There is one exception, though: the SLUB allocator does not create
+        * large order caches, but rather service large kmallocs directly from
+        * the page allocator. Therefore, the following sequence when backed by
+        * the SLUB allocator:
+        *
+        *      memcg_stop_kmem_account();
+        *      kmalloc(<large_number>)
+        *      memcg_resume_kmem_account();
+        *
+        * would effectively ignore the fact that we should skip accounting,
+        * since it will drive us directly to this function without passing
+        * through the cache selector memcg_kmem_get_cache. Such large
+        * allocations are extremely rare but can happen, for instance, for the
+        * cache arrays. We bring this test here.
+        */
+       if (!current->mm || current->memcg_kmem_skip_account)
+               return true;
+
        memcg = try_get_mem_cgroup_from_mm(current->mm);
 
        /*
@@ -5214,7 +5232,9 @@ static int memcg_propagate_kmem(struct mem_cgroup *memcg)
        static_key_slow_inc(&memcg_kmem_enabled_key);
 
        mutex_lock(&set_limit_mutex);
+       memcg_stop_kmem_account();
        ret = memcg_update_cache_sizes(memcg);
+       memcg_resume_kmem_account();
        mutex_unlock(&set_limit_mutex);
 out:
        return ret;
@@ -6087,13 +6107,13 @@ static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
                mz->on_tree = false;
                mz->memcg = memcg;
        }
-       memcg->info.nodeinfo[node] = pn;
+       memcg->nodeinfo[node] = pn;
        return 0;
 }
 
 static void free_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
 {
-       kfree(memcg->info.nodeinfo[node]);
+       kfree(memcg->nodeinfo[node]);
 }
 
 static struct mem_cgroup *mem_cgroup_alloc(void)
@@ -6325,16 +6345,6 @@ mem_cgroup_css_online(struct cgroup *cont)
 
        error = memcg_init_kmem(memcg, &mem_cgroup_subsys);
        mutex_unlock(&memcg_create_mutex);
-       if (error) {
-               /*
-                * We call put now because our (and parent's) refcnts
-                * are already in place. mem_cgroup_put() will internally
-                * call __mem_cgroup_free, so return directly
-                */
-               mem_cgroup_put(memcg);
-               if (parent->use_hierarchy)
-                       mem_cgroup_put(parent);
-       }
        return error;
 }