When dax fault handler fails to provision the fault page due to hwpoison, it returns VM_FAULT_SIGBUS which lead to a sigbus delivered to userspace with .si_code BUS_ADRERR. Channel dax backend driver's detection on hwpoison to the filesystem to provide the precise reason for the fault. Signed-off-by: Jane Chu <jane.chu@xxxxxxxxxx> --- drivers/nvdimm/pmem.c | 2 +- fs/dax.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index ceea55f621cc..46e094e56159 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -260,7 +260,7 @@ __weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff, long actual_nr; if (mode != DAX_RECOVERY_WRITE) - return -EIO; + return -EHWPOISON; /* * Set the recovery stride is set to kernel page size because diff --git a/fs/dax.c b/fs/dax.c index 3e457a16c7d1..3f22686abc88 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -1456,7 +1456,7 @@ static loff_t dax_iomap_iter(const struct iomap_iter *iomi, map_len = dax_direct_access(dax_dev, pgoff, PHYS_PFN(size), DAX_ACCESS, &kaddr, NULL); - if (map_len == -EIO && iov_iter_rw(iter) == WRITE) { + if (map_len == -EHWPOISON && iov_iter_rw(iter) == WRITE) { map_len = dax_direct_access(dax_dev, pgoff, PHYS_PFN(size), DAX_RECOVERY_WRITE, &kaddr, NULL); @@ -1550,11 +1550,21 @@ dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter, } EXPORT_SYMBOL_GPL(dax_iomap_rw); +/* + * Concerning hwpoison triggered page fault: dax is THP, a pmd + * level fault handler will fallback (VM_FAULT_FALLBACK) before + * give up, hence return VM_FAULT_HWPOISON which implies + * corrupted range is PAGE_SIZE. + */ static vm_fault_t dax_fault_return(int error) { if (error == 0) return VM_FAULT_NOPAGE; - return vmf_error(error); + else if (error == -ENOMEM) + return VM_FAULT_OOM; + else if (error == -EHWPOISON) + return VM_FAULT_HWPOISON; + return VM_FAULT_SIGBUS; } /* -- 2.18.4