|
@@ -5247,16 +5247,29 @@ out_free:
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Helpers for freeing a kmalloc()ed/vzalloc()ed mem_cgroup by RCU,
|
|
|
- * but in process context. The work_freeing structure is overlaid
|
|
|
- * on the rcu_freeing structure, which itself is overlaid on memsw.
|
|
|
+ * At destroying mem_cgroup, references from swap_cgroup can remain.
|
|
|
+ * (scanning all at force_empty is too costly...)
|
|
|
+ *
|
|
|
+ * Instead of clearing all references at force_empty, we remember
|
|
|
+ * the number of reference from swap_cgroup and free mem_cgroup when
|
|
|
+ * it goes down to 0.
|
|
|
+ *
|
|
|
+ * Removal of cgroup itself succeeds regardless of refs from swap.
|
|
|
*/
|
|
|
-static void free_work(struct work_struct *work)
|
|
|
+
|
|
|
+static void __mem_cgroup_free(struct mem_cgroup *memcg)
|
|
|
{
|
|
|
- struct mem_cgroup *memcg;
|
|
|
+ int node;
|
|
|
int size = sizeof(struct mem_cgroup);
|
|
|
|
|
|
- memcg = container_of(work, struct mem_cgroup, work_freeing);
|
|
|
+ mem_cgroup_remove_from_trees(memcg);
|
|
|
+ free_css_id(&mem_cgroup_subsys, &memcg->css);
|
|
|
+
|
|
|
+ for_each_node(node)
|
|
|
+ free_mem_cgroup_per_zone_info(memcg, node);
|
|
|
+
|
|
|
+ free_percpu(memcg->stat);
|
|
|
+
|
|
|
/*
|
|
|
* We need to make sure that (at least for now), the jump label
|
|
|
* destruction code runs outside of the cgroup lock. This is because
|
|
@@ -5275,38 +5288,27 @@ static void free_work(struct work_struct *work)
|
|
|
vfree(memcg);
|
|
|
}
|
|
|
|
|
|
-static void free_rcu(struct rcu_head *rcu_head)
|
|
|
-{
|
|
|
- struct mem_cgroup *memcg;
|
|
|
-
|
|
|
- memcg = container_of(rcu_head, struct mem_cgroup, rcu_freeing);
|
|
|
- INIT_WORK(&memcg->work_freeing, free_work);
|
|
|
- schedule_work(&memcg->work_freeing);
|
|
|
-}
|
|
|
|
|
|
/*
|
|
|
- * At destroying mem_cgroup, references from swap_cgroup can remain.
|
|
|
- * (scanning all at force_empty is too costly...)
|
|
|
- *
|
|
|
- * Instead of clearing all references at force_empty, we remember
|
|
|
- * the number of reference from swap_cgroup and free mem_cgroup when
|
|
|
- * it goes down to 0.
|
|
|
- *
|
|
|
- * Removal of cgroup itself succeeds regardless of refs from swap.
|
|
|
+ * Helpers for freeing a kmalloc()ed/vzalloc()ed mem_cgroup by RCU,
|
|
|
+ * but in process context. The work_freeing structure is overlaid
|
|
|
+ * on the rcu_freeing structure, which itself is overlaid on memsw.
|
|
|
*/
|
|
|
-
|
|
|
-static void __mem_cgroup_free(struct mem_cgroup *memcg)
|
|
|
+static void free_work(struct work_struct *work)
|
|
|
{
|
|
|
- int node;
|
|
|
+ struct mem_cgroup *memcg;
|
|
|
|
|
|
- mem_cgroup_remove_from_trees(memcg);
|
|
|
- free_css_id(&mem_cgroup_subsys, &memcg->css);
|
|
|
+ memcg = container_of(work, struct mem_cgroup, work_freeing);
|
|
|
+ __mem_cgroup_free(memcg);
|
|
|
+}
|
|
|
|
|
|
- for_each_node(node)
|
|
|
- free_mem_cgroup_per_zone_info(memcg, node);
|
|
|
+static void free_rcu(struct rcu_head *rcu_head)
|
|
|
+{
|
|
|
+ struct mem_cgroup *memcg;
|
|
|
|
|
|
- free_percpu(memcg->stat);
|
|
|
- call_rcu(&memcg->rcu_freeing, free_rcu);
|
|
|
+ memcg = container_of(rcu_head, struct mem_cgroup, rcu_freeing);
|
|
|
+ INIT_WORK(&memcg->work_freeing, free_work);
|
|
|
+ schedule_work(&memcg->work_freeing);
|
|
|
}
|
|
|
|
|
|
static void mem_cgroup_get(struct mem_cgroup *memcg)
|
|
@@ -5318,7 +5320,7 @@ static void __mem_cgroup_put(struct mem_cgroup *memcg, int count)
|
|
|
{
|
|
|
if (atomic_sub_and_test(count, &memcg->refcnt)) {
|
|
|
struct mem_cgroup *parent = parent_mem_cgroup(memcg);
|
|
|
- __mem_cgroup_free(memcg);
|
|
|
+ call_rcu(&memcg->rcu_freeing, free_rcu);
|
|
|
if (parent)
|
|
|
mem_cgroup_put(parent);
|
|
|
}
|