The s390 MMIO syscalls when using the classic PCI instructions do not cause a page fault when follow_pte() fails due to the page not being present. Besides being a general deficiency this breaks vfio-pci's mmap() handling once VFIO_PCI_MMAP gets enabled as this lazily maps on first access. Fix this by following a failed follow_pte() with fixup_user_page() and retrying the follow_pte(). Reviewed-by: Jason Gunthorpe <jgg@xxxxxxxxxx> Reviewed-by: Matthew Rosato <mjrosato@xxxxxxxxxxxxx> Signed-off-by: Niklas Schnelle <schnelle@xxxxxxxxxxxxx> --- arch/s390/pci/pci_mmio.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c index 5398729bfe1b..80c21b1a101c 100644 --- a/arch/s390/pci/pci_mmio.c +++ b/arch/s390/pci/pci_mmio.c @@ -170,8 +170,12 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr, goto out_unlock_mmap; ret = follow_pte(vma, mmio_addr, &ptep, &ptl); - if (ret) - goto out_unlock_mmap; + if (ret) { + fixup_user_fault(current->mm, mmio_addr, FAULT_FLAG_WRITE, NULL); + ret = follow_pte(vma, mmio_addr, &ptep, &ptl); + if (ret) + goto out_unlock_mmap; + } io_addr = (void __iomem *)((pte_pfn(*ptep) << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); @@ -305,12 +309,16 @@ SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr, if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) goto out_unlock_mmap; ret = -EACCES; - if (!(vma->vm_flags & VM_WRITE)) + if (!(vma->vm_flags & VM_READ)) goto out_unlock_mmap; ret = follow_pte(vma, mmio_addr, &ptep, &ptl); - if (ret) - goto out_unlock_mmap; + if (ret) { + fixup_user_fault(current->mm, mmio_addr, 0, NULL); + ret = follow_pte(vma, mmio_addr, &ptep, &ptl); + if (ret) + goto out_unlock_mmap; + } io_addr = (void __iomem *)((pte_pfn(*ptep) << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); -- 2.40.1