From: Hongbo Yao yaohongbo@huawei.com
hulk inclusion category: bugfix bugzilla: 27970 CVE: NA
-------------------------------------------------
This reverts commit 038c2f6d971260670b0844208f4e3424b1d55c39. If we do hotplug in vfio-enabled kvm, holding the mmap_sem reader longer will cause hangtask.
[ 1091.426125] Call trace: [ 1091.428572] __switch_to+0xe4/0x148 [ 1091.432054] __schedule+0x31c/0x9c0 [ 1091.435528] schedule+0x2c/0x88 [ 1091.438660] rwsem_down_write_failed+0x138/0x2e8 [ 1091.443261] down_write+0x58/0x70 [ 1091.446569] vaddr_get_pfn+0x54/0x280 [vfio_iommu_type1] [ 1091.451863] vfio_pin_pages_remote+0x88/0x3c0 [vfio_iommu_type1] [ 1091.457848] vfio_pin_map_dma+0xc0/0x300 [vfio_iommu_type1] [ 1091.463401] vfio_iommu_type1_ioctl+0xa5c/0xcc4 [vfio_iommu_type1] [ 1091.469563] vfio_fops_unl_ioctl+0x74/0x2e0 [vfio] [ 1091.474338] do_vfs_ioctl+0xc4/0x8c0 [ 1091.477904] ksys_ioctl+0x8c/0xa0 [ 1091.481210] __arm64_sys_ioctl+0x28/0x38 [ 1091.485121] el0_svc_common+0x78/0x130 [ 1091.488860] el0_svc_handler+0x38/0x78 [ 1091.492598] el0_svc+0x8/0xc
Signed-off-by: Hongbo Yao yaohongbo@huawei.com Reviewed-By: Xie XiuQi xiexiuqi@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/vfio/vfio_iommu_type1.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 414bb2e8c7bd..306778dcbb9e 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -347,7 +347,7 @@ static int put_pfn(unsigned long pfn, int prot) }
static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, - int prot, unsigned long *pfn, bool handle_mmap_sem) + int prot, unsigned long *pfn) { struct page *page[1]; struct vm_area_struct *vma; @@ -358,8 +358,7 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, if (prot & IOMMU_WRITE) flags |= FOLL_WRITE;
- if (handle_mmap_sem) - down_read(&mm->mmap_sem); + down_read(&mm->mmap_sem); if (mm == current->mm) { ret = get_user_pages_longterm(vaddr, 1, flags, page, vmas); } else { @@ -377,16 +376,14 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, put_page(page[0]); } } - if (handle_mmap_sem) - up_read(&mm->mmap_sem); + up_read(&mm->mmap_sem);
if (ret == 1) { *pfn = page_to_pfn(page[0]); return 0; }
- if (handle_mmap_sem) - down_read(&mm->mmap_sem); + down_read(&mm->mmap_sem);
vma = find_vma_intersection(mm, vaddr, vaddr + 1);
@@ -396,8 +393,7 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, ret = 0; }
- if (handle_mmap_sem) - up_read(&mm->mmap_sem); + up_read(&mm->mmap_sem); return ret; }
@@ -419,12 +415,9 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, if (!mm) return -ENODEV;
- down_read(&mm->mmap_sem); - ret = vaddr_get_pfn(mm, vaddr, dma->prot, pfn_base, false); - if (ret) { - up_read(&mm->mmap_sem); + ret = vaddr_get_pfn(mm, vaddr, dma->prot, pfn_base); + if (ret) return ret; - }
pinned++; rsvd = is_invalid_reserved_pfn(*pfn_base); @@ -439,7 +432,6 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, put_pfn(*pfn_base, dma->prot); pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__, limit << PAGE_SHIFT); - up_read(&mm->mmap_sem); return -ENOMEM; } lock_acct++; @@ -451,7 +443,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, /* Lock all the consecutive pages from pfn_base */ for (vaddr += PAGE_SIZE, iova += PAGE_SIZE; pinned < npage; pinned++, vaddr += PAGE_SIZE, iova += PAGE_SIZE) { - ret = vaddr_get_pfn(mm, vaddr, dma->prot, &pfn, false); + ret = vaddr_get_pfn(mm, vaddr, dma->prot, &pfn); if (ret) break;
@@ -468,7 +460,6 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__, limit << PAGE_SHIFT); ret = -ENOMEM; - up_read(&mm->mmap_sem); goto unpin_out; } lock_acct++; @@ -476,7 +467,6 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, }
out: - up_read(&mm->mmap_sem); ret = vfio_lock_acct(dma, lock_acct, false);
unpin_out: @@ -523,7 +513,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr, if (!mm) return -ENODEV;
- ret = vaddr_get_pfn(mm, vaddr, dma->prot, pfn_base, true); + ret = vaddr_get_pfn(mm, vaddr, dma->prot, pfn_base); if (!ret && do_accounting && !is_invalid_reserved_pfn(*pfn_base)) { ret = vfio_lock_acct(dma, 1, true); if (ret) {