This small series converts the DT code to use __free() based cleanups
for kfree() and of_node_put(). Using __free() simplifies function exit
handling. Initial support for struct device_node was added in commit
9448e55d032d ("of: Add cleanup.h based auto release via
__free(device_node) markings").
Signed-off-by: Rob Herring <[email protected]>
---
Changes in v2:
- Also use cleanup for 'dev' in __of_translate_address()
- Further simplify of_dma_is_coherent() and of_mmio_is_nonposted()
- Link to v1: https://lore.kernel.org/r/[email protected]
---
Rob Herring (3):
of: Add a helper to free property struct
of: Use scope based kfree() cleanups
of: Use scope based of_node_put() cleanups
drivers/of/address.c | 113 +++++++++++++++++-------------------------------
drivers/of/base.c | 34 ++++-----------
drivers/of/dynamic.c | 37 +++++++---------
drivers/of/of_private.h | 1 +
drivers/of/overlay.c | 11 ++---
drivers/of/property.c | 22 +++-------
drivers/of/resolver.c | 35 ++++++---------
drivers/of/unittest.c | 12 ++---
8 files changed, 90 insertions(+), 175 deletions(-)
---
base-commit: 4cece764965020c22cff7665b18a012006359095
change-id: 20240404-dt-cleanup-free-6d5334b4b368
Best regards,
--
Rob Herring <[email protected]>
Freeing a property struct is 3 kfree()'s which is duplicated in multiple
spots. Add a helper, __of_prop_free(), and replace all the open coded
cases in the DT code.
Reviewed-by: Saravana Kannan <[email protected]>
Reviewed-by: Jonathan Cameron <[email protected]>
Signed-off-by: Rob Herring <[email protected]>
---
drivers/of/dynamic.c | 26 ++++++++++++--------------
drivers/of/of_private.h | 1 +
drivers/of/overlay.c | 11 +++--------
drivers/of/unittest.c | 12 +++---------
4 files changed, 19 insertions(+), 31 deletions(-)
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 3bf27052832f..af7c57a7a25d 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -305,15 +305,20 @@ int of_detach_node(struct device_node *np)
}
EXPORT_SYMBOL_GPL(of_detach_node);
+void __of_prop_free(struct property *prop)
+{
+ kfree(prop->name);
+ kfree(prop->value);
+ kfree(prop);
+}
+
static void property_list_free(struct property *prop_list)
{
struct property *prop, *next;
for (prop = prop_list; prop != NULL; prop = next) {
next = prop->next;
- kfree(prop->name);
- kfree(prop->value);
- kfree(prop);
+ __of_prop_free(prop);
}
}
@@ -426,9 +431,7 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
return new;
err_free:
- kfree(new->name);
- kfree(new->value);
- kfree(new);
+ __of_prop_free(new);
return NULL;
}
@@ -470,9 +473,7 @@ struct device_node *__of_node_dup(const struct device_node *np,
if (!new_pp)
goto err_prop;
if (__of_add_property(node, new_pp)) {
- kfree(new_pp->name);
- kfree(new_pp->value);
- kfree(new_pp);
+ __of_prop_free(new_pp);
goto err_prop;
}
}
@@ -921,11 +922,8 @@ static int of_changeset_add_prop_helper(struct of_changeset *ocs,
return -ENOMEM;
ret = of_changeset_add_property(ocs, np, new_pp);
- if (ret) {
- kfree(new_pp->name);
- kfree(new_pp->value);
- kfree(new_pp);
- }
+ if (ret)
+ __of_prop_free(new_pp);
return ret;
}
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 485483524b7f..94fc0aa07af9 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -123,6 +123,7 @@ extern void *__unflatten_device_tree(const void *blob,
* own the devtree lock or work on detached trees only.
*/
struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags);
+void __of_prop_free(struct property *prop);
struct device_node *__of_node_dup(const struct device_node *np,
const char *full_name);
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 2ae7e9d24a64..4d861a75d694 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -262,9 +262,7 @@ static struct property *dup_and_fixup_symbol_prop(
return new_prop;
err_free_new_prop:
- kfree(new_prop->name);
- kfree(new_prop->value);
- kfree(new_prop);
+ __of_prop_free(new_prop);
err_free_target_path:
kfree(target_path);
@@ -361,11 +359,8 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
pr_err("WARNING: memory leak will occur if overlay removed, property: %pOF/%s\n",
target->np, new_prop->name);
- if (ret) {
- kfree(new_prop->name);
- kfree(new_prop->value);
- kfree(new_prop);
- }
+ if (ret)
+ __of_prop_free(new_prop);
return ret;
}
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 6b5c36b6a758..a8c01c953a29 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -795,15 +795,11 @@ static void __init of_unittest_property_copy(void)
new = __of_prop_dup(&p1, GFP_KERNEL);
unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n");
- kfree(new->value);
- kfree(new->name);
- kfree(new);
+ __of_prop_free(new);
new = __of_prop_dup(&p2, GFP_KERNEL);
unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n");
- kfree(new->value);
- kfree(new->name);
- kfree(new);
+ __of_prop_free(new);
#endif
}
@@ -3718,9 +3714,7 @@ static __init void of_unittest_overlay_high_level(void)
goto err_unlock;
}
if (__of_add_property(of_symbols, new_prop)) {
- kfree(new_prop->name);
- kfree(new_prop->value);
- kfree(new_prop);
+ __of_prop_free(new_prop);
/* "name" auto-generated by unflatten */
if (!strcmp(prop->name, "name"))
continue;
--
2.43.0
Use the relatively new scope based kfree() cleanup to simplify error
handling. Doing so reduces the chances of memory leaks and simplifies
error paths by avoiding the need for goto statements.
Reviewed-by: Saravana Kannan <[email protected]>
Reviewed-by: Jonathan Cameron <[email protected]>
Signed-off-by: Rob Herring <[email protected]>
---
drivers/of/base.c | 34 ++++++++--------------------------
drivers/of/dynamic.c | 11 ++++-------
drivers/of/resolver.c | 35 +++++++++++++----------------------
3 files changed, 25 insertions(+), 55 deletions(-)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 8856c67c466a..20603d3c9931 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -16,6 +16,7 @@
#define pr_fmt(fmt) "OF: " fmt
+#include <linux/cleanup.h>
#include <linux/console.h>
#include <linux/ctype.h>
#include <linux/cpu.h>
@@ -1393,8 +1394,10 @@ int of_parse_phandle_with_args_map(const struct device_node *np,
const char *stem_name,
int index, struct of_phandle_args *out_args)
{
- char *cells_name, *map_name = NULL, *mask_name = NULL;
- char *pass_name = NULL;
+ char *cells_name __free(kfree) = kasprintf(GFP_KERNEL, "#%s-cells", stem_name);
+ char *map_name __free(kfree) = kasprintf(GFP_KERNEL, "%s-map", stem_name);
+ char *mask_name __free(kfree) = kasprintf(GFP_KERNEL, "%s-map-mask", stem_name);
+ char *pass_name __free(kfree) = kasprintf(GFP_KERNEL, "%s-map-pass-thru", stem_name);
struct device_node *cur, *new = NULL;
const __be32 *map, *mask, *pass;
static const __be32 dummy_mask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
@@ -1407,27 +1410,13 @@ int of_parse_phandle_with_args_map(const struct device_node *np,
if (index < 0)
return -EINVAL;
- cells_name = kasprintf(GFP_KERNEL, "#%s-cells", stem_name);
- if (!cells_name)
+ if (!cells_name || !map_name || !mask_name || !pass_name)
return -ENOMEM;
- ret = -ENOMEM;
- map_name = kasprintf(GFP_KERNEL, "%s-map", stem_name);
- if (!map_name)
- goto free;
-
- mask_name = kasprintf(GFP_KERNEL, "%s-map-mask", stem_name);
- if (!mask_name)
- goto free;
-
- pass_name = kasprintf(GFP_KERNEL, "%s-map-pass-thru", stem_name);
- if (!pass_name)
- goto free;
-
ret = __of_parse_phandle_with_args(np, list_name, cells_name, -1, index,
out_args);
if (ret)
- goto free;
+ return ret;
/* Get the #<list>-cells property */
cur = out_args->np;
@@ -1444,8 +1433,7 @@ int of_parse_phandle_with_args_map(const struct device_node *np,
/* Get the <list>-map property */
map = of_get_property(cur, map_name, &map_len);
if (!map) {
- ret = 0;
- goto free;
+ return 0;
}
map_len /= sizeof(u32);
@@ -1521,12 +1509,6 @@ int of_parse_phandle_with_args_map(const struct device_node *np,
put:
of_node_put(cur);
of_node_put(new);
-free:
- kfree(mask_name);
- kfree(map_name);
- kfree(cells_name);
- kfree(pass_name);
-
return ret;
}
EXPORT_SYMBOL(of_parse_phandle_with_args_map);
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index af7c57a7a25d..43f4e2c93bd2 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -9,6 +9,7 @@
#define pr_fmt(fmt) "OF: " fmt
+#include <linux/cleanup.h>
#include <linux/of.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -1019,10 +1020,9 @@ int of_changeset_add_prop_u32_array(struct of_changeset *ocs,
const u32 *array, size_t sz)
{
struct property prop;
- __be32 *val;
- int i, ret;
+ __be32 *val __free(kfree) = kcalloc(sz, sizeof(__be32), GFP_KERNEL);
+ int i;
- val = kcalloc(sz, sizeof(__be32), GFP_KERNEL);
if (!val)
return -ENOMEM;
@@ -1032,9 +1032,6 @@ int of_changeset_add_prop_u32_array(struct of_changeset *ocs,
prop.length = sizeof(u32) * sz;
prop.value = (void *)val;
- ret = of_changeset_add_prop_helper(ocs, np, &prop);
- kfree(val);
-
- return ret;
+ return of_changeset_add_prop_helper(ocs, np, &prop);
}
EXPORT_SYMBOL_GPL(of_changeset_add_prop_u32_array);
diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c
index b278ab4338ce..2780928764a4 100644
--- a/drivers/of/resolver.c
+++ b/drivers/of/resolver.c
@@ -8,6 +8,7 @@
#define pr_fmt(fmt) "OF: resolver: " fmt
+#include <linux/cleanup.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -74,11 +75,11 @@ static int update_usages_of_a_phandle_reference(struct device_node *overlay,
{
struct device_node *refnode;
struct property *prop;
- char *value, *cur, *end, *node_path, *prop_name, *s;
+ char *value __free(kfree) = kmemdup(prop_fixup->value, prop_fixup->length, GFP_KERNEL);
+ char *cur, *end, *node_path, *prop_name, *s;
int offset, len;
int err = 0;
- value = kmemdup(prop_fixup->value, prop_fixup->length, GFP_KERNEL);
if (!value)
return -ENOMEM;
@@ -89,23 +90,19 @@ static int update_usages_of_a_phandle_reference(struct device_node *overlay,
node_path = cur;
s = strchr(cur, ':');
- if (!s) {
- err = -EINVAL;
- goto err_fail;
- }
+ if (!s)
+ return -EINVAL;
*s++ = '\0';
prop_name = s;
s = strchr(s, ':');
- if (!s) {
- err = -EINVAL;
- goto err_fail;
- }
+ if (!s)
+ return -EINVAL;
*s++ = '\0';
err = kstrtoint(s, 10, &offset);
if (err)
- goto err_fail;
+ return err;
refnode = __of_find_node_by_full_path(of_node_get(overlay), node_path);
if (!refnode)
@@ -117,22 +114,16 @@ static int update_usages_of_a_phandle_reference(struct device_node *overlay,
}
of_node_put(refnode);
- if (!prop) {
- err = -ENOENT;
- goto err_fail;
- }
+ if (!prop)
+ return -ENOENT;
- if (offset < 0 || offset + sizeof(__be32) > prop->length) {
- err = -EINVAL;
- goto err_fail;
- }
+ if (offset < 0 || offset + sizeof(__be32) > prop->length)
+ return -EINVAL;
*(__be32 *)(prop->value + offset) = cpu_to_be32(phandle);
}
-err_fail:
- kfree(value);
- return err;
+ return 0;
}
/* compare nodes taking into account that 'name' strips out the @ part */
--
2.43.0
Use the relatively new scope based of_node_put() cleanup to simplify
function exit handling. Doing so reduces the chances of forgetting an
of_node_put() and simplifies error paths by avoiding the need for goto
statements.
Reviewed-by: Saravana Kannan <[email protected]>
Signed-off-by: Rob Herring <[email protected]>
---
v2:
- Also use cleanup for 'dev' in __of_translate_address()
- Further simplify of_dma_is_coherent() and of_mmio_is_nonposted()
---
drivers/of/address.c | 113 +++++++++++++++++---------------------------------
drivers/of/property.c | 22 ++++------
2 files changed, 46 insertions(+), 89 deletions(-)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index ae46a3605904..c350185ceaeb 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -486,34 +486,30 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
* device that had registered logical PIO mapping, and the return code is
* relative to that node.
*/
-static u64 __of_translate_address(struct device_node *dev,
+static u64 __of_translate_address(struct device_node *node,
struct device_node *(*get_parent)(const struct device_node *),
const __be32 *in_addr, const char *rprop,
struct device_node **host)
{
- struct device_node *parent = NULL;
+ struct device_node *dev __free(device_node) = of_node_get(node);
+ struct device_node *parent __free(device_node) = get_parent(dev);
struct of_bus *bus, *pbus;
__be32 addr[OF_MAX_ADDR_CELLS];
int na, ns, pna, pns;
- u64 result = OF_BAD_ADDR;
pr_debug("** translation for device %pOF **\n", dev);
- /* Increase refcount at current level */
- of_node_get(dev);
-
*host = NULL;
- /* Get parent & match bus type */
- parent = get_parent(dev);
+
if (parent == NULL)
- goto bail;
+ return OF_BAD_ADDR;
bus = of_match_bus(parent);
/* Count address cells & copy address locally */
bus->count_cells(dev, &na, &ns);
if (!OF_CHECK_COUNTS(na, ns)) {
pr_debug("Bad cell count for %pOF\n", dev);
- goto bail;
+ return OF_BAD_ADDR;
}
memcpy(addr, in_addr, na * 4);
@@ -533,8 +529,7 @@ static u64 __of_translate_address(struct device_node *dev,
/* If root, we have finished */
if (parent == NULL) {
pr_debug("reached root node\n");
- result = of_read_number(addr, na);
- break;
+ return of_read_number(addr, na);
}
/*
@@ -543,11 +538,11 @@ static u64 __of_translate_address(struct device_node *dev,
*/
iorange = find_io_range_by_fwnode(&dev->fwnode);
if (iorange && (iorange->flags != LOGIC_PIO_CPU_MMIO)) {
- result = of_read_number(addr + 1, na - 1);
+ u64 result = of_read_number(addr + 1, na - 1);
pr_debug("indirectIO matched(%pOF) 0x%llx\n",
dev, result);
- *host = of_node_get(dev);
- break;
+ *host = no_free_ptr(dev);
+ return result;
}
/* Get new parent bus and counts */
@@ -555,7 +550,7 @@ static u64 __of_translate_address(struct device_node *dev,
pbus->count_cells(dev, &pna, &pns);
if (!OF_CHECK_COUNTS(pna, pns)) {
pr_err("Bad cell count for %pOF\n", dev);
- break;
+ return OF_BAD_ADDR;
}
pr_debug("parent bus is %s (na=%d, ns=%d) on %pOF\n",
@@ -563,7 +558,7 @@ static u64 __of_translate_address(struct device_node *dev,
/* Apply bus translation */
if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
- break;
+ return OF_BAD_ADDR;
/* Complete the move up one level */
na = pna;
@@ -572,11 +567,8 @@ static u64 __of_translate_address(struct device_node *dev,
of_dump_addr("one level translation:", addr, na);
}
- bail:
- of_node_put(parent);
- of_node_put(dev);
- return result;
+ return OF_BAD_ADDR;
}
u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
@@ -654,19 +646,16 @@ EXPORT_SYMBOL(of_translate_dma_address);
const __be32 *of_translate_dma_region(struct device_node *dev, const __be32 *prop,
phys_addr_t *start, size_t *length)
{
- struct device_node *parent;
+ struct device_node *parent __free(device_node) = __of_get_dma_parent(dev);
u64 address, size;
int na, ns;
- parent = __of_get_dma_parent(dev);
if (!parent)
return NULL;
na = of_bus_n_addr_cells(parent);
ns = of_bus_n_size_cells(parent);
- of_node_put(parent);
-
address = of_translate_dma_address(dev, prop);
if (address == OF_BAD_ADDR)
return NULL;
@@ -688,21 +677,19 @@ const __be32 *__of_get_address(struct device_node *dev, int index, int bar_no,
{
const __be32 *prop;
unsigned int psize;
- struct device_node *parent;
+ struct device_node *parent __free(device_node) = of_get_parent(dev);
struct of_bus *bus;
int onesize, i, na, ns;
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
if (parent == NULL)
return NULL;
+
+ /* match the parent's bus type */
bus = of_match_bus(parent);
- if (strcmp(bus->name, "pci") && (bar_no >= 0)) {
- of_node_put(parent);
+ if (strcmp(bus->name, "pci") && (bar_no >= 0))
return NULL;
- }
+
bus->count_cells(dev, &na, &ns);
- of_node_put(parent);
if (!OF_CHECK_ADDR_COUNT(na))
return NULL;
@@ -888,14 +875,13 @@ static u64 of_translate_ioport(struct device_node *dev, const __be32 *in_addr,
*/
int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
{
- struct device_node *node = of_node_get(np);
+ struct device_node *node __free(device_node) = of_node_get(np);
const __be32 *ranges = NULL;
bool found_dma_ranges = false;
struct of_range_parser parser;
struct of_range range;
struct bus_dma_region *r;
int len, num_ranges = 0;
- int ret = 0;
while (node) {
ranges = of_get_property(node, "dma-ranges", &len);
@@ -905,10 +891,9 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
break;
/* Once we find 'dma-ranges', then a missing one is an error */
- if (found_dma_ranges && !ranges) {
- ret = -ENODEV;
- goto out;
- }
+ if (found_dma_ranges && !ranges)
+ return -ENODEV;
+
found_dma_ranges = true;
node = of_get_next_dma_parent(node);
@@ -916,10 +901,8 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
if (!node || !ranges) {
pr_debug("no dma-ranges found for node(%pOF)\n", np);
- ret = -ENODEV;
- goto out;
+ return -ENODEV;
}
-
of_dma_range_parser_init(&parser, node);
for_each_of_range(&parser, &range) {
if (range.cpu_addr == OF_BAD_ADDR) {
@@ -930,16 +913,12 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
num_ranges++;
}
- if (!num_ranges) {
- ret = -EINVAL;
- goto out;
- }
+ if (!num_ranges)
+ return -EINVAL;
r = kcalloc(num_ranges + 1, sizeof(*r), GFP_KERNEL);
- if (!r) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!r)
+ return -ENOMEM;
/*
* Record all info in the generic DMA ranges array for struct device,
@@ -957,9 +936,7 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
r->size = range.size;
r++;
}
-out:
- of_node_put(node);
- return ret;
+ return 0;
}
#endif /* CONFIG_HAS_DMA */
@@ -1016,24 +993,18 @@ phys_addr_t __init of_dma_get_max_cpu_address(struct device_node *np)
*/
bool of_dma_is_coherent(struct device_node *np)
{
- struct device_node *node;
- bool is_coherent = dma_default_coherent;
-
- node = of_node_get(np);
+ struct device_node *node __free(device_node) = of_node_get(np);
while (node) {
- if (of_property_read_bool(node, "dma-coherent")) {
- is_coherent = true;
- break;
- }
- if (of_property_read_bool(node, "dma-noncoherent")) {
- is_coherent = false;
- break;
- }
+ if (of_property_read_bool(node, "dma-coherent"))
+ return true;
+
+ if (of_property_read_bool(node, "dma-noncoherent"))
+ return false;
+
node = of_get_next_dma_parent(node);
}
- of_node_put(node);
- return is_coherent;
+ return dma_default_coherent;
}
EXPORT_SYMBOL_GPL(of_dma_is_coherent);
@@ -1049,20 +1020,14 @@ EXPORT_SYMBOL_GPL(of_dma_is_coherent);
*/
static bool of_mmio_is_nonposted(struct device_node *np)
{
- struct device_node *parent;
- bool nonposted;
-
if (!IS_ENABLED(CONFIG_ARCH_APPLE))
return false;
- parent = of_get_parent(np);
+ struct device_node *parent __free(device_node) = of_get_parent(np);
if (!parent)
return false;
- nonposted = of_property_read_bool(parent, "nonposted-mmio");
-
- of_node_put(parent);
- return nonposted;
+ return of_property_read_bool(parent, "nonposted-mmio");
}
static int __of_address_to_resource(struct device_node *dev, int index, int bar_no,
diff --git a/drivers/of/property.c b/drivers/of/property.c
index a6358ee99b74..b73daf81c99d 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -40,15 +40,12 @@
*/
bool of_graph_is_present(const struct device_node *node)
{
- struct device_node *ports, *port;
+ struct device_node *ports __free(device_node) = of_get_child_by_name(node, "ports");
- ports = of_get_child_by_name(node, "ports");
if (ports)
node = ports;
- port = of_get_child_by_name(node, "port");
- of_node_put(ports);
- of_node_put(port);
+ struct device_node *port __free(device_node) = of_get_child_by_name(node, "port");
return !!port;
}
@@ -610,9 +607,9 @@ EXPORT_SYMBOL(of_graph_parse_endpoint);
*/
struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
{
- struct device_node *node, *port;
+ struct device_node *port;
+ struct device_node *node __free(device_node) = of_get_child_by_name(parent, "ports");
- node = of_get_child_by_name(parent, "ports");
if (node)
parent = node;
@@ -626,8 +623,6 @@ struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
break;
}
- of_node_put(node);
-
return port;
}
EXPORT_SYMBOL(of_graph_get_port_by_id);
@@ -655,14 +650,13 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
* parent port node.
*/
if (!prev) {
- struct device_node *node;
+ struct device_node *node __free(device_node) =
+ of_get_child_by_name(parent, "ports");
- node = of_get_child_by_name(parent, "ports");
if (node)
parent = node;
port = of_get_child_by_name(parent, "port");
- of_node_put(node);
if (!port) {
pr_debug("graph: no port node found in %pOF\n", parent);
@@ -1052,15 +1046,13 @@ static int of_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
struct fwnode_endpoint *endpoint)
{
const struct device_node *node = to_of_node(fwnode);
- struct device_node *port_node = of_get_parent(node);
+ struct device_node *port_node __free(device_node) = of_get_parent(node);
endpoint->local_fwnode = fwnode;
of_property_read_u32(port_node, "reg", &endpoint->port);
of_property_read_u32(node, "reg", &endpoint->id);
- of_node_put(port_node);
-
return 0;
}
--
2.43.0
On Tue, 09 Apr 2024 13:59:41 -0500
Rob Herring <[email protected]> wrote:
> Use the relatively new scope based of_node_put() cleanup to simplify
> function exit handling. Doing so reduces the chances of forgetting an
> of_node_put() and simplifies error paths by avoiding the need for goto
> statements.
>
> Reviewed-by: Saravana Kannan <[email protected]>
> Signed-off-by: Rob Herring <[email protected]>
Hi Rob,
A few follow up comments, but they are all in the 'you could' category.
Either way.
Reviewed-by: Jonathan Cameron <[email protected]>
> ---
> v2:
> - Also use cleanup for 'dev' in __of_translate_address()
> - Further simplify of_dma_is_coherent() and of_mmio_is_nonposted()
> ---
> drivers/of/address.c | 113 +++++++++++++++++---------------------------------
> drivers/of/property.c | 22 ++++------
> 2 files changed, 46 insertions(+), 89 deletions(-)
>
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index ae46a3605904..c350185ceaeb 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -486,34 +486,30 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
> * device that had registered logical PIO mapping, and the return code is
> * relative to that node.
> */
> -static u64 __of_translate_address(struct device_node *dev,
> +static u64 __of_translate_address(struct device_node *node,
> struct device_node *(*get_parent)(const struct device_node *),
> const __be32 *in_addr, const char *rprop,
> struct device_node **host)
> {
> - struct device_node *parent = NULL;
> + struct device_node *dev __free(device_node) = of_node_get(node);
> + struct device_node *parent __free(device_node) = get_parent(dev);
..
> @@ -572,11 +567,8 @@ static u64 __of_translate_address(struct device_node *dev,
>
> of_dump_addr("one level translation:", addr, na);
> }
> - bail:
> - of_node_put(parent);
> - of_node_put(dev);
>
> - return result;
> + return OF_BAD_ADDR;
I think this is unreachable as there is no way to exist the loop without returning.
If so (and the compiler complains if you remove this) you could mark it as such
with unreachable();
> }
> static int __of_address_to_resource(struct device_node *dev, int index, int bar_no,
> diff --git a/drivers/of/property.c b/drivers/of/property.c
> index a6358ee99b74..b73daf81c99d 100644
> --- a/drivers/of/property.c
> +++ b/drivers/of/property.c
> @@ -610,9 +607,9 @@ EXPORT_SYMBOL(of_graph_parse_endpoint);
> */
> struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
> {
> - struct device_node *node, *port;
> + struct device_node *port;
> + struct device_node *node __free(device_node) = of_get_child_by_name(parent, "ports");
>
> - node = of_get_child_by_name(parent, "ports");
> if (node)
> parent = node;
>
> @@ -626,8 +623,6 @@ struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
> break;
> }
>
> - of_node_put(node);
> -
You 'could' (feel free to ignore) make this perhaps more obvious wiht.
for_each_child_of_node_scoped(parent, port) {
u32 port_id = 0;
if (!of_node_name_eq(port, "port"))
continue;
of_property_read_u32(port, "reg", &port_id);
if (id == port_id)
return_ptr(port);
}
return NULL;
Makes it explicit you are holding a reference on exit if you go vial
the return_ptr() route and that if you don't then in all cases the return value
will be NULL.
> return port;
> }
> EXPORT_SYMBOL(of_graph_get_port_by_id);
> @@ -655,14 +650,13 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
> * parent port node.
> */
> if (!prev) {
> - struct device_node *node;
> + struct device_node *node __free(device_node) =
> + of_get_child_by_name(parent, "ports");
>
> - node = of_get_child_by_name(parent, "ports");
> if (node)
> parent = node;
>
> port = of_get_child_by_name(parent, "port");
> - of_node_put(node);
Very trivial but I'd drop the blank line here to more closely associate the check
with retrieval of the port.
>
> if (!port) {
> pr_debug("graph: no port node found in %pOF\n", parent);
>
On Tue, 09 Apr 2024 13:59:41 -0500
Rob Herring <[email protected]> wrote:
> Use the relatively new scope based of_node_put() cleanup to simplify
> function exit handling. Doing so reduces the chances of forgetting an
> of_node_put() and simplifies error paths by avoiding the need for goto
> statements.
>
> Reviewed-by: Saravana Kannan <[email protected]>
> Signed-off-by: Rob Herring <[email protected]>
> ---
> v2:
> - Also use cleanup for 'dev' in __of_translate_address()
> - Further simplify of_dma_is_coherent() and of_mmio_is_nonposted()
> ---
> drivers/of/address.c | 113 +++++++++++++++++---------------------------------
> drivers/of/property.c | 22 ++++------
> 2 files changed, 46 insertions(+), 89 deletions(-)
>
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index ae46a3605904..c350185ceaeb 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -486,34 +486,30 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
> * device that had registered logical PIO mapping, and the return code is
> * relative to that node.
> */
> -static u64 __of_translate_address(struct device_node *dev,
> +static u64 __of_translate_address(struct device_node *node,
> struct device_node *(*get_parent)(const struct device_node *),
> const __be32 *in_addr, const char *rprop,
> struct device_node **host)
> {
> - struct device_node *parent = NULL;
> + struct device_node *dev __free(device_node) = of_node_get(node);
> + struct device_node *parent __free(device_node) = get_parent(dev);
> struct of_bus *bus, *pbus;
> __be32 addr[OF_MAX_ADDR_CELLS];
> int na, ns, pna, pns;
> - u64 result = OF_BAD_ADDR;
>
> pr_debug("** translation for device %pOF **\n", dev);
>
> - /* Increase refcount at current level */
> - of_node_get(dev);
> -
> *host = NULL;
> - /* Get parent & match bus type */
> - parent = get_parent(dev);
> +
> if (parent == NULL)
> - goto bail;
> + return OF_BAD_ADDR;
> bus = of_match_bus(parent);
>
> /* Count address cells & copy address locally */
> bus->count_cells(dev, &na, &ns);
> if (!OF_CHECK_COUNTS(na, ns)) {
> pr_debug("Bad cell count for %pOF\n", dev);
> - goto bail;
> + return OF_BAD_ADDR;
> }
> memcpy(addr, in_addr, na * 4);
>
> @@ -533,8 +529,7 @@ static u64 __of_translate_address(struct device_node *dev,
> /* If root, we have finished */
> if (parent == NULL) {
> pr_debug("reached root node\n");
> - result = of_read_number(addr, na);
> - break;
> + return of_read_number(addr, na);
> }
>
> /*
> @@ -543,11 +538,11 @@ static u64 __of_translate_address(struct device_node *dev,
> */
> iorange = find_io_range_by_fwnode(&dev->fwnode);
> if (iorange && (iorange->flags != LOGIC_PIO_CPU_MMIO)) {
> - result = of_read_number(addr + 1, na - 1);
> + u64 result = of_read_number(addr + 1, na - 1);
> pr_debug("indirectIO matched(%pOF) 0x%llx\n",
> dev, result);
> - *host = of_node_get(dev);
> - break;
> + *host = no_free_ptr(dev);
> + return result;
> }
>
> /* Get new parent bus and counts */
> @@ -555,7 +550,7 @@ static u64 __of_translate_address(struct device_node *dev,
> pbus->count_cells(dev, &pna, &pns);
> if (!OF_CHECK_COUNTS(pna, pns)) {
> pr_err("Bad cell count for %pOF\n", dev);
> - break;
> + return OF_BAD_ADDR;
> }
>
> pr_debug("parent bus is %s (na=%d, ns=%d) on %pOF\n",
> @@ -563,7 +558,7 @@ static u64 __of_translate_address(struct device_node *dev,
>
> /* Apply bus translation */
> if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
> - break;
> + return OF_BAD_ADDR;
>
> /* Complete the move up one level */
> na = pna;
> @@ -572,11 +567,8 @@ static u64 __of_translate_address(struct device_node *dev,
>
> of_dump_addr("one level translation:", addr, na);
> }
> - bail:
> - of_node_put(parent);
> - of_node_put(dev);
>
> - return result;
> + return OF_BAD_ADDR;
> }
>
> u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
> @@ -654,19 +646,16 @@ EXPORT_SYMBOL(of_translate_dma_address);
> const __be32 *of_translate_dma_region(struct device_node *dev, const __be32 *prop,
> phys_addr_t *start, size_t *length)
> {
> - struct device_node *parent;
> + struct device_node *parent __free(device_node) = __of_get_dma_parent(dev);
> u64 address, size;
> int na, ns;
>
> - parent = __of_get_dma_parent(dev);
> if (!parent)
> return NULL;
>
> na = of_bus_n_addr_cells(parent);
> ns = of_bus_n_size_cells(parent);
>
> - of_node_put(parent);
> -
> address = of_translate_dma_address(dev, prop);
> if (address == OF_BAD_ADDR)
> return NULL;
> @@ -688,21 +677,19 @@ const __be32 *__of_get_address(struct device_node *dev, int index, int bar_no,
> {
> const __be32 *prop;
> unsigned int psize;
> - struct device_node *parent;
> + struct device_node *parent __free(device_node) = of_get_parent(dev);
> struct of_bus *bus;
> int onesize, i, na, ns;
>
> - /* Get parent & match bus type */
> - parent = of_get_parent(dev);
> if (parent == NULL)
> return NULL;
> +
> + /* match the parent's bus type */
> bus = of_match_bus(parent);
> - if (strcmp(bus->name, "pci") && (bar_no >= 0)) {
> - of_node_put(parent);
> + if (strcmp(bus->name, "pci") && (bar_no >= 0))
> return NULL;
> - }
> +
> bus->count_cells(dev, &na, &ns);
> - of_node_put(parent);
> if (!OF_CHECK_ADDR_COUNT(na))
> return NULL;
>
> @@ -888,14 +875,13 @@ static u64 of_translate_ioport(struct device_node *dev, const __be32 *in_addr,
> */
> int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
> {
> - struct device_node *node = of_node_get(np);
> + struct device_node *node __free(device_node) = of_node_get(np);
> const __be32 *ranges = NULL;
> bool found_dma_ranges = false;
> struct of_range_parser parser;
> struct of_range range;
> struct bus_dma_region *r;
> int len, num_ranges = 0;
> - int ret = 0;
>
> while (node) {
> ranges = of_get_property(node, "dma-ranges", &len);
> @@ -905,10 +891,9 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
> break;
>
> /* Once we find 'dma-ranges', then a missing one is an error */
> - if (found_dma_ranges && !ranges) {
> - ret = -ENODEV;
> - goto out;
> - }
> + if (found_dma_ranges && !ranges)
> + return -ENODEV;
> +
> found_dma_ranges = true;
>
> node = of_get_next_dma_parent(node);
> @@ -916,10 +901,8 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
>
> if (!node || !ranges) {
> pr_debug("no dma-ranges found for node(%pOF)\n", np);
> - ret = -ENODEV;
> - goto out;
> + return -ENODEV;
> }
> -
> of_dma_range_parser_init(&parser, node);
> for_each_of_range(&parser, &range) {
> if (range.cpu_addr == OF_BAD_ADDR) {
> @@ -930,16 +913,12 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
> num_ranges++;
> }
>
> - if (!num_ranges) {
> - ret = -EINVAL;
> - goto out;
> - }
> + if (!num_ranges)
> + return -EINVAL;
>
> r = kcalloc(num_ranges + 1, sizeof(*r), GFP_KERNEL);
> - if (!r) {
> - ret = -ENOMEM;
> - goto out;
> - }
> + if (!r)
> + return -ENOMEM;
>
> /*
> * Record all info in the generic DMA ranges array for struct device,
> @@ -957,9 +936,7 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
> r->size = range.size;
> r++;
> }
> -out:
> - of_node_put(node);
> - return ret;
> + return 0;
> }
> #endif /* CONFIG_HAS_DMA */
>
> @@ -1016,24 +993,18 @@ phys_addr_t __init of_dma_get_max_cpu_address(struct device_node *np)
> */
> bool of_dma_is_coherent(struct device_node *np)
> {
> - struct device_node *node;
> - bool is_coherent = dma_default_coherent;
> -
> - node = of_node_get(np);
> + struct device_node *node __free(device_node) = of_node_get(np);
>
> while (node) {
> - if (of_property_read_bool(node, "dma-coherent")) {
> - is_coherent = true;
> - break;
> - }
> - if (of_property_read_bool(node, "dma-noncoherent")) {
> - is_coherent = false;
> - break;
> - }
> + if (of_property_read_bool(node, "dma-coherent"))
> + return true;
> +
> + if (of_property_read_bool(node, "dma-noncoherent"))
> + return false;
> +
> node = of_get_next_dma_parent(node);
> }
> - of_node_put(node);
> - return is_coherent;
> + return dma_default_coherent;
> }
> EXPORT_SYMBOL_GPL(of_dma_is_coherent);
>
> @@ -1049,20 +1020,14 @@ EXPORT_SYMBOL_GPL(of_dma_is_coherent);
> */
> static bool of_mmio_is_nonposted(struct device_node *np)
> {
> - struct device_node *parent;
> - bool nonposted;
> -
> if (!IS_ENABLED(CONFIG_ARCH_APPLE))
> return false;
>
> - parent = of_get_parent(np);
> + struct device_node *parent __free(device_node) = of_get_parent(np);
> if (!parent)
> return false;
>
> - nonposted = of_property_read_bool(parent, "nonposted-mmio");
> -
> - of_node_put(parent);
> - return nonposted;
> + return of_property_read_bool(parent, "nonposted-mmio");
> }
>
> static int __of_address_to_resource(struct device_node *dev, int index, int bar_no,
> diff --git a/drivers/of/property.c b/drivers/of/property.c
> index a6358ee99b74..b73daf81c99d 100644
> --- a/drivers/of/property.c
> +++ b/drivers/of/property.c
> @@ -40,15 +40,12 @@
> */
> bool of_graph_is_present(const struct device_node *node)
> {
> - struct device_node *ports, *port;
> + struct device_node *ports __free(device_node) = of_get_child_by_name(node, "ports");
>
> - ports = of_get_child_by_name(node, "ports");
> if (ports)
> node = ports;
>
> - port = of_get_child_by_name(node, "port");
> - of_node_put(ports);
> - of_node_put(port);
> + struct device_node *port __free(device_node) = of_get_child_by_name(node, "port");
>
> return !!port;
> }
> @@ -610,9 +607,9 @@ EXPORT_SYMBOL(of_graph_parse_endpoint);
> */
> struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
> {
> - struct device_node *node, *port;
> + struct device_node *port;
> + struct device_node *node __free(device_node) = of_get_child_by_name(parent, "ports");
>
> - node = of_get_child_by_name(parent, "ports");
> if (node)
> parent = node;
>
> @@ -626,8 +623,6 @@ struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
> break;
Trivial but you could use
return port;
}
return NULL;
which I think would make the flow a tiny bit more obvious to anyone who doesn't
know that for_each_child_of_node() leaves it set to NULL on exit.
Maybe use the scoped form a a return_ptr() to make it obvious you are intentionally
holding on to the port node on exit?
> }
>
> - of_node_put(node);
> -
> return port;
> }
> EXPORT_SYMBOL(of_graph_get_port_by_id);
> @@ -655,14 +650,13 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
> * parent port node.
> */
> if (!prev) {
> - struct device_node *node;
> + struct device_node *node __free(device_node) =
> + of_get_child_by_name(parent, "ports");
>
> - node = of_get_child_by_name(parent, "ports");
> if (node)
> parent = node;
>
> port = of_get_child_by_name(parent, "port");
> - of_node_put(node);
Completely trivial but I'd drop the blank line to bring the error check
up into same block of code as the line that gets what it is checking.
>
> if (!port) {
> pr_debug("graph: no port node found in %pOF\n", parent);
>