of: overlay: unittest: add tests for overlay notifiers
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
This commit is contained in:
parent
1ac17586c9
commit
992b0dc5c3
|
@ -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 \
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -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),
|
||||
|
|
Loading…
Reference in New Issue