IB/umem: Fix possible hang on process exit

If ib_umem_release() is called after ib_uverbs_close() sets context->closing,
then a process can get stuck in a D state, because the code boils down to

if (down_write_trylock(&mm->mmap_sem))
down_write(&mm->mmap_sem);

which is obviously a stupid instant deadlock. Fix the code so that we
only try to take the lock once.

This bug was introduced in commit f7c6a7b5 ("IB/uverbs: Export
ib_umem_get()/ib_umem_release() to modules") which fortunately never
made it into a release, and was reported by Pete Wyckoff <pw@osc.edu>.

Signed-off-by: Roland Dreier <rolandd@cisco.com>

+8 -6
+8 -6
drivers/infiniband/core/umem.c
··· 225 225 * up here and not be able to take the mmap_sem. In that case 226 226 * we defer the vm_locked accounting to the system workqueue. 227 227 */ 228 - if (context->closing && !down_write_trylock(&mm->mmap_sem)) { 229 - INIT_WORK(&umem->work, ib_umem_account); 230 - umem->mm = mm; 231 - umem->diff = diff; 228 + if (context->closing) { 229 + if (!down_write_trylock(&mm->mmap_sem)) { 230 + INIT_WORK(&umem->work, ib_umem_account); 231 + umem->mm = mm; 232 + umem->diff = diff; 232 233 233 - schedule_work(&umem->work); 234 - return; 234 + schedule_work(&umem->work); 235 + return; 236 + } 235 237 } else 236 238 down_write(&mm->mmap_sem); 237 239