@@ -39,5 +39,6 @@ ndctl_SOURCES += ../test/libndctl.c \
../util/sysfs.c \
../test/dpa-alloc.c \
../test/parent-uuid.c \
+ ../test/multi-pmem.c \
../test/core.c
endif
@@ -62,5 +62,8 @@ int cmd_test(int argc, const char **argv, struct ndctl_ctx *ctx)
rc = test_parent_uuid(loglevel, test, ctx);
fprintf(stderr, "test-parent-uuid: %s\n", result(rc));
+ rc = test_multi_pmem(loglevel, test, ctx);
+ fprintf(stderr, "test-multi-pmem: %s\n", result(rc));
+
return ndctl_test_result(test, rc);
}
@@ -16,6 +16,7 @@ void builtin_xaction_namespace_reset(void);
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, 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);
@@ -5,6 +5,7 @@ TESTS =\
dsm-fail \
dpa-alloc \
parent-uuid \
+ multi-pmem \
create.sh \
clear.sh \
dax-errors.sh
@@ -14,6 +15,7 @@ check_PROGRAMS =\
dsm-fail \
dpa-alloc \
parent-uuid \
+ multi-pmem \
dax-errors
if ENABLE_DESTRUCTIVE
@@ -78,3 +80,13 @@ device_dax_LDADD = \
$(LIBNDCTL_LIB) \
$(JSON_LIBS) \
../libutil.a
+
+multi_pmem_SOURCES = \
+ multi-pmem.c \
+ core.c \
+ ../ndctl/builtin-xaction-namespace.c \
+ ../ndctl/util/json.c
+multi_pmem_LDADD = \
+ $(LIBNDCTL_LIB) \
+ $(JSON_LIBS) \
+ ../libutil.a
new file mode 100644
@@ -0,0 +1,272 @@
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <libkmod.h>
+#include <uuid/uuid.h>
+#include <sys/types.h>
+#include <util/size.h>
+#include <linux/falloc.h>
+#include <linux/version.h>
+#include <ndctl/libndctl.h>
+#include <ccan/array_size/array_size.h>
+
+#ifdef HAVE_NDCTL_H
+#include <linux/ndctl.h>
+#else
+#include <ndctl.h>
+#endif
+
+#include <ndctl/builtin.h>
+#include <test.h>
+
+#define NUM_NAMESPACES 4
+#define SZ_NAMESPACE SZ_16M
+
+static int setup_namespace(struct ndctl_region *region)
+{
+ struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
+ const char *argv[] = {
+ "__func__", "-v", "-m", "raw", "-s", "16M", "-r", "",
+ };
+ int argc = ARRAY_SIZE(argv);
+
+ argv[argc - 1] = ndctl_region_get_devname(region);
+ builtin_xaction_namespace_reset();
+ return cmd_create_namespace(argc, argv, ctx);
+}
+
+static void destroy_namespace(struct ndctl_namespace *ndns)
+{
+ struct ndctl_ctx *ctx = ndctl_namespace_get_ctx(ndns);
+ const char *argv[] = {
+ "__func__", "-v", "-f", "",
+ };
+ int argc = ARRAY_SIZE(argv);
+
+ argv[argc - 1] = ndctl_namespace_get_devname(ndns);
+ builtin_xaction_namespace_reset();
+ cmd_destroy_namespace(argc, argv, ctx);
+}
+
+static int do_multi_pmem(struct ndctl_ctx *ctx, struct ndctl_test *test)
+{
+ int i;
+ char devname[100];
+ struct ndctl_bus *bus;
+ uuid_t uuid[NUM_NAMESPACES];
+ struct ndctl_namespace *ndns;
+ struct ndctl_dimm *dimm_target, *dimm;
+ struct ndctl_region *region, *target = NULL;
+ struct ndctl_namespace *namespaces[NUM_NAMESPACES];
+ unsigned long long blk_avail, blk_avail_orig, expect;
+
+ if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
+ ndctl_test_skip(test);
+ return 77;
+ }
+
+ bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");
+ if (!bus)
+ return -ENXIO;
+
+ /* 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) {
+ int rc = ndctl_dimm_zero_labels(dimm);
+
+ if (rc < 0) {
+ fprintf(stderr, "failed to zero %s\n",
+ ndctl_dimm_get_devname(dimm));
+ return rc;
+ }
+ }
+
+ /*
+ * Set regions back to their default state and find our target
+ * region.
+ */
+ ndctl_region_foreach(bus, region) {
+ ndctl_region_enable(region);
+ if (ndctl_region_get_available_size(region)
+ == SZ_NAMESPACE * NUM_NAMESPACES)
+ target = region;
+ }
+
+ if (!target) {
+ fprintf(stderr, "multi-pmem: failed to find target region\n");
+ return -ENXIO;
+ }
+ region = target;
+
+ for (i = 0; i < (int) ARRAY_SIZE(uuid); i++) {
+ if (setup_namespace(region) != 0) {
+ fprintf(stderr, "multi-pmem: failed to setup namespace: %d\n", i);
+ return -ENXIO;
+ }
+ sprintf(devname, "namespace%d.%d",
+ ndctl_region_get_id(region), i);
+ ndctl_namespace_foreach(region, ndns)
+ if (strcmp(ndctl_namespace_get_devname(ndns), devname) == 0
+ && ndctl_namespace_is_enabled(ndns))
+ break;
+ if (!ndns) {
+ fprintf(stderr, "multi-pmem: failed to find namespace: %s\n",
+ devname);
+ return -ENXIO;
+ }
+ ndctl_namespace_get_uuid(ndns, uuid[i]);
+ }
+
+ /* bounce the region and verify everything came back as expected */
+ ndctl_region_disable_invalidate(region);
+ ndctl_region_enable(region);
+
+ for (i = 0; i < (int) ARRAY_SIZE(uuid); i++) {
+ char uuid_str1[40], uuid_str2[40];
+ uuid_t uuid_check;
+
+ ndctl_namespace_foreach(region, ndns)
+ sprintf(devname, "namespace%d.%d",
+ ndctl_region_get_id(region), i);
+ ndctl_namespace_foreach(region, ndns)
+ if (strcmp(ndctl_namespace_get_devname(ndns), devname) == 0
+ && ndctl_namespace_is_enabled(ndns))
+ break;
+ if (!ndns) {
+ fprintf(stderr, "multi-pmem: failed to restore namespace: %s\n",
+ devname);
+ return -ENXIO;
+ }
+
+ ndctl_namespace_get_uuid(ndns, uuid_check);
+ uuid_unparse(uuid_check, uuid_str2);
+ uuid_unparse(uuid[i], uuid_str1);
+ if (uuid_compare(uuid_check, uuid[i]) != 0) {
+ fprintf(stderr, "multi-pmem: expected uuid[%d]: %s, got %s\n",
+ i, uuid_str1, uuid_str2);
+ return -ENXIO;
+ }
+ namespaces[i] = ndns;
+ }
+
+ /*
+ * Check that aliased blk capacity does not increase until the
+ * highest dpa pmem-namespace is deleted.
+ */
+ dimm_target = ndctl_region_get_first_dimm(region);
+ if (!dimm_target) {
+ fprintf(stderr, "multi-pmem: failed to retrieve dimm from %s\n",
+ ndctl_region_get_devname(region));
+ return -ENXIO;
+ }
+
+ dimm = NULL;
+ ndctl_region_foreach(bus, region) {
+ if (ndctl_region_get_type(region) != ND_DEVICE_REGION_BLK)
+ continue;
+ ndctl_dimm_foreach_in_region(region, dimm)
+ if (dimm == dimm_target)
+ break;
+ if (dimm)
+ break;
+ }
+
+ blk_avail_orig = ndctl_region_get_available_size(region);
+ for (i = 1; i < NUM_NAMESPACES - 1; i++) {
+ ndns = namespaces[i];
+ sprintf(devname, "%s", ndctl_namespace_get_devname(ndns));
+ destroy_namespace(ndns);
+ blk_avail = ndctl_region_get_available_size(region);
+ if (blk_avail != blk_avail_orig) {
+ fprintf(stderr, "multi-pmem: destroy %s %llx avail, expect %llx\n",
+ devname, blk_avail, blk_avail_orig);
+ return -ENXIO;
+ }
+ }
+
+ ndns = namespaces[NUM_NAMESPACES - 1];
+ sprintf(devname, "%s", ndctl_namespace_get_devname(ndns));
+ destroy_namespace(ndns);
+ blk_avail = ndctl_region_get_available_size(region);
+ expect = (SZ_NAMESPACE / ndctl_region_get_interleave_ways(target))
+ * (NUM_NAMESPACES - 1) + blk_avail_orig;
+ if (blk_avail != expect) {
+ fprintf(stderr, "multi-pmem: destroy %s %llx avail, expect %llx\n",
+ devname, blk_avail, expect);
+ return -ENXIO;
+ }
+
+ ndctl_bus_foreach(ctx, bus) {
+ if (strncmp(ndctl_bus_get_provider(bus), "nfit_test", 9) != 0)
+ continue;
+ ndctl_region_foreach(bus, region)
+ ndctl_region_disable_invalidate(region);
+ }
+
+ return 0;
+}
+
+int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
+{
+ struct kmod_module *mod;
+ struct kmod_ctx *kmod_ctx;
+ int err, result = EXIT_FAILURE;
+
+ if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
+ return 77;
+
+ 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;
+ }
+
+ result = do_multi_pmem(ctx, test);
+ 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_multi_pmem(LOG_DEBUG, test, ctx);
+ ndctl_unref(ctx);
+ return ndctl_test_result(test, rc);
+}
@@ -5,6 +5,8 @@
#define SZ_1M 0x00100000
#define SZ_2M 0x00200000
#define SZ_4M 0x00400000
+#define SZ_16M 0x01000000
+#define SZ_64M 0x04000000
#define SZ_1G 0x40000000
#define SZ_1T 0x10000000000ULL
Create multiple pmem namespaces in a region and check that the same namespaces return in the same order after a region disable/enable event. Also, check that the highest BLK capacity is limited to the dimm-physical-address space after the highest PMEM allocation. Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- ndctl/Makefile.am | 1 ndctl/builtin-test.c | 3 + test.h | 1 test/Makefile.am | 12 ++ test/multi-pmem.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++ util/size.h | 2 6 files changed, 291 insertions(+) create mode 100644 test/multi-pmem.c