Jeff Moyer reports that:
"
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.

[ 4614.138357] dax dax1.0: dax_open
[ 4614.154838] dax dax1.0: dax_mmap
[ 4614.171898] dax dax1.0: dax_dev_huge_fault: fio: write (0x7f08f0a00000 - 
0x7f0ce0800000)
[ 4614.211720] dax dax1.0: __dax_dev_pud_fault: phys_to_pgoff(0xffffffffcf600) 
failed
[ 4614.568911] 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
"

It looks like the code does not fallback at all when handling faults. The
fault handlers are missing some boundary checking for the VMA. Also, we need
to fall back if the alignment requested is less than the P-entry size.

Reported-by: Jeff Moyer <[email protected]>
Signed-off-by: Dave Jiang <[email protected]>
---
 drivers/dax/dax.c |   22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c
index 174690a..5c7998e 100644
--- a/drivers/dax/dax.c
+++ b/drivers/dax/dax.c
@@ -480,12 +480,21 @@ static int __dax_dev_pmd_fault(struct dax_dev *dax_dev, 
struct vm_fault *vmf)
                return VM_FAULT_SIGBUS;
        }
 
+       /* fall back if we are outside of the VMA */
+       if (pmd_addr < vmf->vma->vm_start)
+               return VM_FAULT_FALLBACK;
+       if ((pmd_addr + PMD_SIZE) > vmf->vma->vm_end)
+               return VM_FAULT_FALLBACK;
+
+       if (dax_region->align < PMD_SIZE)
+               return VM_FAULT_FALLBACK;
+
        pgoff = linear_page_index(vmf->vma, pmd_addr);
        phys = pgoff_to_phys(dax_dev, pgoff, PMD_SIZE);
        if (phys == -1) {
                dev_dbg(dev, "%s: pgoff_to_phys(%#lx) failed\n", __func__,
                                pgoff);
-               return VM_FAULT_SIGBUS;
+               return VM_FAULT_FALLBACK;
        }
 
        pfn = phys_to_pfn_t(phys, dax_region->pfn_flags);
@@ -519,12 +528,21 @@ static int __dax_dev_pud_fault(struct dax_dev *dax_dev, 
struct vm_fault *vmf)
                return VM_FAULT_SIGBUS;
        }
 
+       /* fall back if we are outside of the VMA */
+       if (pud_addr < vmf->vma->vm_start)
+               return VM_FAULT_FALLBACK;
+       if ((pud_addr + PUD_SIZE) > vmf->vma->vm_end)
+               return VM_FAULT_FALLBACK;
+
+       if (dax_region->align < PUD_SIZE)
+               return VM_FAULT_FALLBACK;
+
        pgoff = linear_page_index(vmf->vma, pud_addr);
        phys = pgoff_to_phys(dax_dev, pgoff, PUD_SIZE);
        if (phys == -1) {
                dev_dbg(dev, "%s: pgoff_to_phys(%#lx) failed\n", __func__,
                                pgoff);
-               return VM_FAULT_SIGBUS;
+               return VM_FAULT_FALLBACK;
        }
 
        pfn = phys_to_pfn_t(phys, dax_region->pfn_flags);

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

Reply via email to