summaryrefslogtreecommitdiff
path: root/drivers/of/overlay.c
diff options
context:
space:
mode:
authorFrank Rowand <frank.rowand@sony.com>2022-05-02 13:17:42 -0500
committerRob Herring <robh@kernel.org>2022-05-03 11:53:15 -0500
commit421f4d14bc037f708a3d11fbb01274b741767bf9 (patch)
tree0dcc545c1d08ae4eed261f9f25a0a6c8b0ff5d08 /drivers/of/overlay.c
parent992b0dc5c38a4e79dca17577960c5201275b83f1 (diff)
of: overlay: do not free changeset when of_overlay_apply returns error
New unittests for overlay notifiers reveal a memory leak in of_overlay_apply() 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 Change the error path to no longer call free_overlay_changeset(), and document that the caller of of_overlay_fdt_apply() may choose to remove the overlay. Update the unittest that triggered the error to expect the changed return values and to call of_overlay_remove(). 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-4-frowand.list@gmail.com
Diffstat (limited to 'drivers/of/overlay.c')
-rw-r--r--drivers/of/overlay.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index ae5ea5b1079b..4044ddcb02c6 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -952,6 +952,25 @@ out:
return ret;
}
+/*
+ * of_overlay_fdt_apply() - Create and apply an overlay changeset
+ * @overlay_fdt: pointer to overlay FDT
+ * @overlay_fdt_size: number of bytes in @overlay_fdt
+ * @ret_ovcs_id: pointer for returning created changeset id
+ *
+ * Creates and applies an overlay changeset.
+ *
+ * See of_overlay_apply() for important behavior information.
+ *
+ * Return: 0 on success, or a negative error number. *@ret_ovcs_id is set to
+ * the value of overlay changeset id, which can be passed to of_overlay_remove()
+ * to remove the overlay.
+ *
+ * On error return, the changeset may be partially applied. This is especially
+ * likely if an OF_OVERLAY_POST_APPLY notifier returns an error. In this case
+ * the caller should call of_overlay_remove() with the value in *@ret_ovcs_id.
+ */
+
int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
int *ret_ovcs_id)
{
@@ -1019,15 +1038,19 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
ovcs->overlay_mem = overlay_mem;
ret = of_overlay_apply(ovcs);
- if (ret < 0)
- goto err_free_ovcs;
+ /*
+ * If of_overlay_apply() error, calling free_overlay_changeset() may
+ * result in a memory leak if the apply partly succeeded, so do NOT
+ * goto err_free_ovcs. Instead, the caller of of_overlay_fdt_apply()
+ * can call of_overlay_remove();
+ */
mutex_unlock(&of_mutex);
of_overlay_mutex_unlock();
*ret_ovcs_id = ovcs->id;
- return 0;
+ return ret;
err_free_ovcs:
free_overlay_changeset(ovcs);