diff options
| author | Dave Jiang <dave.jiang@intel.com> | 2017-03-10 15:24:22 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-03-30 03:41:27 -0400 |
| commit | eae72468c45d827484a2c0980a519f5220b1985c (patch) | |
| tree | 5b964ad7baf29975a8c6e4094120e15d0ebffc58 | |
| parent | 81ec3dc1de0af47a4f38a276f68f55f4e7e8e621 (diff) | |
device-dax: fix pmd/pte fault fallback handling
commit 0134ed4fb9e78672ee9f7b18007114404c81e63f upstream.
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.
Fixes: dee410792419 ("/dev/dax, core: file operations and dax-mmap")
Cc: <stable@vger.kernel.org>
Reported-by: Jeff Moyer <jmoyer@redhat.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | drivers/dax/dax.c | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 286447a83dab..152552d2c306 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c | |||
| @@ -334,6 +334,7 @@ static int __dax_dev_fault(struct dax_dev *dax_dev, struct vm_area_struct *vma, | |||
| 334 | int rc = VM_FAULT_SIGBUS; | 334 | int rc = VM_FAULT_SIGBUS; |
| 335 | phys_addr_t phys; | 335 | phys_addr_t phys; |
| 336 | pfn_t pfn; | 336 | pfn_t pfn; |
| 337 | unsigned int fault_size = PAGE_SIZE; | ||
| 337 | 338 | ||
| 338 | if (check_vma(dax_dev, vma, __func__)) | 339 | if (check_vma(dax_dev, vma, __func__)) |
| 339 | return VM_FAULT_SIGBUS; | 340 | return VM_FAULT_SIGBUS; |
| @@ -344,6 +345,9 @@ static int __dax_dev_fault(struct dax_dev *dax_dev, struct vm_area_struct *vma, | |||
| 344 | return VM_FAULT_SIGBUS; | 345 | return VM_FAULT_SIGBUS; |
| 345 | } | 346 | } |
| 346 | 347 | ||
| 348 | if (fault_size != dax_region->align) | ||
| 349 | return VM_FAULT_SIGBUS; | ||
| 350 | |||
| 347 | phys = pgoff_to_phys(dax_dev, vmf->pgoff, PAGE_SIZE); | 351 | phys = pgoff_to_phys(dax_dev, vmf->pgoff, PAGE_SIZE); |
| 348 | if (phys == -1) { | 352 | if (phys == -1) { |
| 349 | dev_dbg(dev, "%s: phys_to_pgoff(%#lx) failed\n", __func__, | 353 | dev_dbg(dev, "%s: phys_to_pgoff(%#lx) failed\n", __func__, |
| @@ -389,6 +393,7 @@ static int __dax_dev_pmd_fault(struct dax_dev *dax_dev, | |||
| 389 | phys_addr_t phys; | 393 | phys_addr_t phys; |
| 390 | pgoff_t pgoff; | 394 | pgoff_t pgoff; |
| 391 | pfn_t pfn; | 395 | pfn_t pfn; |
| 396 | unsigned int fault_size = PMD_SIZE; | ||
| 392 | 397 | ||
| 393 | if (check_vma(dax_dev, vma, __func__)) | 398 | if (check_vma(dax_dev, vma, __func__)) |
| 394 | return VM_FAULT_SIGBUS; | 399 | return VM_FAULT_SIGBUS; |
| @@ -405,6 +410,16 @@ static int __dax_dev_pmd_fault(struct dax_dev *dax_dev, | |||
| 405 | return VM_FAULT_SIGBUS; | 410 | return VM_FAULT_SIGBUS; |
| 406 | } | 411 | } |
| 407 | 412 | ||
| 413 | if (fault_size < dax_region->align) | ||
| 414 | return VM_FAULT_SIGBUS; | ||
| 415 | else if (fault_size > dax_region->align) | ||
| 416 | return VM_FAULT_FALLBACK; | ||
| 417 | |||
| 418 | /* if we are outside of the VMA */ | ||
| 419 | if (pmd_addr < vma->vm_start || | ||
| 420 | (pmd_addr + PMD_SIZE) > vma->vm_end) | ||
| 421 | return VM_FAULT_SIGBUS; | ||
| 422 | |||
| 408 | pgoff = linear_page_index(vma, pmd_addr); | 423 | pgoff = linear_page_index(vma, pmd_addr); |
| 409 | phys = pgoff_to_phys(dax_dev, pgoff, PMD_SIZE); | 424 | phys = pgoff_to_phys(dax_dev, pgoff, PMD_SIZE); |
| 410 | if (phys == -1) { | 425 | if (phys == -1) { |
