diff options
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 4d0ea3ceba6d..8e4be9cb2a6a 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -202,6 +202,7 @@ pcg_default_flags[NR_CHARGE_TYPE] = { | |||
202 | 202 | ||
203 | static void mem_cgroup_get(struct mem_cgroup *mem); | 203 | static void mem_cgroup_get(struct mem_cgroup *mem); |
204 | static void mem_cgroup_put(struct mem_cgroup *mem); | 204 | static void mem_cgroup_put(struct mem_cgroup *mem); |
205 | static struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *mem); | ||
205 | 206 | ||
206 | static void mem_cgroup_charge_statistics(struct mem_cgroup *mem, | 207 | static void mem_cgroup_charge_statistics(struct mem_cgroup *mem, |
207 | struct page_cgroup *pc, | 208 | struct page_cgroup *pc, |
@@ -1684,7 +1685,7 @@ move_account: | |||
1684 | /* This is for making all *used* pages to be on LRU. */ | 1685 | /* This is for making all *used* pages to be on LRU. */ |
1685 | lru_add_drain_all(); | 1686 | lru_add_drain_all(); |
1686 | ret = 0; | 1687 | ret = 0; |
1687 | for_each_node_state(node, N_POSSIBLE) { | 1688 | for_each_node_state(node, N_HIGH_MEMORY) { |
1688 | for (zid = 0; !ret && zid < MAX_NR_ZONES; zid++) { | 1689 | for (zid = 0; !ret && zid < MAX_NR_ZONES; zid++) { |
1689 | enum lru_list l; | 1690 | enum lru_list l; |
1690 | for_each_lru(l) { | 1691 | for_each_lru(l) { |
@@ -2193,10 +2194,23 @@ static void mem_cgroup_get(struct mem_cgroup *mem) | |||
2193 | 2194 | ||
2194 | static void mem_cgroup_put(struct mem_cgroup *mem) | 2195 | static void mem_cgroup_put(struct mem_cgroup *mem) |
2195 | { | 2196 | { |
2196 | if (atomic_dec_and_test(&mem->refcnt)) | 2197 | if (atomic_dec_and_test(&mem->refcnt)) { |
2198 | struct mem_cgroup *parent = parent_mem_cgroup(mem); | ||
2197 | __mem_cgroup_free(mem); | 2199 | __mem_cgroup_free(mem); |
2200 | if (parent) | ||
2201 | mem_cgroup_put(parent); | ||
2202 | } | ||
2198 | } | 2203 | } |
2199 | 2204 | ||
2205 | /* | ||
2206 | * Returns the parent mem_cgroup in memcgroup hierarchy with hierarchy enabled. | ||
2207 | */ | ||
2208 | static struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *mem) | ||
2209 | { | ||
2210 | if (!mem->res.parent) | ||
2211 | return NULL; | ||
2212 | return mem_cgroup_from_res_counter(mem->res.parent, res); | ||
2213 | } | ||
2200 | 2214 | ||
2201 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP | 2215 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP |
2202 | static void __init enable_swap_cgroup(void) | 2216 | static void __init enable_swap_cgroup(void) |
@@ -2235,6 +2249,13 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont) | |||
2235 | if (parent && parent->use_hierarchy) { | 2249 | if (parent && parent->use_hierarchy) { |
2236 | res_counter_init(&mem->res, &parent->res); | 2250 | res_counter_init(&mem->res, &parent->res); |
2237 | res_counter_init(&mem->memsw, &parent->memsw); | 2251 | res_counter_init(&mem->memsw, &parent->memsw); |
2252 | /* | ||
2253 | * We increment refcnt of the parent to ensure that we can | ||
2254 | * safely access it on res_counter_charge/uncharge. | ||
2255 | * This refcnt will be decremented when freeing this | ||
2256 | * mem_cgroup(see mem_cgroup_put). | ||
2257 | */ | ||
2258 | mem_cgroup_get(parent); | ||
2238 | } else { | 2259 | } else { |
2239 | res_counter_init(&mem->res, NULL); | 2260 | res_counter_init(&mem->res, NULL); |
2240 | res_counter_init(&mem->memsw, NULL); | 2261 | res_counter_init(&mem->memsw, NULL); |