@@ -102,6 +102,11 @@ AS_IF([test "x$enable_test" = "xyes"],
[AC_DEFINE([ENABLE_TEST], [1], [ndctl test support])])
AM_CONDITIONAL([ENABLE_TEST], [test "x$enable_test" = "xyes"])
+AC_CHECK_DECLS([BUS_MCEERR_AR], [enable_poison=yes], [], [[#include <signal.h>]])
+AS_IF([test "x$enable_poison" = "xyes"],
+ [AC_DEFINE([ENABLE_POISON], [1], [ndctl test poison support])])
+AM_CONDITIONAL([ENABLE_POISON], [test "x$enable_poison" = "xyes"])
+
PKG_CHECK_MODULES([KMOD], [libkmod])
PKG_CHECK_MODULES([UDEV], [libudev])
PKG_CHECK_MODULES([UUID], [uuid])
@@ -38,8 +38,16 @@ struct ndctl_ctx;
int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
int test_dax_directio(int dax_fd, unsigned long align, void *dax_addr, off_t offset);
+#ifdef ENABLE_POISON
int test_dax_poison(int dax_fd, unsigned long align, void *dax_addr,
off_t offset, bool fsdax);
+#else
+static inline int test_dax_poison(int dax_fd, unsigned long align,
+ void *dax_addr, off_t offset, bool fsdax)
+{
+ return 0;
+}
+#endif
int test_dpa_alloc(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
int test_dsm_fail(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
int test_libndctl(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
@@ -97,6 +97,7 @@ dax_dev_LDADD = $(LIBNDCTL_LIB) $(KMOD_LIBS)
dax_pmd_SOURCES = dax-pmd.c
hugetlb_SOURCES = hugetlb.c \
dax-pmd.c
+
mmap_SOURCES = mmap.c
dax_errors_SOURCES = dax-errors.c
daxdev_errors_SOURCES = daxdev-errors.c \
@@ -111,6 +112,13 @@ device_dax_SOURCES = \
../ndctl/namespace.c \
../ndctl/check.c \
../util/json.c
+
+if ENABLE_POISON
+dax_pmd_SOURCES += dax-poison.c
+hugetlb_SOURCES += dax-poison.c
+device_dax_SOURCES += dax-poison.c
+endif
+
device_dax_LDADD = \
$(LIBNDCTL_LIB) \
$(KMOD_LIBS) \
@@ -27,7 +27,6 @@
#include <test.h>
#include <util/size.h>
#include <linux/fiemap.h>
-#include <stdbool.h>
#define NUM_EXTENTS 5
#define fail() fprintf(stderr, "%s: failed at: %d (%s)\n", \
@@ -194,135 +193,6 @@ 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);
-}
-
-int test_dax_poison(int dax_fd, unsigned long align, void *dax_addr,
- off_t offset, bool fsdax)
-{
- unsigned char *addr = MAP_FAILED;
- struct sigaction act;
- unsigned x = x;
- void *buf;
- int rc;
-
- /*
- * MADV_HWPOISON must be page aligned, and this routine assumes
- * align is >= 8K
- */
- if (align < SZ_2M)
- return 0;
-
- 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 */
- if (fsdax) {
- 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;
- }
-
- if (!fsdax) {
- rc = 0;
- 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)
{
new file mode 100644
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2018 Intel Corporation. All rights reserved. */
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/mman.h>
+#include <linux/mman.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <linux/fs.h>
+#include <test.h>
+#include <util/size.h>
+#include <stdbool.h>
+
+#define fail() fprintf(stderr, "%s: failed at: %d (%s)\n", \
+ __func__, __LINE__, strerror(errno))
+
+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);
+}
+
+int test_dax_poison(int dax_fd, unsigned long align, void *dax_addr,
+ off_t offset, bool fsdax)
+{
+ unsigned char *addr = MAP_FAILED;
+ struct sigaction act;
+ unsigned x = x;
+ void *buf;
+ int rc;
+
+ /*
+ * MADV_HWPOISON must be page aligned, and this routine assumes
+ * align is >= 8K
+ */
+ if (align < SZ_2M)
+ return 0;
+
+ 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 */
+ if (fsdax) {
+ 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;
+ }
+
+ if (!fsdax) {
+ rc = 0;
+ 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;
+}
The definition of BUS_MCEERR_AR is not available by default on older glibc releases. Auto-detect this capability and de-feature the MADV_HWPOISON injection tests if the definition is not found. Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- This depends on "test: Add device-dax MADV_HWPOISON test" https://patchwork.kernel.org/patch/10451131/ configure.ac | 5 ++ test.h | 8 +++ test/Makefile.am | 8 +++ test/dax-pmd.c | 130 ---------------------------------------------- test/dax-poison.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 130 deletions(-) create mode 100644 test/dax-poison.c