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

Reply via email to