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); |
