We expect that if the dimm driver fails to enable then any label-data-dependent regions/namespaces will also fail to enable.
Signed-off-by: Dan Williams <dan.j.willi...@intel.com> --- ndctl/Makefile.am | 3 + ndctl/builtin-test.c | 5 + test.h | 1 test/Makefile.am | 10 ++ test/dsm-fail.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 239 insertions(+) create mode 100644 test/dsm-fail.c diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am index f6cd3f1c235b..63f387b58de9 100644 --- a/ndctl/Makefile.am +++ b/ndctl/Makefile.am @@ -34,6 +34,9 @@ ndctl_LDADD =\ if ENABLE_TEST ndctl_SOURCES += ../test/libndctl.c \ + ../test/dsm-fail.c \ + ../util/log.c \ + ../util/sysfs.c \ ../test/dpa-alloc.c \ ../test/parent-uuid.c \ ../test/core.c diff --git a/ndctl/builtin-test.c b/ndctl/builtin-test.c index d9c5b0f28d6e..d8539a133d10 100644 --- a/ndctl/builtin-test.c +++ b/ndctl/builtin-test.c @@ -49,6 +49,11 @@ int cmd_test(int argc, const char **argv, struct ndctl_ctx *ctx) if (rc && rc != 77) return rc; + rc = test_dsm_fail(loglevel, test, ctx); + fprintf(stderr, "test-dsm-fail: %s\n", result(rc)); + if (rc && rc != 77) + return rc; + rc = test_dpa_alloc(loglevel, test, ctx); fprintf(stderr, "test-dpa-alloc: %s\n", result(rc)); if (rc && rc != 77) diff --git a/test.h b/test.h index 2940ac0f7396..bf708f38bfbf 100644 --- a/test.h +++ b/test.h @@ -18,6 +18,7 @@ struct ndctl_ctx; int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx); int test_dax_directio(int dax_fd, void *dax_addr, off_t offset); 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); int test_blk_namespaces(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx); int test_pmem_namespaces(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx); diff --git a/test/Makefile.am b/test/Makefile.am index f0240fe5883a..5513f429869f 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -2,6 +2,7 @@ include $(top_srcdir)/Makefile.am.in TESTS =\ libndctl \ + dsm-fail \ dpa-alloc \ parent-uuid \ create.sh \ @@ -10,6 +11,7 @@ TESTS =\ check_PROGRAMS =\ libndctl \ + dsm-fail \ dpa-alloc \ parent-uuid \ dax-errors @@ -39,6 +41,14 @@ LIBNDCTL_LIB =\ libndctl_SOURCES = libndctl.c core.c libndctl_LDADD = $(LIBNDCTL_LIB) $(UUID_LIBS) $(KMOD_LIBS) +dsm_fail_SOURCES =\ + dsm-fail.c \ + core.c \ + ../util/log.c \ + ../util/sysfs.c + +dsm_fail_LDADD = $(LIBNDCTL_LIB) $(KMOD_LIBS) + blk_ns_SOURCES = blk_namespaces.c core.c blk_ns_LDADD = $(LIBNDCTL_LIB) $(KMOD_LIBS) diff --git a/test/dsm-fail.c b/test/dsm-fail.c new file mode 100644 index 000000000000..ca80cef79092 --- /dev/null +++ b/test/dsm-fail.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2014-2016, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU Lesser General Public License, + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + */ +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <syslog.h> +#include <libkmod.h> +#include <util/log.h> +#include <util/sysfs.h> +#include <linux/version.h> + +#include <ccan/array_size/array_size.h> +#include <ndctl/libndctl.h> +#ifdef HAVE_NDCTL_H +#include <linux/ndctl.h> +#else +#include <ndctl.h> +#endif +#include <test.h> + +#define DIMM_PATH "/sys/devices/platform/nfit_test.0/nfit_test_dimm/test_dimm0" + +static void reset_bus(struct ndctl_bus *bus) +{ + struct ndctl_region *region; + struct ndctl_dimm *dimm; + + /* disable all regions so that set_config_data commands are permitted */ + ndctl_region_foreach(bus, region) + ndctl_region_disable_invalidate(region); + + ndctl_dimm_foreach(bus, dimm) + ndctl_dimm_zero_labels(dimm); + + /* set regions back to their default state */ + ndctl_region_foreach(bus, region) + ndctl_region_enable(region); +} + +static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test) +{ + struct ndctl_bus *bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0"); + struct ndctl_dimm *dimm, *victim = NULL; + char path[1024], buf[SYSFS_ATTR_SIZE]; + struct ndctl_region *region; + struct log_ctx log_ctx; + unsigned int handle; + int rc, err = 0; + + if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0))) + return 77; + + if (!bus) + return -ENXIO; + + log_init(&log_ctx, "test/dsm-fail", "NDCTL_TEST"); + + ndctl_bus_wait_probe(bus); + + /* disable all regions so that we can disable a dimm */ + ndctl_region_foreach(bus, region) + ndctl_region_disable_invalidate(region); + + sprintf(path, "%s/handle", DIMM_PATH); + rc = __sysfs_read_attr(&log_ctx, path, buf); + if (rc) { + fprintf(stderr, "failed to retrieve test dimm handle\n"); + return -ENXIO; + } + + handle = strtoul(buf, NULL, 0); + + ndctl_dimm_foreach(bus, dimm) { + if (ndctl_dimm_get_handle(dimm) == handle) + victim = dimm; + + if (ndctl_dimm_disable(dimm)) { + fprintf(stderr, "failed to disable: %s\n", + ndctl_dimm_get_devname(dimm)); + return -ENXIO; + } + } + + if (!victim) { + fprintf(stderr, "failed to find victim dimm\n"); + return -ENXIO; + } + fprintf(stderr, "victim: %s\n", ndctl_dimm_get_devname(victim)); + + sprintf(path, "%s/fail_cmd", DIMM_PATH); + sprintf(buf, "%#x\n", 1 << ND_CMD_GET_CONFIG_SIZE); + rc = __sysfs_write_attr(&log_ctx, path, buf); + if (rc) { + fprintf(stderr, "failed to set fail cmd mask\n"); + return -ENXIO; + } + + ndctl_dimm_foreach(bus, dimm) { + rc = ndctl_dimm_enable(dimm); + fprintf(stderr, "dimm: %s enable: %d\n", + ndctl_dimm_get_devname(dimm), rc); + if ((rc == 0) == (dimm == victim)) { + fprintf(stderr, "fail expected %s enable %s victim: %s\n", + ndctl_dimm_get_devname(dimm), + (dimm == victim) ? "failure" : "success", + ndctl_dimm_get_devname(victim)); + err = -ENXIO; + goto out; + } + } + + ndctl_region_foreach(bus, region) { + bool has_victim = false; + + ndctl_dimm_foreach_in_region(region, dimm) { + if (dimm == victim) { + has_victim = true; + break; + } + } + + rc = ndctl_region_enable(region); + fprintf(stderr, "region: %s enable: %d has_victim: %d\n", + ndctl_region_get_devname(region), rc, has_victim); + if ((rc == 0) == has_victim) { + fprintf(stderr, "fail expected %s enable %s with %s disabled\n", + ndctl_region_get_devname(region), + has_victim ? "failure" : "success", + ndctl_dimm_get_devname(victim)); + err = -ENXIO; + goto out; + } + } + + out: + sprintf(buf, "0\n"); + rc = __sysfs_write_attr(&log_ctx, path, buf); + if (rc) { + fprintf(stderr, "%s: failed to clear fail_cmd mask\n", + ndctl_dimm_get_devname(victim)); + err = -ENXIO; + } + rc = ndctl_dimm_enable(victim); + if (rc) { + fprintf(stderr, "failed to enable victim: %s after clearing error\n", + ndctl_dimm_get_devname(victim)); + err = -ENXIO; + } + reset_bus(bus); + + return err; +} + +int test_dsm_fail(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx) +{ + struct kmod_module *mod; + struct kmod_ctx *kmod_ctx; + int result = EXIT_FAILURE, err; + + ndctl_set_log_priority(ctx, loglevel); + kmod_ctx = kmod_new(NULL, NULL); + if (!kmod_ctx) + return result; + kmod_set_log_priority(kmod_ctx, loglevel); + + err = kmod_module_new_from_name(kmod_ctx, "nfit_test", &mod); + if (err < 0) + goto err_module; + + err = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, + NULL, NULL, NULL, NULL); + if (err < 0) { + result = 77; + ndctl_test_skip(test); + fprintf(stderr, "%s unavailable skipping tests\n", + "nfit_test"); + goto err_module; + } + + if (do_test(ctx, test) == 0) + result = EXIT_SUCCESS; + + kmod_module_remove_module(mod, 0); + + err_module: + kmod_unref(kmod_ctx); + return result; +} + +int __attribute__((weak)) main(int argc, char *argv[]) +{ + struct ndctl_test *test = ndctl_test_new(0); + struct ndctl_ctx *ctx; + int rc; + + if (!test) { + fprintf(stderr, "failed to initialize test\n"); + return EXIT_FAILURE; + } + + rc = ndctl_new(&ctx); + if (rc) + return ndctl_test_result(test, rc); + rc = test_dsm_fail(LOG_DEBUG, test, ctx); + ndctl_unref(ctx); + return ndctl_test_result(test, rc); +} _______________________________________________ Linux-nvdimm mailing list Linux-nvdimm@lists.01.org https://lists.01.org/mailman/listinfo/linux-nvdimm