aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Rowand <frank.rowand@sony.com>2018-10-04 23:24:17 -0400
committerFrank Rowand <frank.rowand@sony.com>2018-11-09 01:10:35 -0500
commit144552c786925314c1e7cb8f91a71dae1aca8798 (patch)
tree529691048e02c625ece39d41db6304f6f16db9a9
parent651022382c7f8da46cb4872a545ee1da6d097d2a (diff)
of: overlay: add tests to validate kfrees from overlay removal
Add checks: - attempted kfree due to refcount reaching zero before overlay is removed - properties linked to an overlay node when the node is removed - node refcount > one during node removal in a changeset destroy, if the node was created by the changeset After applying this patch, several validation warnings will be reported from the devicetree unittest during boot due to pre-existing devicetree bugs. The warnings will be similar to: OF: ERROR: of_node_release(), unexpected properties in /testcase-data/overlay-node/test-bus/test-unittest11 OF: ERROR: memory leak, expected refcount 1 instead of 2, of_node_get()/of_node_put() unbalanced - destroy cset entry: attach overlay node /testcase-data-2/substation@100/ hvac-medium-2 Tested-by: Alan Tull <atull@kernel.org> Signed-off-by: Frank Rowand <frank.rowand@sony.com>
-rw-r--r--drivers/of/dynamic.c29
-rw-r--r--drivers/of/overlay.c1
-rw-r--r--include/linux/of.h15
3 files changed, 40 insertions, 5 deletions
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index f4f8ed9b5454..12c3f9a15e94 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -330,6 +330,25 @@ void of_node_release(struct kobject *kobj)
330 if (!of_node_check_flag(node, OF_DYNAMIC)) 330 if (!of_node_check_flag(node, OF_DYNAMIC))
331 return; 331 return;
332 332
333 if (of_node_check_flag(node, OF_OVERLAY)) {
334
335 if (!of_node_check_flag(node, OF_OVERLAY_FREE_CSET)) {
336 /* premature refcount of zero, do not free memory */
337 pr_err("ERROR: memory leak before free overlay changeset, %pOF\n",
338 node);
339 return;
340 }
341
342 /*
343 * If node->properties non-empty then properties were added
344 * to this node either by different overlay that has not
345 * yet been removed, or by a non-overlay mechanism.
346 */
347 if (node->properties)
348 pr_err("ERROR: %s(), unexpected properties in %pOF\n",
349 __func__, node);
350 }
351
333 property_list_free(node->properties); 352 property_list_free(node->properties);
334 property_list_free(node->deadprops); 353 property_list_free(node->deadprops);
335 354
@@ -434,6 +453,16 @@ struct device_node *__of_node_dup(const struct device_node *np,
434 453
435static void __of_changeset_entry_destroy(struct of_changeset_entry *ce) 454static void __of_changeset_entry_destroy(struct of_changeset_entry *ce)
436{ 455{
456 if (ce->action == OF_RECONFIG_ATTACH_NODE &&
457 of_node_check_flag(ce->np, OF_OVERLAY)) {
458 if (kref_read(&ce->np->kobj.kref) > 1) {
459 pr_err("ERROR: memory leak, expected refcount 1 instead of %d, of_node_get()/of_node_put() unbalanced - destroy cset entry: attach overlay node %pOF\n",
460 kref_read(&ce->np->kobj.kref), ce->np);
461 } else {
462 of_node_set_flag(ce->np, OF_OVERLAY_FREE_CSET);
463 }
464 }
465
437 of_node_put(ce->np); 466 of_node_put(ce->np);
438 list_del(&ce->node); 467 list_del(&ce->node);
439 kfree(ce); 468 kfree(ce);
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 42b1f73ac5f6..f5fc8859a7ee 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -373,6 +373,7 @@ static int add_changeset_node(struct overlay_changeset *ovcs,
373 return -ENOMEM; 373 return -ENOMEM;
374 374
375 tchild->parent = target_node; 375 tchild->parent = target_node;
376 of_node_set_flag(tchild, OF_OVERLAY);
376 377
377 ret = of_changeset_attach_node(&ovcs->cset, tchild); 378 ret = of_changeset_attach_node(&ovcs->cset, tchild);
378 if (ret) 379 if (ret)
diff --git a/include/linux/of.h b/include/linux/of.h
index a5aee3c438ad..664cd5573ae2 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -138,11 +138,16 @@ extern struct device_node *of_aliases;
138extern struct device_node *of_stdout; 138extern struct device_node *of_stdout;
139extern raw_spinlock_t devtree_lock; 139extern raw_spinlock_t devtree_lock;
140 140
141/* flag descriptions (need to be visible even when !CONFIG_OF) */ 141/*
142#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ 142 * struct device_node flag descriptions
143#define OF_DETACHED 2 /* node has been detached from the device tree */ 143 * (need to be visible even when !CONFIG_OF)
144#define OF_POPULATED 3 /* device already created for the node */ 144 */
145#define OF_POPULATED_BUS 4 /* of_platform_populate recursed to children of this node */ 145#define OF_DYNAMIC 1 /* (and properties) allocated via kmalloc */
146#define OF_DETACHED 2 /* detached from the device tree */
147#define OF_POPULATED 3 /* device already created */
148#define OF_POPULATED_BUS 4 /* platform bus created for children */
149#define OF_OVERLAY 5 /* allocated for an overlay */
150#define OF_OVERLAY_FREE_CSET 6 /* in overlay cset being freed */
146 151
147#define OF_BAD_ADDR ((u64)-1) 152#define OF_BAD_ADDR ((u64)-1)
148 153