提交 44d6e907 编写于 作者: H Hongbo Yao 提交者: Xie XiuQi

Revert "vfio: relieve mmap_sem reader cacheline bouncing by holding it longer"

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: NHongbo Yao <yaohongbo@huawei.com>
Reviewed-By: NXie XiuQi <xiexiuqi@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: NXie XiuQi <xiexiuqi@huawei.com>
上级 cf975ca6
...@@ -347,7 +347,7 @@ static int put_pfn(unsigned long pfn, int prot) ...@@ -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, 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 page *page[1];
struct vm_area_struct *vma; struct vm_area_struct *vma;
...@@ -358,8 +358,7 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, ...@@ -358,8 +358,7 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr,
if (prot & IOMMU_WRITE) if (prot & IOMMU_WRITE)
flags |= FOLL_WRITE; flags |= FOLL_WRITE;
if (handle_mmap_sem) down_read(&mm->mmap_sem);
down_read(&mm->mmap_sem);
if (mm == current->mm) { if (mm == current->mm) {
ret = get_user_pages_longterm(vaddr, 1, flags, page, vmas); ret = get_user_pages_longterm(vaddr, 1, flags, page, vmas);
} else { } else {
...@@ -377,16 +376,14 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, ...@@ -377,16 +376,14 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr,
put_page(page[0]); put_page(page[0]);
} }
} }
if (handle_mmap_sem) up_read(&mm->mmap_sem);
up_read(&mm->mmap_sem);
if (ret == 1) { if (ret == 1) {
*pfn = page_to_pfn(page[0]); *pfn = page_to_pfn(page[0]);
return 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); vma = find_vma_intersection(mm, vaddr, vaddr + 1);
...@@ -396,8 +393,7 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, ...@@ -396,8 +393,7 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr,
ret = 0; ret = 0;
} }
if (handle_mmap_sem) up_read(&mm->mmap_sem);
up_read(&mm->mmap_sem);
return ret; return ret;
} }
...@@ -419,12 +415,9 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, ...@@ -419,12 +415,9 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr,
if (!mm) if (!mm)
return -ENODEV; return -ENODEV;
down_read(&mm->mmap_sem); ret = vaddr_get_pfn(mm, vaddr, dma->prot, pfn_base);
ret = vaddr_get_pfn(mm, vaddr, dma->prot, pfn_base, false); if (ret)
if (ret) {
up_read(&mm->mmap_sem);
return ret; return ret;
}
pinned++; pinned++;
rsvd = is_invalid_reserved_pfn(*pfn_base); rsvd = is_invalid_reserved_pfn(*pfn_base);
...@@ -439,7 +432,6 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, ...@@ -439,7 +432,6 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr,
put_pfn(*pfn_base, dma->prot); put_pfn(*pfn_base, dma->prot);
pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__, pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__,
limit << PAGE_SHIFT); limit << PAGE_SHIFT);
up_read(&mm->mmap_sem);
return -ENOMEM; return -ENOMEM;
} }
lock_acct++; lock_acct++;
...@@ -451,7 +443,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, ...@@ -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 */ /* Lock all the consecutive pages from pfn_base */
for (vaddr += PAGE_SIZE, iova += PAGE_SIZE; pinned < npage; for (vaddr += PAGE_SIZE, iova += PAGE_SIZE; pinned < npage;
pinned++, vaddr += PAGE_SIZE, iova += PAGE_SIZE) { 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) if (ret)
break; break;
...@@ -468,7 +460,6 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, ...@@ -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", pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n",
__func__, limit << PAGE_SHIFT); __func__, limit << PAGE_SHIFT);
ret = -ENOMEM; ret = -ENOMEM;
up_read(&mm->mmap_sem);
goto unpin_out; goto unpin_out;
} }
lock_acct++; lock_acct++;
...@@ -476,7 +467,6 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, ...@@ -476,7 +467,6 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr,
} }
out: out:
up_read(&mm->mmap_sem);
ret = vfio_lock_acct(dma, lock_acct, false); ret = vfio_lock_acct(dma, lock_acct, false);
unpin_out: unpin_out:
...@@ -523,7 +513,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr, ...@@ -523,7 +513,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr,
if (!mm) if (!mm)
return -ENODEV; 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)) { if (!ret && do_accounting && !is_invalid_reserved_pfn(*pfn_base)) {
ret = vfio_lock_acct(dma, 1, true); ret = vfio_lock_acct(dma, 1, true);
if (ret) { if (ret) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册