[PATCH RFC 2/2] of/unittest: Add reference count tests

From: Geert Uytterhoeven
Date: Fri Jan 23 2015 - 11:10:26 EST


Add tests to detect reference count imbalances. The tests use a fixed
list of paths to devices nodes (required device nodes in a minimal DTS,
and device nodes present in unittest-data).

These tests are executed only if CONFIG_OF_DYNAMIC=y.

Signed-off-by: Geert Uytterhoeven <geert+renesas@xxxxxxxxx>
---
drivers/of/unittest.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 155 insertions(+)

diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 7aa1d6dae5ba72af..464703c6e7021760 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1383,6 +1383,154 @@ out:
static inline void __init of_selftest_overlay(void) { }
#endif

+#ifdef CONFIG_OF_DYNAMIC
+static struct {
+ const char *path;
+ int refcnt;
+} refcnt_tests[] __initdata = {
+ /* required nodes */
+ { "/" },
+ { "/aliases" },
+ { "/chosen" },
+ { "/cpus" },
+ { "/cpus/cpu@0" },
+ { "/testcase-data" },
+ /* unittest-data */
+ { "/testcase-data/interrupts" },
+ { "/testcase-data/interrupts/intc0" },
+ { "/testcase-data/interrupts/intc1" },
+ { "/testcase-data/interrupts/intc2" },
+ { "/testcase-data/interrupts/interrupts0" },
+ { "/testcase-data/interrupts/interrupts1" },
+ { "/testcase-data/interrupts/interrupts-extended0" },
+ { "/testcase-data/interrupts/intmap0" },
+ { "/testcase-data/interrupts/intmap1" },
+ { "/testcase-data/platform-tests" },
+ { "/testcase-data/platform-tests/test-device@0" },
+ { "/testcase-data/platform-tests/test-device@0/dev@100" },
+ { "/testcase-data/platform-tests/test-device@1" },
+ { "/testcase-data/platform-tests/test-device@1/dev@100" },
+ { "/testcase-data/phandle-tests" },
+ { "/testcase-data/phandle-tests/consumer-a" },
+ { "/testcase-data/phandle-tests/provider0" },
+ { "/testcase-data/phandle-tests/provider1" },
+ { "/testcase-data/phandle-tests/provider2" },
+ { "/testcase-data/phandle-tests/provider3" },
+ { "/testcase-data/match-node" },
+ { "/testcase-data/match-node/a" },
+ { "/testcase-data/match-node/a/name2" },
+ { "/testcase-data/match-node/b" },
+ { "/testcase-data/match-node/b/name2" },
+ { "/testcase-data/match-node/c" },
+ { "/testcase-data/match-node/c/name2" },
+ { "/testcase-data/match-node/name0" },
+ { "/testcase-data/match-node/name1" },
+ { "/testcase-data/match-node/name3" },
+ { "/testcase-data/match-node/name4" },
+ { "/testcase-data/match-node/name5" },
+ { "/testcase-data/match-node/name6" },
+ { "/testcase-data/match-node/name7" },
+ { "/testcase-data/match-node/name8" },
+ { "/testcase-data/match-node/name9" },
+ { "/testcase-data/changeset" },
+ { "/testcase-data/changeset/node-remove" },
+ { "/testcase-data/overlay-node" },
+ { "/testcase-data/overlay-node/test-bus" },
+ { "/testcase-data/overlay-node/test-bus/test-selftest100" },
+ { "/testcase-data/overlay-node/test-bus/test-selftest101" },
+ { "/testcase-data/overlay-node/test-bus/test-selftest0" },
+ { "/testcase-data/overlay-node/test-bus/test-selftest1" },
+ { "/testcase-data/overlay-node/test-bus/test-selftest2" },
+ { "/testcase-data/overlay-node/test-bus/test-selftest3" },
+ { "/testcase-data/overlay-node/test-bus/test-selftest5" },
+ { "/testcase-data/overlay-node/test-bus/test-selftest6" },
+ { "/testcase-data/overlay-node/test-bus/test-selftest7" },
+ { "/testcase-data/overlay-node/test-bus/test-selftest8" },
+ { "/testcase-data/overlay0" },
+ { "/testcase-data/overlay0/fragment@0" },
+ { "/testcase-data/overlay0/fragment@0/__overlay__" },
+ { "/testcase-data/overlay1" },
+ { "/testcase-data/overlay1/fragment@0" },
+ { "/testcase-data/overlay1/fragment@0/__overlay__" },
+ { "/testcase-data/overlay2" },
+ { "/testcase-data/overlay2/fragment@0" },
+ { "/testcase-data/overlay2/fragment@0/__overlay__" },
+ { "/testcase-data/overlay3" },
+ { "/testcase-data/overlay3/fragment@0" },
+ { "/testcase-data/overlay3/fragment@0/__overlay__" },
+ { "/testcase-data/overlay4" },
+ { "/testcase-data/overlay4/fragment@0" },
+ { "/testcase-data/overlay4/fragment@0/__overlay__" },
+ { "/testcase-data/overlay4/fragment@0/__overlay__/test-selftest4" },
+ { "/testcase-data/overlay5" },
+ { "/testcase-data/overlay5/fragment@0" },
+ { "/testcase-data/overlay5/fragment@0/__overlay__" },
+ { "/testcase-data/overlay6" },
+ { "/testcase-data/overlay6/fragment@0" },
+ { "/testcase-data/overlay6/fragment@0/__overlay__" },
+ { "/testcase-data/overlay7" },
+ { "/testcase-data/overlay7/fragment@0" },
+ { "/testcase-data/overlay7/fragment@0/__overlay__" },
+ { "/testcase-data/overlay8" },
+ { "/testcase-data/overlay8/fragment@0" },
+ { "/testcase-data/overlay8/fragment@0/__overlay__" },
+ { "/testcase-data/overlay9" },
+ { "/testcase-data/overlay9/fragment@0" },
+ { "/testcase-data/overlay9/fragment@0/__overlay__" },
+ { "/testcase-data/duplicate-name#1" },
+ { "/testcase-data/testcase-device1" },
+ { "/testcase-data/testcase-device2" },
+ { "/__local_fixups__/testcase-data" },
+ { "/__local_fixups__/testcase-data/interrupts" },
+ { "/__local_fixups__/testcase-data/interrupts/interrupts0" },
+ { "/__local_fixups__/testcase-data/interrupts/interrupts1" },
+ { "/__local_fixups__/testcase-data/interrupts/interrupts-extended0" },
+ { "/__local_fixups__/testcase-data/interrupts/intmap0" },
+ { "/__local_fixups__/testcase-data/interrupts/intmap1" },
+ { "/__local_fixups__/testcase-data/phandle-tests" },
+ { "/__local_fixups__/testcase-data/phandle-tests/consumer-a" },
+ { "/__local_fixups__/testcase-data/overlay2" },
+ { "/__local_fixups__/testcase-data/overlay2/fragment@0" },
+ { "/__local_fixups__/testcase-data/overlay3" },
+ { "/__local_fixups__/testcase-data/overlay3/fragment@0" },
+ { "/__local_fixups__/testcase-data/overlay4" },
+ { "/__local_fixups__/testcase-data/overlay4/fragment@0" },
+ { "/__local_fixups__/testcase-data/testcase-device1" },
+ { "/__local_fixups__/testcase-data/testcase-device2" },
+};
+
+static void __init of_selftest_refcnt(void)
+{
+ static bool called;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(refcnt_tests); i++) {
+ const char *path = refcnt_tests[i].path;
+ struct device_node *np = of_find_node_by_path(path);
+ int refcnt;
+
+ selftest(np, "%s: not found", path);
+ if (!np)
+ continue;
+
+ refcnt = atomic_read(&np->kobj.kref.refcount);
+ if (!called)
+ refcnt_tests[i].refcnt = refcnt;
+ else
+ selftest(refcnt == refcnt_tests[i].refcnt,
+ "%s: expected:%i got:%i\n", path,
+ refcnt_tests[i].refcnt, refcnt);
+
+ of_node_put(np);
+ }
+
+ called = true;
+}
+
+#else
+static inline void __init of_selftest_refcnt(void) { }
+#endif
+
static int __init of_selftest(void)
{
struct device_node *np;
@@ -1403,6 +1551,11 @@ static int __init of_selftest(void)
of_node_put(np);

pr_info("start of selftest - you will see error messages\n");
+
+ /* gather reference counts */
+ of_selftest_refcnt();
+ /* verify reference counts */
+ of_selftest_refcnt();
of_selftest_check_tree_linkage();
of_selftest_check_phandles();
of_selftest_find_node_by_name();
@@ -1420,6 +1573,8 @@ static int __init of_selftest(void)
/* Double check linkage after removing testcase data */
of_selftest_check_tree_linkage();

+ of_selftest_refcnt();
+
pr_info("end of selftest - %i passed, %i failed\n",
selftest_results.passed, selftest_results.failed);

--
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/