OSDN Git Service

of: overlay: unittest: add tests for overlay notifiers
authorFrank Rowand <frank.rowand@sony.com>
Mon, 2 May 2022 18:17:41 +0000 (13:17 -0500)
committerRob Herring <robh@kernel.org>
Tue, 3 May 2022 16:53:15 +0000 (11:53 -0500)
Add tests for overlay apply and remove notifiers.  Trigger errors
for each of the notifier actions.

These tests will reveal a memory leak problem when a notifier returns
an error for action OF_OVERLAY_POST_APPLY.  The pr_err() message is:

   OF: ERROR: memory leak, expected refcount 1 instead of 3,
   of_node_get()/of_node_put() unbalanced - destroy cset entry: attach
   overlay node /testcase-data/overlay-node/test-bus/test-unittest17

Signed-off-by: Frank Rowand <frank.rowand@sony.com>
Signed-off-by: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20220502181742.1402826-3-frowand.list@gmail.com
drivers/of/unittest-data/Makefile
drivers/of/unittest-data/overlay_16.dts [new file with mode: 0644]
drivers/of/unittest-data/overlay_17.dts [new file with mode: 0644]
drivers/of/unittest-data/overlay_18.dts [new file with mode: 0644]
drivers/of/unittest-data/overlay_19.dts [new file with mode: 0644]
drivers/of/unittest-data/overlay_20.dts [new file with mode: 0644]
drivers/of/unittest.c

index fbded24..d072f3b 100644 (file)
@@ -17,6 +17,11 @@ obj-$(CONFIG_OF_OVERLAY) += overlay.dtb.o \
                            overlay_12.dtb.o \
                            overlay_13.dtb.o \
                            overlay_15.dtb.o \
+                           overlay_16.dtb.o \
+                           overlay_17.dtb.o \
+                           overlay_18.dtb.o \
+                           overlay_19.dtb.o \
+                           overlay_20.dtb.o \
                            overlay_bad_add_dup_node.dtb.o \
                            overlay_bad_add_dup_prop.dtb.o \
                            overlay_bad_phandle.dtb.o \
@@ -75,6 +80,11 @@ apply_static_overlay_1 := overlay_0.dtbo \
                          overlay_12.dtbo \
                          overlay_13.dtbo \
                          overlay_15.dtbo \
+                         overlay_16.dtbo \
+                         overlay_17.dtbo \
+                         overlay_18.dtbo \
+                         overlay_19.dtbo \
+                         overlay_20.dtbo \
                          overlay_gpio_01.dtbo \
                          overlay_gpio_02a.dtbo \
                          overlay_gpio_02b.dtbo \
diff --git a/drivers/of/unittest-data/overlay_16.dts b/drivers/of/unittest-data/overlay_16.dts
new file mode 100644 (file)
index 0000000..80a46dc
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+/* overlay_16 - notify test */
+
+&unittest_test_bus {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       test-unittest16 {
+               compatible = "unittest";
+               reg = <16>;
+       };
+};
diff --git a/drivers/of/unittest-data/overlay_17.dts b/drivers/of/unittest-data/overlay_17.dts
new file mode 100644 (file)
index 0000000..5b8a220
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+/* overlay_17 - notify test */
+
+&unittest_test_bus {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       test-unittest17 {
+               compatible = "unittest";
+               reg = <17>;
+       };
+};
diff --git a/drivers/of/unittest-data/overlay_18.dts b/drivers/of/unittest-data/overlay_18.dts
new file mode 100644 (file)
index 0000000..dcddd5f
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+/* overlay_18 - notify test */
+
+&unittest_test_bus {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       test-unittest18 {
+               compatible = "unittest";
+               reg = <18>;
+       };
+};
diff --git a/drivers/of/unittest-data/overlay_19.dts b/drivers/of/unittest-data/overlay_19.dts
new file mode 100644 (file)
index 0000000..32b3ba0
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+/* overlay_19 - notify test */
+
+&unittest_test_bus {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       test-unittest19 {
+               compatible = "unittest";
+               reg = <19>;
+       };
+};
diff --git a/drivers/of/unittest-data/overlay_20.dts b/drivers/of/unittest-data/overlay_20.dts
new file mode 100644 (file)
index 0000000..d4a4f2f
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+/* overlay_20 - notify test */
+
+&unittest_test_bus {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       test-unittest20 {
+               compatible = "unittest";
+               reg = <20>;
+       };
+};
index c4106de..6747e8e 100644 (file)
@@ -2741,6 +2741,189 @@ static inline void of_unittest_overlay_i2c_15(void) { }
 
 #endif
 
