diff mbox

[05/11] ndctl: add a unit test for parent_uuid verification

Message ID 20150905013143.28464.61557.stgit@dwillia2-desk3.amr.corp.intel.com (mailing list archive)
State Accepted
Commit c2bbd7e0d27b
Headers show

Commit Message

Dan Williams Sept. 5, 2015, 1:31 a.m. UTC
From: Vishal Verma <vishal.l.verma@intel.com>

BTT autodetect should correctly check for the UUID of the parent
namespace, and enable the BTT accordingly. This unit test checks for
both cases, when a BTT should be correctly autodetected and enabled
(matching parent_uuid), and when it shouldn't have been enabled (updated
parent_uuid for the namespace).

Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 Makefile.am            |    9 +-
 builtin-test.c         |    6 +
 lib/test-parent-uuid.c |  282 ++++++++++++++++++++++++++++++++++++++++++++++++
 test-parent-uuid.h     |    4 +
 4 files changed, 298 insertions(+), 3 deletions(-)
 create mode 100644 lib/test-parent-uuid.c
 create mode 100644 test-parent-uuid.h
diff mbox

Patch

diff --git a/Makefile.am b/Makefile.am
index d22e55708474..99ddfaff8ed9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -63,7 +63,7 @@  ndctl_SOURCES = ndctl.c \
 		util/wrapper.c
 
 if ENABLE_TEST
-ndctl_SOURCES += lib/test-libndctl.c lib/test-dpa-alloc.c
+ndctl_SOURCES += lib/test-libndctl.c lib/test-dpa-alloc.c lib/test-parent-uuid.c
 endif
 
 if ENABLE_DESTRUCTIVE
@@ -102,8 +102,8 @@  pkgconfig_DATA = lib/libndctl.pc
 EXTRA_DIST += lib/libndctl.pc.in
 CLEANFILES += lib/libndctl.pc
 
-TESTS = lib/test-libndctl lib/test-dpa-alloc
-check_PROGRAMS = lib/test-libndctl lib/test-dpa-alloc
+TESTS = lib/test-libndctl lib/test-dpa-alloc lib/test-parent-uuid
+check_PROGRAMS = lib/test-libndctl lib/test-dpa-alloc lib/test-parent-uuid
 
 if ENABLE_DESTRUCTIVE
 TESTS += lib/test-blk-ns lib/test-pmem-ns
@@ -121,3 +121,6 @@  lib_test_pmem_ns_LDADD = lib/libndctl.la $(KMOD_LIBS)
 
 lib_test_dpa_alloc_SOURCES = lib/test-dpa-alloc.c
 lib_test_dpa_alloc_LDADD = lib/libndctl.la $(UUID_LIBS) $(KMOD_LIBS)
+
+lib_test_parent_uuid_SOURCES = lib/test-parent-uuid.c
+lib_test_parent_uuid_LDADD = lib/libndctl.la $(UUID_LIBS) $(KMOD_LIBS)
diff --git a/builtin-test.c b/builtin-test.c
index b739924991b9..73a24e0b3c75 100644
--- a/builtin-test.c
+++ b/builtin-test.c
@@ -2,6 +2,7 @@ 
 #include <syslog.h>
 #include <test-libndctl.h>
 #include <test-dpa-alloc.h>
+#include <test-parent-uuid.h>
 #include <util/parse-options.h>
 
 int cmd_test(int argc, const char **argv)
@@ -32,5 +33,10 @@  int cmd_test(int argc, const char **argv)
 
 	rc = test_dpa_alloc(loglevel);
 	fprintf(stderr, "test-dpa-alloc: %s\n", rc ? "FAIL" : "PASS");
+	if (rc)
+		return rc;
+
+	rc = test_parent_uuid(loglevel);
+	fprintf(stderr, "test-parent-uuid: %s\n", rc ? "FAIL" : "PASS");
 	return rc;
 }
