Check that injecting soft-poison to a dax mapping results in SIGBUS with the expected BUS_MCEERR_AR siginfo data.
Signed-off-by: Dan Williams <[email protected]> --- test/dax-pmd.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 126 insertions(+), 4 deletions(-) diff --git a/test/dax-pmd.c b/test/dax-pmd.c index 65bee6ffe907..abff4f9fd199 100644 --- a/test/dax-pmd.c +++ b/test/dax-pmd.c @@ -12,6 +12,7 @@ */ #include <stdio.h> #include <unistd.h> +#include <setjmp.h> #include <sys/mman.h> #include <linux/mman.h> #include <sys/types.h> @@ -192,15 +193,130 @@ int test_dax_directio(int dax_fd, unsigned long align, void *dax_addr, off_t off return rc; } +static sigjmp_buf sj_env; +static int sig_mcerr_ao, sig_mcerr_ar, sig_count; + +static void sigbus_hdl(int sig, siginfo_t *si, void *ptr) +{ + switch (si->si_code) { + case BUS_MCEERR_AO: + fprintf(stderr, "%s: BUS_MCEERR_AO addr: %p len: %d\n", + __func__, si->si_addr, 1 << si->si_addr_lsb); + sig_mcerr_ao++; + break; + case BUS_MCEERR_AR: + fprintf(stderr, "%s: BUS_MCEERR_AR addr: %p len: %d\n", + __func__, si->si_addr, 1 << si->si_addr_lsb); + sig_mcerr_ar++; + break; + default: + sig_count++; + break; + } + + siglongjmp(sj_env, 1); +} + +static int test_dax_poison(int dax_fd, unsigned long align, void *dax_addr, + off_t offset) +{ + unsigned char *addr = MAP_FAILED; + struct sigaction act; + unsigned x = x; + void *buf; + int rc; + + if (posix_memalign(&buf, 4096, 4096) != 0) + return -ENOMEM; + + memset(&act, 0, sizeof(act)); + act.sa_sigaction = sigbus_hdl; + act.sa_flags = SA_SIGINFO; + + if (sigaction(SIGBUS, &act, 0)) { + fail(); + rc = -errno; + goto out; + } + + /* dirty the block on disk to bypass the default zero page */ + rc = pwrite(dax_fd, buf, 4096, offset + align / 2); + if (rc < 4096) { + fail(); + rc = -ENXIO; + goto out; + } + fsync(dax_fd); + + addr = mmap(dax_addr, 2*align, PROT_READ|PROT_WRITE, + MAP_SHARED_VALIDATE|MAP_POPULATE|MAP_SYNC, dax_fd, offset); + if (addr == MAP_FAILED) { + fail(); + rc = -errno; + goto out; + } + + if (sigsetjmp(sj_env, 1)) { + if (sig_mcerr_ar) { + fprintf(stderr, "madvise triggered 'action required' sigbus\n"); + goto clear_error; + } else if (sig_count) { + fail(); + return -ENXIO; + } + } + + rc = madvise(addr + align / 2, 4096, MADV_HWPOISON); + if (rc) { + fail(); + rc = -errno; + goto out; + } + + /* clear the error */ +clear_error: + if (!sig_mcerr_ar) { + fail(); + rc = -ENXIO; + goto out; + } + + rc = fallocate(dax_fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, + offset + align / 2, 4096); + if (rc) { + fail(); + rc = -errno; + goto out; + } + + rc = pwrite(dax_fd, buf, 4096, offset + align / 2); + if (rc < 4096) { + fail(); + rc = -ENXIO; + goto out; + } + fsync(dax_fd); + + /* check that we can fault in the poison page */ + x = *(volatile unsigned *) addr + align / 2; + rc = 0; + +out: + if (addr != MAP_FAILED) + munmap(addr, 2 * align); + free(buf); + return rc; +} + /* test_pmd assumes that fd references a pre-allocated + dax-capable file */ static int test_pmd(int fd) { - unsigned long long m_align, p_align; + unsigned long long m_align, p_align, pmd_off; struct fiemap_extent *ext; + void *base, *pmd_addr; struct fiemap *map; int rc = -ENXIO; unsigned long i; - void *base; if (fd < 0) { fail(); @@ -249,9 +365,15 @@ static int test_pmd(int fd) m_align = ALIGN(base, HPAGE_SIZE) - ((unsigned long) base); p_align = ALIGN(ext->fe_physical, HPAGE_SIZE) - ext->fe_physical; - rc = test_dax_directio(fd, HPAGE_SIZE, (char *) base + m_align, - ext->fe_logical + p_align); + pmd_addr = (char *) base + m_align; + pmd_off = ext->fe_logical + p_align; + rc = test_dax_directio(fd, HPAGE_SIZE, pmd_addr, pmd_off); + if (rc) + goto err_directio; + + rc = test_dax_poison(fd, HPAGE_SIZE, pmd_addr, pmd_off); + err_directio: err_extent: err_mmap: free(map); _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
