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

powerpc/pseries/vas: Hold mmap_mutex after mmap lock during window close

Commit 8ef7b9e1765a ("powerpc/pseries/vas: Close windows with DLPAR
core removal") unmaps the window paste address and issues HCALL to
close window in the hypervisor for migration or DLPAR core removal
events. So holds mmap_mutex and then mmap lock before unmap the
paste address. But if the user space issue mmap paste address at
the same time with the migration event, coproc_mmap() is called
after holding the mmap lock which can trigger deadlock when trying
to acquire mmap_mutex in coproc_mmap().

t1: mmap() call to mmap t2: Migration event
window paste address

do_mmap2() migration_store()
ksys_mmap_pgoff() pseries_migrate_partition()
vm_mmap_pgoff() vas_migration_handler()
Acquire mmap lock reconfig_close_windows()
do_mmap() lock mmap_mutex
mmap_region() Acquire mmap lock
call_mmap() //Wait for mmap lock
coproc_mmap() unmap vma
lock mmap_mutex update window status
//wait for mmap_mutex Release mmap lock
mmap vma unlock mmap_mutex
update window status
unlock mmap_mutex
...
Release mmap lock

Fix this deadlock issue by holding mmap lock first before mmap_mutex
in reconfig_close_windows().

Fixes: 8ef7b9e1765a ("powerpc/pseries/vas: Close windows with DLPAR core removal")
Signed-off-by: Haren Myneni <haren@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230716100506.7833-1-haren@linux.ibm.com

authored by

Haren Myneni and committed by
Michael Ellerman
b59c9dc4 fdf0eaf1

+7 -2
+7 -2
arch/powerpc/platforms/pseries/vas.c
··· 744 744 } 745 745 746 746 task_ref = &win->vas_win.task_ref; 747 + /* 748 + * VAS mmap (coproc_mmap()) and its fault handler 749 + * (vas_mmap_fault()) are called after holding mmap lock. 750 + * So hold mmap mutex after mmap_lock to avoid deadlock. 751 + */ 752 + mmap_write_lock(task_ref->mm); 747 753 mutex_lock(&task_ref->mmap_mutex); 748 754 vma = task_ref->vma; 749 755 /* ··· 758 752 */ 759 753 win->vas_win.status |= flag; 760 754 761 - mmap_write_lock(task_ref->mm); 762 755 /* 763 756 * vma is set in the original mapping. But this mapping 764 757 * is done with mmap() after the window is opened with ioctl. ··· 767 762 if (vma) 768 763 zap_vma_pages(vma); 769 764 770 - mmap_write_unlock(task_ref->mm); 771 765 mutex_unlock(&task_ref->mmap_mutex); 766 + mmap_write_unlock(task_ref->mm); 772 767 /* 773 768 * Close VAS window in the hypervisor, but do not 774 769 * free vas_window struct since it may be reused