diff --git a/lib/test-parent-uuid.c b/lib/test-parent-uuid.c
new file mode 100644
index 000000000000..46e006053e01
--- /dev/null
+++ b/lib/test-parent-uuid.c
@@ -0,0 +1,282 @@ 
+/*
+ * blk_namespaces: tests functionality of multiple block namespaces
+ *
+ * Copyright (c) 2015, 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 <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <syslog.h>
+#include <libkmod.h>
+#include <uuid/uuid.h>
+#include <test-parent-uuid.h>
+
+#include <ndctl/libndctl.h>
+
+#ifdef HAVE_NDCTL_H
+#include <linux/ndctl.h>
+#else
+#include <ndctl.h>
+#endif
+
+
+static const char *NFIT_TEST_MODULE = "nfit_test";
+static const char *PROVIDER = "nfit_test.0";
+
+static struct ndctl_bus *get_bus_by_provider(struct ndctl_ctx *ctx,
+		const char *provider)
+{
+	struct ndctl_bus *bus;
+
+        ndctl_bus_foreach(ctx, bus)
+		if (strcmp(provider, ndctl_bus_get_provider(bus)) == 0)
+			return bus;
+
+	return NULL;
+}
+
+static struct ndctl_btt *get_idle_btt(struct ndctl_region *region)
+{
+	struct ndctl_btt *btt;
+
+	ndctl_btt_foreach(region, btt)
+		if (!ndctl_btt_is_enabled(btt)
+				&& !ndctl_btt_is_configured(btt))
+			return btt;
+	return NULL;
+}
+
+static struct ndctl_namespace *create_blk_namespace(int region_fraction,
+		struct ndctl_region *region, unsigned long long req_size,
+		uuid_t uuid)
+{
+	struct ndctl_namespace *ndns, *seed_ns = NULL;
+	unsigned long long size;
+
+	ndctl_namespace_foreach(region, ndns)
+		if (ndctl_namespace_get_size(ndns) == 0) {
+			seed_ns = ndns;
+			break;
+		}
+
+	if (!seed_ns)
+		return NULL;
+
+	size = ndctl_region_get_size(region)/region_fraction;
+	if (req_size)
+		size = req_size;
+
+	if (ndctl_namespace_set_uuid(seed_ns, uuid) < 0)
+		return NULL;
+
+	if (ndctl_namespace_set_size(seed_ns, size) < 0)
+		return NULL;
+
+	if (ndctl_namespace_set_sector_size(seed_ns, 512) < 0)
+		return NULL;
+
+	if (ndctl_namespace_enable(seed_ns) < 0)
+		return NULL;
+
+	return seed_ns;
+}
+
+static int disable_blk_namespace(struct ndctl_namespace *ndns)
+{
+	if (ndctl_namespace_disable(ndns) < 0)
+		return -ENODEV;
+
+	if (ndctl_namespace_delete(ndns) < 0)
+		return -ENODEV;
+
+	return 0;
+}
+
+static struct ndctl_btt *check_valid_btt(struct ndctl_region *region,
+		struct ndctl_namespace *ndns, uuid_t btt_uuid)
+{
+	struct ndctl_btt *btt = NULL;
+	ndctl_btt_foreach(region, btt) {
+		struct ndctl_namespace *btt_ndns;
+		uuid_t uu;
+
+		ndctl_btt_get_uuid(btt, uu);
+		if (uuid_compare(uu, btt_uuid) != 0)
+			continue;
+		if (!ndctl_btt_is_enabled(btt))
+			continue;
+		btt_ndns = ndctl_btt_get_namespace(btt);
+		if (strcmp(ndctl_namespace_get_devname(btt_ndns),
+				ndctl_namespace_get_devname(ndns)) != 0)
+			continue;
+		return btt;
+	}
+	return NULL;
+}
+
+
+static int do_test(struct ndctl_ctx *ctx)
+{
+	int rc;
+	struct ndctl_bus *bus;
+	struct ndctl_btt *btt, *found = NULL;
+	struct ndctl_region *region, *blk_region;
+	struct ndctl_namespace *ndns;
+	unsigned long long ns_size = 18874368;
+	uuid_t uuid = {0,  1,  2,  3,  4,  5,  6,  7, 8, 9, 10, 11, 12, 13, 14, 16};
+	uuid_t btt_uuid;
+
+	bus = get_bus_by_provider(ctx, PROVIDER);
+	if (!bus) {
+		fprintf(stderr, "failed to find NFIT-provider: %s\n", PROVIDER);
+		rc = -ENODEV;
+		goto err_nobus;
+	}
+
+	ndctl_region_foreach(bus, region)
+		if (ndctl_region_get_nstype(region) == ND_DEVICE_NAMESPACE_BLK) {
+			blk_region = region;
+			break;
+		}
+
+	if (!blk_region) {
+		fprintf(stderr, "failed to find block region\n");
+		rc = -ENODEV;
+		goto err_cleanup;
+	}
+
+	/* create a blk namespace */
+	ndns = create_blk_namespace(1, blk_region, ns_size, uuid);
+	if (!ndns) {
+		fprintf(stderr, "failed to create block namespace\n");
+		goto err_cleanup;
+	}
+
+	/* create a btt for this namespace */
+	uuid_generate(btt_uuid);
+	btt = get_idle_btt(region);
+	if (!btt)
+		return -ENXIO;
+
+	ndctl_btt_set_uuid(btt, btt_uuid);
+	ndctl_btt_set_sector_size(btt, 512);
+	ndctl_btt_set_namespace(btt, ndns);
+	ndctl_namespace_disable(ndns);
+	rc = ndctl_btt_enable(btt);
+	if (rc) {
+		fprintf(stderr, "failed to create btt 0\n");
+		goto err_cleanup;
+	}
+
+	/* disable the btt */
+	ndctl_btt_delete(btt);
+
+	/* re-create the namespace - this should auto-enable the btt */
+	disable_blk_namespace(ndns);
+	ndns = create_blk_namespace(1, blk_region, ns_size, uuid);
+	if (!ndns) {
+		fprintf(stderr, "failed to re-create block namespace\n");
+		goto err_cleanup;
+	}
+
+	/* Verify btt was auto-created */
+	found = check_valid_btt(blk_region, ndns, btt_uuid);
+	if (!found) {
+		rc = -ENXIO;
+		goto err_cleanup;
+	}
+	btt = found;
+
+	/*disable the btt and namespace again */
+	ndctl_btt_delete(btt);
+	disable_blk_namespace(ndns);
+
+	/* recreate the namespace with a different uuid */
+	uuid_generate(uuid);
+	ndns = create_blk_namespace(1, blk_region, ns_size, uuid);
+	if (!ndns) {
+		fprintf(stderr, "failed to re-create block namespace\n");
+		goto err_cleanup;
+	}
+
+	/* make sure there is no btt on this namespace */
+	found = check_valid_btt(blk_region, ndns, btt_uuid);
+	if (found) {
+		fprintf(stderr, "found a stale btt\n");
+		rc = -ENXIO;
+		goto err_cleanup;
+	}
+
+err_cleanup:
+	ndctl_btt_foreach(blk_region, btt)
+		ndctl_btt_delete(btt);
+
+	ndctl_namespace_foreach(blk_region, ndns)
+		if (ndctl_namespace_get_size(ndns) != 0)
+			disable_blk_namespace(ndns);
+	ndctl_region_foreach(bus, region)
+		ndctl_region_disable_invalidate(region);
+
+
+ err_nobus:
+	ndctl_unref(ctx);
+	return rc;
+}
+
+int test_parent_uuid(int loglevel)
+{
+	struct ndctl_ctx *ctx;
+	struct kmod_module *mod;
+	struct kmod_ctx *kmod_ctx;
+	int err, result = EXIT_FAILURE;
+
+	err = ndctl_new(&ctx);
+	if (err < 0)
+		exit(EXIT_FAILURE);
+
+	ndctl_set_log_priority(ctx, loglevel);
+
+	kmod_ctx = kmod_new(NULL, NULL);
+	if (!kmod_ctx)
+		goto err_kmod;
+
+	err = kmod_module_new_from_name(kmod_ctx, NFIT_TEST_MODULE, &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)
+		goto err_module;
+
+	err = do_test(ctx);
+	if (err == 0)
+		result = EXIT_SUCCESS;
+	kmod_module_remove_module(mod, 0);
+
+err_module:
+	kmod_unref(kmod_ctx);
+err_kmod:
+	ndctl_unref(ctx);
+	return result;
+}
+
+int __attribute__((weak)) main(int argc, char *argv[])
+{
+	return test_parent_uuid(LOG_DEBUG);
+}
diff --git a/test-parent-uuid.h b/test-parent-uuid.h
new file mode 100644
index 000000000000..57a5ff75071b
--- /dev/null
+++ b/test-parent-uuid.h
@@ -0,0 +1,4 @@ 
+#ifndef __TEST_PARENT_UUID__
+#define __TEST_PARENT_UUID__
+int test_parent_uuid(int loglevel);
+#endif