Skip to content

Commit 764d66d

Browse files
Peter Zijlstragregkh
Peter Zijlstra
authored andcommitted
cpuset: Fix memory allocator deadlock
commit 0fc0287 upstream. Juri hit the below lockdep report: [ 4.303391] ====================================================== [ 4.303392] [ INFO: SOFTIRQ-safe -> SOFTIRQ-unsafe lock order detected ] [ 4.303394] 3.12.0-dl-peterz+ #144 Not tainted [ 4.303395] ------------------------------------------------------ [ 4.303397] kworker/u4:3/689 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire: [ 4.303399] (&p->mems_allowed_seq){+.+...}, at: [<ffffffff8114e63c>] new_slab+0x6c/0x290 [ 4.303417] [ 4.303417] and this task is already holding: [ 4.303418] (&(&q->__queue_lock)->rlock){..-...}, at: [<ffffffff812d2dfb>] blk_execute_rq_nowait+0x5b/0x100 [ 4.303431] which would create a new lock dependency: [ 4.303432] (&(&q->__queue_lock)->rlock){..-...} -> (&p->mems_allowed_seq){+.+...} [ 4.303436] [ 4.303898] the dependencies between the lock to be acquired and SOFTIRQ-irq-unsafe lock: [ 4.303918] -> (&p->mems_allowed_seq){+.+...} ops: 2762 { [ 4.303922] HARDIRQ-ON-W at: [ 4.303923] [<ffffffff8108ab9a>] __lock_acquire+0x65a/0x1ff0 [ 4.303926] [<ffffffff8108cbe3>] lock_acquire+0x93/0x140 [ 4.303929] [<ffffffff81063dd6>] kthreadd+0x86/0x180 [ 4.303931] [<ffffffff816ded6c>] ret_from_fork+0x7c/0xb0 [ 4.303933] SOFTIRQ-ON-W at: [ 4.303933] [<ffffffff8108abcc>] __lock_acquire+0x68c/0x1ff0 [ 4.303935] [<ffffffff8108cbe3>] lock_acquire+0x93/0x140 [ 4.303940] [<ffffffff81063dd6>] kthreadd+0x86/0x180 [ 4.303955] [<ffffffff816ded6c>] ret_from_fork+0x7c/0xb0 [ 4.303959] INITIAL USE at: [ 4.303960] [<ffffffff8108a884>] __lock_acquire+0x344/0x1ff0 [ 4.303963] [<ffffffff8108cbe3>] lock_acquire+0x93/0x140 [ 4.303966] [<ffffffff81063dd6>] kthreadd+0x86/0x180 [ 4.303969] [<ffffffff816ded6c>] ret_from_fork+0x7c/0xb0 [ 4.303972] } Which reports that we take mems_allowed_seq with interrupts enabled. A little digging found that this can only be from cpuset_change_task_nodemask(). This is an actual deadlock because an interrupt doing an allocation will hit get_mems_allowed()->...->__read_seqcount_begin(), which will spin forever waiting for the write side to complete. Cc: John Stultz <[email protected]> Cc: Mel Gorman <[email protected]> Reported-by: Juri Lelli <[email protected]> Signed-off-by: Peter Zijlstra <[email protected]> Tested-by: Juri Lelli <[email protected]> Acked-by: Li Zefan <[email protected]> Acked-by: Mel Gorman <[email protected]> Signed-off-by: Tejun Heo <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent e6af24f commit 764d66d

File tree

1 file changed

+6
-2
lines changed

1 file changed

+6
-2
lines changed

kernel/cpuset.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,17 +1033,21 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
10331033
need_loop = task_has_mempolicy(tsk) ||
10341034
!nodes_intersects(*newmems, tsk->mems_allowed);
10351035

1036-
if (need_loop)
1036+
if (need_loop) {
1037+
local_irq_disable();
10371038
write_seqcount_begin(&tsk->mems_allowed_seq);
1039+
}
10381040

10391041
nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);
10401042
mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP1);
10411043

10421044
mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP2);
10431045
tsk->mems_allowed = *newmems;
10441046

1045-
if (need_loop)
1047+
if (need_loop) {
10461048
write_seqcount_end(&tsk->mems_allowed_seq);
1049+
local_irq_enable();
1050+
}
10471051

10481052
task_unlock(tsk);
10491053
}

0 commit comments

Comments
 (0)