+static int of_notify(struct notifier_block *nb, unsigned long action,
+                    void *arg)
+{
+       struct of_overlay_notify_data *nd = arg;
+       struct device_node *found;
+       int ret;
+
+       /*
+        * For overlay_16 .. overlay_19, check that returning an error
+        * works for each of the actions by setting an arbitrary return
+        * error number that matches the test number.  e.g. for unittest16,
+        * ret = -EBUSY which is -16.
+        *
+        * OVERLAY_INFO() for the overlays is declared to expect the same
+        * error number, so overlay_data_apply() will return no error.
+        *
+        * overlay_20 will return NOTIFY_DONE
+        */
+
+       ret = 0;
+       of_node_get(nd->overlay);
+
+       switch (action) {
+
+       case OF_OVERLAY_PRE_APPLY:
+               found = of_find_node_by_name(nd->overlay, "test-unittest16");
+               if (found) {
+                       of_node_put(found);
+                       ret = -EBUSY;
+               }
+               break;
+
+       case OF_OVERLAY_POST_APPLY:
+               found = of_find_node_by_name(nd->overlay, "test-unittest17");
+               if (found) {
+                       of_node_put(found);
+                       ret = -EEXIST;
+               }
+               break;
+
+       case OF_OVERLAY_PRE_REMOVE:
+               found = of_find_node_by_name(nd->overlay, "test-unittest18");
+               if (found) {
+                       of_node_put(found);
+                       ret = -EXDEV;
+               }
+               break;
+
+       case OF_OVERLAY_POST_REMOVE:
+               found = of_find_node_by_name(nd->overlay, "test-unittest19");
+               if (found) {
+                       of_node_put(found);
+                       ret = -ENODEV;
+               }
+               break;
+
+       default:                        /* should not happen */
+               of_node_put(nd->overlay);
+               ret = -EINVAL;
+               break;
+       }
+
+       if (ret)
+               return notifier_from_errno(ret);
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block of_nb = {
+       .notifier_call = of_notify,
+};
+
+static void __init of_unittest_overlay_notify(void)
+{
+       int ovcs_id;
+       int ret;
+
+       ret = of_overlay_notifier_register(&of_nb);
+       unittest(!ret,
+                "of_overlay_notifier_register() failed, ret = %d\n", ret);
+       if (ret)
+               return;
+
+       /*
+        * The overlays are applied by overlay_data_apply()
+        * instead of of_unittest_apply_overlay() so that they
+        * will not be tracked.  Thus they will not be removed
+        * by of_unittest_remove_tracked_overlays().
+        *
+        * Applying overlays 16 - 19 will each trigger an error for a
+        * different action in of_notify().
+        *
+        * Applying overlay 20 will not trigger any error in of_notify().
+        */
+
+       /* ---  overlay 16  --- */
+
+       EXPECT_BEGIN(KERN_INFO, "OF: overlay: overlay changeset pre-apply notifier error -16, target: /testcase-data/overlay-node/test-bus");
+
+       unittest(overlay_data_apply("overlay_16", &ovcs_id),
+                "test OF_OVERLAY_PRE_APPLY notify injected error\n");
+
+       EXPECT_END(KERN_INFO, "OF: overlay: overlay changeset pre-apply notifier error -16, target: /testcase-data/overlay-node/test-bus");
+
+       unittest(!ovcs_id, "ovcs_id created for overlay_16\n");
+
+       /* ---  overlay 17  --- */
+
+       EXPECT_BEGIN(KERN_INFO, "OF: overlay: overlay changeset post-apply notifier error -17, target: /testcase-data/overlay-node/test-bus");
+
+       unittest(overlay_data_apply("overlay_17", &ovcs_id),
+                "test OF_OVERLAY_POST_APPLY notify injected error\n");
+
+       EXPECT_END(KERN_INFO, "OF: overlay: overlay changeset post-apply notifier error -17, target: /testcase-data/overlay-node/test-bus");
+
+       unittest(!ovcs_id, "ovcs_id created for overlay_17\n");
+
+       /* ---  overlay 18  --- */
+
+       unittest(overlay_data_apply("overlay_18", &ovcs_id),
+                "OF_OVERLAY_PRE_REMOVE notify injected error\n");
+
+       unittest(ovcs_id, "ovcs_id not created for overlay_18\n");
+
+       if (ovcs_id) {
+               EXPECT_BEGIN(KERN_INFO, "OF: overlay: overlay changeset pre-remove notifier error -18, target: /testcase-data/overlay-node/test-bus");
+
+               ret = of_overlay_remove(&ovcs_id);
+               EXPECT_END(KERN_INFO, "OF: overlay: overlay changeset pre-remove notifier error -18, target: /testcase-data/overlay-node/test-bus");
+               if (ret == -EXDEV) {
+                       /*
+                        * change set ovcs_id should still exist
+                        */
+                       unittest(1, "overlay_18 of_overlay_remove() injected error for OF_OVERLAY_PRE_REMOVE\n");
+               } else {
+                       unittest(0, "overlay_18 of_overlay_remove() injected error for OF_OVERLAY_PRE_REMOVE not returned\n");
+               }
+       } else {
+               unittest(1, "ovcs_id not created for overlay_18\n");
+       }
+
+       unittest(ovcs_id, "ovcs_id removed for overlay_18\n");
+
+       /* ---  overlay 19  --- */
+
+       unittest(overlay_data_apply("overlay_19", &ovcs_id),
+                "OF_OVERLAY_POST_REMOVE notify injected error\n");
+
+       unittest(ovcs_id, "ovcs_id not created for overlay_19\n");
+
+       if (ovcs_id) {
+               EXPECT_BEGIN(KERN_INFO, "OF: overlay: overlay changeset post-remove notifier error -19, target: /testcase-data/overlay-node/test-bus");
+               ret = of_overlay_remove(&ovcs_id);
+               EXPECT_END(KERN_INFO, "OF: overlay: overlay changeset post-remove notifier error -19, target: /testcase-data/overlay-node/test-bus");
+               if (ret == -ENODEV)
+                       unittest(1, "overlay_19 of_overlay_remove() injected error for OF_OVERLAY_POST_REMOVE\n");
+               else
+                       unittest(0, "overlay_19 of_overlay_remove() injected error for OF_OVERLAY_POST_REMOVE not returned\n");
+       } else {
+               unittest(1, "ovcs_id removed for overlay_19\n");
+       }
+
+       unittest(!ovcs_id, "changeset ovcs_id = %d not removed for overlay_19\n",
+                ovcs_id);
+
+       /* ---  overlay 20  --- */
+
+       unittest(overlay_data_apply("overlay_20", &ovcs_id),
+                "overlay notify no injected error\n");
+
+       if (ovcs_id) {
+               ret = of_overlay_remove(&ovcs_id);
+               if (ret)
+                       unittest(1, "overlay_20 failed to be destroyed, ret = %d\n",
+                                ret);
+       } else {
+               unittest(1, "ovcs_id not created for overlay_20\n");
+       }
+
+       unittest(!of_overlay_notifier_unregister(&of_nb),
+                "of_overlay_notifier_unregister() failed, ret = %d\n", ret);
+}
+
 static void __init of_unittest_overlay(void)
 {
        struct device_node *bus_np = NULL;
@@ -2804,6 +2987,8 @@ static void __init of_unittest_overlay(void)
 
        of_unittest_remove_tracked_overlays();
 
+       of_unittest_overlay_notify();
+
 out:
        of_node_put(bus_np);
 }
@@ -2855,6 +3040,11 @@ OVERLAY_INFO_EXTERN(overlay_11);
 OVERLAY_INFO_EXTERN(overlay_12);
 OVERLAY_INFO_EXTERN(overlay_13);
 OVERLAY_INFO_EXTERN(overlay_15);
+OVERLAY_INFO_EXTERN(overlay_16);
+OVERLAY_INFO_EXTERN(overlay_17);
+OVERLAY_INFO_EXTERN(overlay_18);
+OVERLAY_INFO_EXTERN(overlay_19);
+OVERLAY_INFO_EXTERN(overlay_20);
 OVERLAY_INFO_EXTERN(overlay_gpio_01);
 OVERLAY_INFO_EXTERN(overlay_gpio_02a);
 OVERLAY_INFO_EXTERN(overlay_gpio_02b);
@@ -2885,6 +3075,11 @@ static struct overlay_info overlays[] = {
        OVERLAY_INFO(overlay_12, 0),
        OVERLAY_INFO(overlay_13, 0),
        OVERLAY_INFO(overlay_15, 0),
+       OVERLAY_INFO(overlay_16, -EBUSY),
+       OVERLAY_INFO(overlay_17, -EEXIST),
+       OVERLAY_INFO(overlay_18, 0),
+       OVERLAY_INFO(overlay_19, 0),
+       OVERLAY_INFO(overlay_20, 0),
        OVERLAY_INFO(overlay_gpio_01, 0),
        OVERLAY_INFO(overlay_gpio_02a, 0),
        OVERLAY_INFO(overlay_gpio_02b, 0),