Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70b085b0 authored by Dave Jiang's avatar Dave Jiang Committed by Dan Williams
Browse files

device-dax: fix pud fault fallback handling



Jeff Moyer reports:

    With a device dax alignment of 4KB or 2MB, I get sigbus when running
    the attached fio job file for the current kernel (4.11.0-rc1+).  If
    I specify an alignment of 1GB, it works.

    I turned on debug output, and saw that it was failing in the huge
    fault code.

     dax dax1.0: dax_open
     dax dax1.0: dax_mmap
     dax dax1.0: dax_dev_huge_fault: fio: write (0x7f08f0a00000 -
     dax dax1.0: __dax_dev_pud_fault: phys_to_pgoff(0xffffffffcf60)
     dax dax1.0: dax_release

    fio config for reproduce:
    [global]
    ioengine=dev-dax
    direct=0
    filename=/dev/dax0.0
    bs=2m

    [write]
    rw=write

    [read]
    stonewall
    rw=read

The driver fails to fallback when taking a fault that is larger than
the device alignment, or handling a larger fault when a smaller
mapping is already established. While we could support larger
mappings for a device with a smaller alignment, that change is
too large for the immediate fix. The simplest change is to force
fallback until the fault size matches the alignment.

Reported-by: default avatarJeff Moyer <jmoyer@redhat.com>
Signed-off-by: default avatarDave Jiang <dave.jiang@intel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 0134ed4f
Loading
Loading
Loading
Loading
+12 −0
Original line number Original line Diff line number Diff line
@@ -518,6 +518,8 @@ static int __dax_dev_pud_fault(struct dax_dev *dax_dev, struct vm_fault *vmf)
	phys_addr_t phys;
	phys_addr_t phys;
	pgoff_t pgoff;
	pgoff_t pgoff;
	pfn_t pfn;
	pfn_t pfn;
	unsigned int fault_size = PUD_SIZE;



	if (check_vma(dax_dev, vmf->vma, __func__))
	if (check_vma(dax_dev, vmf->vma, __func__))
		return VM_FAULT_SIGBUS;
		return VM_FAULT_SIGBUS;
@@ -534,6 +536,16 @@ static int __dax_dev_pud_fault(struct dax_dev *dax_dev, struct vm_fault *vmf)
		return VM_FAULT_SIGBUS;
		return VM_FAULT_SIGBUS;
	}
	}


	if (fault_size < dax_region->align)
		return VM_FAULT_SIGBUS;
	else if (fault_size > dax_region->align)
		return VM_FAULT_FALLBACK;

	/* if we are outside of the VMA */
	if (pud_addr < vmf->vma->vm_start ||
			(pud_addr + PUD_SIZE) > vmf->vma->vm_end)
		return VM_FAULT_SIGBUS;

	pgoff = linear_page_index(vmf->vma, pud_addr);
	pgoff = linear_page_index(vmf->vma, pud_addr);
	phys = pgoff_to_phys(dax_dev, pgoff, PUD_SIZE);
	phys = pgoff_to_phys(dax_dev, pgoff, PUD_SIZE);
	if (phys == -1) {
	if (phys == -1) {