Skip to content

Commit 264a0ae

Browse files
committed
memcg: relocate charge moving from ->attach to ->post_attach
Hello, So, this ended up a lot simpler than I originally expected. I tested it lightly and it seems to work fine. Petr, can you please test these two patches w/o the lru drain drop patch and see whether the problem is gone? Thanks. ------ 8< ------ If charge moving is used, memcg performs relabeling of the affected pages from its ->attach callback which is called under both cgroup_threadgroup_rwsem and thus can't create new kthreads. This is fragile as various operations may depend on workqueues making forward progress which relies on the ability to create new kthreads. There's no reason to perform charge moving from ->attach which is deep in the task migration path. Move it to ->post_attach which is called after the actual migration is finished and cgroup_threadgroup_rwsem is dropped. * move_charge_struct->mm is added and ->can_attach is now responsible for pinning and recording the target mm. mem_cgroup_clear_mc() is updated accordingly. This also simplifies mem_cgroup_move_task(). * mem_cgroup_move_task() is now called from ->post_attach instead of ->attach. Signed-off-by: Tejun Heo <[email protected]> Cc: Johannes Weiner <[email protected]> Acked-by: Michal Hocko <[email protected]> Debugged-and-tested-by: Petr Mladek <[email protected]> Reported-by: Cyril Hrubis <[email protected]> Reported-by: Johannes Weiner <[email protected]> Fixes: 1ed1328 ("sched, cgroup: replace signal_struct->group_rwsem with a global percpu_rwsem") Cc: <[email protected]> # 4.4+
1 parent 5cf1cac commit 264a0ae

File tree

1 file changed

+19
-18
lines changed

1 file changed

+19
-18
lines changed

mm/memcontrol.c

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ static void mem_cgroup_oom_notify(struct mem_cgroup *memcg);
207207
/* "mc" and its members are protected by cgroup_mutex */
208208
static struct move_charge_struct {
209209
spinlock_t lock; /* for from, to */
210+
struct mm_struct *mm;
210211
struct mem_cgroup *from;
211212
struct mem_cgroup *to;
212213
unsigned long flags;
@@ -4667,6 +4668,8 @@ static void __mem_cgroup_clear_mc(void)
46674668

46684669
static void mem_cgroup_clear_mc(void)
46694670
{
4671+
struct mm_struct *mm = mc.mm;
4672+
46704673
/*
46714674
* we must clear moving_task before waking up waiters at the end of
46724675
* task migration.
@@ -4676,7 +4679,10 @@ static void mem_cgroup_clear_mc(void)
46764679
spin_lock(&mc.lock);
46774680
mc.from = NULL;
46784681
mc.to = NULL;
4682+
mc.mm = NULL;
46794683
spin_unlock(&mc.lock);
4684+
4685+
mmput(mm);
46804686
}
46814687

46824688
static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
@@ -4733,6 +4739,7 @@ static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
47334739
VM_BUG_ON(mc.moved_swap);
47344740

47354741
spin_lock(&mc.lock);
4742+
mc.mm = mm;
47364743
mc.from = from;
47374744
mc.to = memcg;
47384745
mc.flags = move_flags;
@@ -4742,8 +4749,9 @@ static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
47424749
ret = mem_cgroup_precharge_mc(mm);
47434750
if (ret)
47444751
mem_cgroup_clear_mc();
4752+
} else {
4753+
mmput(mm);
47454754
}
4746-
mmput(mm);
47474755
return ret;
47484756
}
47494757

@@ -4852,11 +4860,11 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
48524860
return ret;
48534861
}
48544862

4855-
static void mem_cgroup_move_charge(struct mm_struct *mm)
4863+
static void mem_cgroup_move_charge(void)
48564864
{
48574865
struct mm_walk mem_cgroup_move_charge_walk = {
48584866
.pmd_entry = mem_cgroup_move_charge_pte_range,
4859-
.mm = mm,
4867+
.mm = mc.mm,
48604868
};
48614869

48624870
lru_add_drain_all();
@@ -4868,7 +4876,7 @@ static void mem_cgroup_move_charge(struct mm_struct *mm)
48684876
atomic_inc(&mc.from->moving_account);
48694877
synchronize_rcu();
48704878
retry:
4871-
if (unlikely(!down_read_trylock(&mm->mmap_sem))) {
4879+
if (unlikely(!down_read_trylock(&mc.mm->mmap_sem))) {
48724880
/*
48734881
* Someone who are holding the mmap_sem might be waiting in
48744882
* waitq. So we cancel all extra charges, wake up all waiters,
@@ -4885,23 +4893,16 @@ static void mem_cgroup_move_charge(struct mm_struct *mm)
48854893
* additional charge, the page walk just aborts.
48864894
*/
48874895
walk_page_range(0, ~0UL, &mem_cgroup_move_charge_walk);
4888-
up_read(&mm->mmap_sem);
4896+
up_read(&mc.mm->mmap_sem);
48894897
atomic_dec(&mc.from->moving_account);
48904898
}
48914899

4892-
static void mem_cgroup_move_task(struct cgroup_taskset *tset)
4900+
static void mem_cgroup_move_task(void)
48934901
{
4894-
struct cgroup_subsys_state *css;
4895-
struct task_struct *p = cgroup_taskset_first(tset, &css);
4896-
struct mm_struct *mm = get_task_mm(p);
4897-
4898-
if (mm) {
4899-
if (mc.to)
4900-
mem_cgroup_move_charge(mm);
4901-
mmput(mm);
4902-
}
4903-
if (mc.to)
4902+
if (mc.to) {
4903+
mem_cgroup_move_charge();
49044904
mem_cgroup_clear_mc();
4905+
}
49054906
}
49064907
#else /* !CONFIG_MMU */
49074908
static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
@@ -4911,7 +4912,7 @@ static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
49114912
static void mem_cgroup_cancel_attach(struct cgroup_taskset *tset)
49124913
{
49134914
}
4914-
static void mem_cgroup_move_task(struct cgroup_taskset *tset)
4915+
static void mem_cgroup_move_task(void)
49154916
{
49164917
}
49174918
#endif
@@ -5195,7 +5196,7 @@ struct cgroup_subsys memory_cgrp_subsys = {
51955196
.css_reset = mem_cgroup_css_reset,
51965197
.can_attach = mem_cgroup_can_attach,
51975198
.cancel_attach = mem_cgroup_cancel_attach,
5198-
.attach = mem_cgroup_move_task,
5199+
.post_attach = mem_cgroup_move_task,
51995200
.bind = mem_cgroup_bind,
52005201
.dfl_cftypes = memory_files,
52015202
.legacy_cftypes = mem_cgroup_legacy_files,

0 commit comments

Comments
 (0)