From: "zhang.chun" <zhang.chuna@xxxxxxx> I work with zhangzhansheng(from h3c) find that some situation may casue deadlock when we use kmap_high and kmap_XXX or kumap_xxx between differt cores at the same time, kmap_high->map_new_virtual-> flush_all_zero_pkmaps->flush_tlb_kernel_range->on_each_cpu. On this condition, kmap_high hold the kmap_lock,wait the other cores respond to ipi. But the others may disable irq and wait kmap_lock, this is some deadlock condition. I think it's necessary to give kmap_lock before call flush_tlb_kernel_range. Like this: spin_unlock(&kmap_lock); flush_tlb_kernel_range(xxx); spin_lock(&kmap_lock); CPU 0: cpu 1: kmap_xxx() { xxx irq_disable(); kmap_high(); spin_lock(&kmap_lock) xxx yyyyyyy spin_unlock(&kmap_lock) irq_enable(); } kmap_high detail: kmap_high() { zzz spin_lock(&kmap_lock) map_new_virtual-> flush_all_zero_pkmaps-> flush_tlb_kernel_range-> on_each_cpu /* if cpu 1 irq_disabled, the cpu 1 cannot ack, then cpu 0 and cpu 1 may hangup. */ spin_unlock(&kmap_lock) zzz }
Signed-off-by: zhangchun <zhang.chuna@xxxxxxx> Reviewed-by: zhangzhengming <zhang.zhengming@xxxxxxx> --- mm/highmem.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/highmem.c b/mm/highmem.c index bd48ba4..841b370 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -220,8 +220,11 @@ static void flush_all_zero_pkmaps(void) set_page_address(page, NULL); need_flush = 1; } - if (need_flush) + if (need_flush) { + spin_unlock(&kmap_lock); flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP)); + spin_lock(&kmap_lock); + } } void __kmap_flush_unused(void) -- 2.34.1