In case of memcg_online_kmem() failure, memcg_cgroup::id remains hashed in mem_cgroup_idr even after memcg memory is freed. This leads to leak of ID in mem_cgroup_idr. This patch adds removal into mem_cgroup_css_alloc(), which fixes the problem. For better readability, it adds a generic helper which is used in mem_cgroup_alloc() and mem_cgroup_id_put_many() as well.
Unified · Split
| @@ -4037,6 +4037,14 @@ static struct cftype mem_cgroup_legacy_files[] = { · 4036 unmodified lines | |||
| 4037 | 4037 | ||
| 4038 | static DEFINE_IDR(mem_cgroup_idr); | 4038 | static DEFINE_IDR(mem_cgroup_idr); |
| 4039 | 4039 | ||
| 4040 | static void mem_cgroup_id_remove(struct mem_cgroup *memcg) | ||
| 4041 | { | ||
| 4042 | if (memcg->id.id > 0) { | ||
| 4043 | idr_remove(&mem_cgroup_idr, memcg->id.id); | ||
| 4044 | memcg->id.id = 0; | ||
| 4045 | } | ||
| 4046 | } | ||
| 4047 | |||
| 4040 | static void mem_cgroup_id_get_many(struct mem_cgroup *memcg, unsigned int n) | 4048 | static void mem_cgroup_id_get_many(struct mem_cgroup *memcg, unsigned int n) |
| 4041 | { | 4049 | { |
| 4042 | VM_BUG_ON(atomic_read(&memcg->id.ref) <= 0); | 4050 | VM_BUG_ON(atomic_read(&memcg->id.ref) <= 0); |
| @@ -4047,8 +4055,7 @@ static void mem_cgroup_id_put_many(struct mem_cgroup *memcg, unsigned int n) · 4 unmodified lines | |||
| 4047 | { | 4055 | { |
| 4048 | VM_BUG_ON(atomic_read(&memcg->id.ref) < n); | 4056 | VM_BUG_ON(atomic_read(&memcg->id.ref) < n); |
| 4049 | if (atomic_sub_and_test(n, &memcg->id.ref)) { | 4057 | if (atomic_sub_and_test(n, &memcg->id.ref)) { |
| 4050 | idr_remove(&mem_cgroup_idr, memcg->id.id); | 4058 | mem_cgroup_id_remove(memcg); |
| 4051 | memcg->id.id = 0; | ||
| 4052 | 4059 | ||
| 4053 | /* Memcg ID pins CSS */ | 4060 | /* Memcg ID pins CSS */ |
| 4054 | css_put(&memcg->css); | 4061 | css_put(&memcg->css); |
| @@ -4185,8 +4192,7 @@ static struct mem_cgroup *mem_cgroup_alloc(void) · 130 unmodified lines | |||
| 4185 | idr_replace(&mem_cgroup_idr, memcg, memcg->id.id); | 4192 | idr_replace(&mem_cgroup_idr, memcg, memcg->id.id); |
| 4186 | return memcg; | 4193 | return memcg; |
| 4187 | fail: | 4194 | fail: |
| 4188 | if (memcg->id.id > 0) | 4195 | mem_cgroup_id_remove(memcg); |
| 4189 | idr_remove(&mem_cgroup_idr, memcg->id.id); | ||
| 4190 | __mem_cgroup_free(memcg); | 4196 | __mem_cgroup_free(memcg); |
| 4191 | return NULL; | 4197 | return NULL; |
| 4192 | } | 4198 | } |
| @@ -4245,6 +4251,7 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css) · 52 unmodified lines | |||
| 4245 | 4251 | ||
| 4246 | return &memcg->css; | 4252 | return &memcg->css; |
| 4247 | fail: | 4253 | fail: |
| 4254 | mem_cgroup_id_remove(memcg); | ||
| 4248 | mem_cgroup_free(memcg); | 4255 | mem_cgroup_free(memcg); |
| 4249 | return ERR_PTR(-ENOMEM); | 4256 | return ERR_PTR(-ENOMEM); |
| 4250 | } | 4257 | } |