Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sparc32: destroy_context() and switch_mm() needs to disable interrupts.

Load balancing can be triggered in the critical sections protected by
srmmu_context_spinlock in destroy_context() and switch_mm() and can hang
the cpu waiting for the rq lock of another cpu that in turn has called
switch_mm hangning on srmmu_context_spinlock leading to deadlock.

So, disable interrupt while taking srmmu_context_spinlock in
destroy_context() and switch_mm() so we don't deadlock.

See also commit 77b838fa1ef0 ("[SPARC64]: destroy_context() needs to disable
interrupts.")

Signed-off-by: Andreas Larsson <andreas@gaisler.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Andreas Larsson and committed by
David S. Miller
66d0f7ec 44e8967d

+7 -4
+7 -4
arch/sparc/mm/srmmu.c
··· 460 460 void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, 461 461 struct task_struct *tsk) 462 462 { 463 + unsigned long flags; 464 + 463 465 if (mm->context == NO_CONTEXT) { 464 - spin_lock(&srmmu_context_spinlock); 466 + spin_lock_irqsave(&srmmu_context_spinlock, flags); 465 467 alloc_context(old_mm, mm); 466 - spin_unlock(&srmmu_context_spinlock); 468 + spin_unlock_irqrestore(&srmmu_context_spinlock, flags); 467 469 srmmu_ctxd_set(&srmmu_context_table[mm->context], mm->pgd); 468 470 } 469 471 ··· 988 986 989 987 void destroy_context(struct mm_struct *mm) 990 988 { 989 + unsigned long flags; 991 990 992 991 if (mm->context != NO_CONTEXT) { 993 992 flush_cache_mm(mm); 994 993 srmmu_ctxd_set(&srmmu_context_table[mm->context], srmmu_swapper_pg_dir); 995 994 flush_tlb_mm(mm); 996 - spin_lock(&srmmu_context_spinlock); 995 + spin_lock_irqsave(&srmmu_context_spinlock, flags); 997 996 free_context(mm->context); 998 - spin_unlock(&srmmu_context_spinlock); 997 + spin_unlock_irqrestore(&srmmu_context_spinlock, flags); 999 998 mm->context = NO_CONTEXT; 1000 999 } 1001 1000 }