devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] of: Use __free() based cleanups
@ 2024-04-04 14:15 Rob Herring
  2024-04-04 14:15 ` [PATCH 1/3] of: Add a helper to free property struct Rob Herring
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Rob Herring @ 2024-04-04 14:15 UTC (permalink / raw)
  To: Saravana Kannan; +Cc: Jonathan Cameron, devicetree, linux-kernel

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 <robh@kernel.org>
---
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    | 60 ++++++++++++++++---------------------------------
 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, 70 insertions(+), 142 deletions(-)
---
base-commit: 4cece764965020c22cff7665b18a012006359095
change-id: 20240404-dt-cleanup-free-6d5334b4b368

Best regards,
-- 
Rob Herring <robh@kernel.org>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/3] of: Add a helper to free property struct
  2024-04-04 14:15 [PATCH 0/3] of: Use __free() based cleanups Rob Herring
@ 2024-04-04 14:15 ` Rob Herring
  2024-04-04 23:09   ` Saravana Kannan
  2024-04-06 16:47   ` Jonathan Cameron
  2024-04-04 14:15 ` [PATCH 2/3] of: Use scope based kfree() cleanups Rob Herring
  2024-04-04 14:15 ` [PATCH 3/3] of: Use scope based of_node_put() cleanups Rob Herring
  2 siblings, 2 replies; 14+ messages in thread
From: Rob Herring @ 2024-04-04 14:15 UTC (permalink / raw)
  To: Saravana Kannan; +Cc: Jonathan Cameron, devicetree, linux-kernel

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.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 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


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/3] of: Use scope based kfree() cleanups
  2024-04-04 14:15 [PATCH 0/3] of: Use __free() based cleanups Rob Herring
  2024-04-04 14:15 ` [PATCH 1/3] of: Add a helper to free property struct Rob Herring
@ 2024-04-04 14:15 ` Rob Herring
  2024-04-04 23:15   ` Saravana Kannan
  2024-04-06 16:51   ` Jonathan Cameron
  2024-04-04 14:15 ` [PATCH 3/3] of: Use scope based of_node_put() cleanups Rob Herring
  2 siblings, 2 replies; 14+ messages in thread
From: Rob Herring @ 2024-04-04 14:15 UTC (permalink / raw)
  To: Saravana Kannan; +Cc: Jonathan Cameron, devicetree, linux-kernel

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.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 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


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/3] of: Use scope based of_node_put() cleanups
  2024-04-04 14:15 [PATCH 0/3] of: Use __free() based cleanups Rob Herring
  2024-04-04 14:15 ` [PATCH 1/3] of: Add a helper to free property struct Rob Herring
  2024-04-04 14:15 ` [PATCH 2/3] of: Use scope based kfree() cleanups Rob Herring
@ 2024-04-04 14:15 ` Rob Herring
  2024-04-04 23:21   ` Saravana Kannan
  2024-04-06 17:17   ` Jonathan Cameron
  2 siblings, 2 replies; 14+ messages in thread
From: Rob Herring @ 2024-04-04 14:15 UTC (permalink / raw)
  To: Saravana Kannan; +Cc: Jonathan Cameron, devicetree, linux-kernel

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.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 drivers/of/address.c  | 60 ++++++++++++++++-----------------------------------
 drivers/of/property.c | 22 ++++++-------------
 2 files changed, 26 insertions(+), 56 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index ae46a3605904..f7b2d535a6d1 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -491,7 +491,6 @@ static u64 __of_translate_address(struct device_node *dev,
 				  const __be32 *in_addr, const char *rprop,
 				  struct device_node **host)
 {
-	struct device_node *parent = NULL;
 	struct of_bus *bus, *pbus;
 	__be32 addr[OF_MAX_ADDR_CELLS];
 	int na, ns, pna, pns;
@@ -504,7 +503,7 @@ static u64 __of_translate_address(struct device_node *dev,
 
 	*host = NULL;
 	/* Get parent & match bus type */
-	parent = get_parent(dev);
+	struct device_node *parent __free(device_node) = get_parent(dev);
 	if (parent == NULL)
 		goto bail;
 	bus = of_match_bus(parent);
@@ -573,7 +572,6 @@ 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;
@@ -654,19 +652,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 +683,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 +881,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 +897,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 +907,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 +919,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 +942,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,11 +999,9 @@ 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;
+	struct device_node *node __free(device_node) = of_node_get(np);
 	bool is_coherent = dma_default_coherent;
 
-	node = of_node_get(np);
-
 	while (node) {
 		if (of_property_read_bool(node, "dma-coherent")) {
 			is_coherent = true;
@@ -1032,7 +1013,6 @@ bool of_dma_is_coherent(struct device_node *np)
 		}
 		node = of_get_next_dma_parent(node);
 	}
-	of_node_put(node);
 	return is_coherent;
 }
 EXPORT_SYMBOL_GPL(of_dma_is_coherent);
@@ -1049,19 +1029,17 @@ 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;
 }
 
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


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] of: Add a helper to free property struct
  2024-04-04 14:15 ` [PATCH 1/3] of: Add a helper to free property struct Rob Herring
@ 2024-04-04 23:09   ` Saravana Kannan
  2024-04-06 16:47   ` Jonathan Cameron
  1 sibling, 0 replies; 14+ messages in thread
From: Saravana Kannan @ 2024-04-04 23:09 UTC (permalink / raw)
  To: Rob Herring; +Cc: Jonathan Cameron, devicetree, linux-kernel

On Thu, Apr 4, 2024 at 7:15 AM Rob Herring <robh@kernel.org> wrote:
>
> 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.
>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  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;
>

Reviewed-by: Saravana Kannan <saravanak@google.com>

-Saravana

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] of: Use scope based kfree() cleanups
  2024-04-04 14:15 ` [PATCH 2/3] of: Use scope based kfree() cleanups Rob Herring
@ 2024-04-04 23:15   ` Saravana Kannan
  2024-04-05 12:43     ` Rob Herring
  2024-04-06 16:51   ` Jonathan Cameron
  1 sibling, 1 reply; 14+ messages in thread
From: Saravana Kannan @ 2024-04-04 23:15 UTC (permalink / raw)
  To: Rob Herring; +Cc: Jonathan Cameron, devicetree, linux-kernel

On Thu, Apr 4, 2024 at 7:15 AM Rob Herring <robh@kernel.org> wrote:
>
> 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.
>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  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);

With the scoped stuff, do these function calls need to be in the same
line we are defining these variables? If not, I'd rather that the
calls remain where they were. It feels like a lote to visually parse
and take in from a readability perspective.

>         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 */

Reviewed-by: Saravana Kannan <saravanak@google.com>

-Saravana

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] of: Use scope based of_node_put() cleanups
  2024-04-04 14:15 ` [PATCH 3/3] of: Use scope based of_node_put() cleanups Rob Herring
@ 2024-04-04 23:21   ` Saravana Kannan
  2024-04-05 13:00     ` Rob Herring
  2024-04-06 17:17   ` Jonathan Cameron
  1 sibling, 1 reply; 14+ messages in thread
From: Saravana Kannan @ 2024-04-04 23:21 UTC (permalink / raw)
  To: Rob Herring; +Cc: Jonathan Cameron, devicetree, linux-kernel

On Thu, Apr 4, 2024 at 7:15 AM Rob Herring <robh@kernel.org> 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.
>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  drivers/of/address.c  | 60 ++++++++++++++++-----------------------------------
>  drivers/of/property.c | 22 ++++++-------------
>  2 files changed, 26 insertions(+), 56 deletions(-)
>
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index ae46a3605904..f7b2d535a6d1 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -491,7 +491,6 @@ static u64 __of_translate_address(struct device_node *dev,
>                                   const __be32 *in_addr, const char *rprop,
>                                   struct device_node **host)
>  {
> -       struct device_node *parent = NULL;
>         struct of_bus *bus, *pbus;
>         __be32 addr[OF_MAX_ADDR_CELLS];
>         int na, ns, pna, pns;
> @@ -504,7 +503,7 @@ static u64 __of_translate_address(struct device_node *dev,
>
>         *host = NULL;
>         /* Get parent & match bus type */
> -       parent = get_parent(dev);
> +       struct device_node *parent __free(device_node) = get_parent(dev);

Can we leave the variable definition where it was? We generally define
all the variables up top. So, defining the one variable in the middle
feels weird. I at least get when we do this inside for/if blocks. But
randomly in the middle feels weird.

Similar comments in other places. Since both kfree() and of_put() can
both handle NULL pointers, I'd be surprised if we HAVE to combine
these lines.

Not a very strong position, but I'd rather we didn't. So,

Reviewed-by: Saravana Kannan <saravanak@google.com>

-Saravana

>         if (parent == NULL)
>                 goto bail;
>         bus = of_match_bus(parent);
> @@ -573,7 +572,6 @@ 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;
> @@ -654,19 +652,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 +683,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 +881,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 +897,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 +907,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 +919,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 +942,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,11 +999,9 @@ 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;
> +       struct device_node *node __free(device_node) = of_node_get(np);
>         bool is_coherent = dma_default_coherent;
>
> -       node = of_node_get(np);
> -
>         while (node) {
>                 if (of_property_read_bool(node, "dma-coherent")) {
>                         is_coherent = true;
> @@ -1032,7 +1013,6 @@ bool of_dma_is_coherent(struct device_node *np)
>                 }
>                 node = of_get_next_dma_parent(node);
>         }
> -       of_node_put(node);
>         return is_coherent;
>  }
>  EXPORT_SYMBOL_GPL(of_dma_is_coherent);
> @@ -1049,19 +1029,17 @@ 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;
>  }
>
> 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
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] of: Use scope based kfree() cleanups
  2024-04-04 23:15   ` Saravana Kannan
@ 2024-04-05 12:43     ` Rob Herring
  2024-04-05 19:12       ` Saravana Kannan
  0 siblings, 1 reply; 14+ messages in thread
From: Rob Herring @ 2024-04-05 12:43 UTC (permalink / raw)
  To: Saravana Kannan; +Cc: Jonathan Cameron, devicetree, linux-kernel

On Thu, Apr 4, 2024 at 6:16 PM Saravana Kannan <saravanak@google.com> wrote:
>
> On Thu, Apr 4, 2024 at 7:15 AM Rob Herring <robh@kernel.org> wrote:
> >
> > 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.
> >
> > Signed-off-by: Rob Herring <robh@kernel.org>
> > ---
> >  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);
>
> With the scoped stuff, do these function calls need to be in the same
> line we are defining these variables? If not, I'd rather that the
> calls remain where they were. It feels like a lote to visually parse
> and take in from a readability perspective.

They don't have to be, but if you don't want to get yelled at by the
chief penguin, then yes, they should be together. See the discussions
on adding the scoped iterators. But with the C99 adoption, we can move
the declaration to where the assignment was original.

Rob

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] of: Use scope based of_node_put() cleanups
  2024-04-04 23:21   ` Saravana Kannan
@ 2024-04-05 13:00     ` Rob Herring
  2024-04-05 19:12       ` Saravana Kannan
  0 siblings, 1 reply; 14+ messages in thread
From: Rob Herring @ 2024-04-05 13:00 UTC (permalink / raw)
  To: Saravana Kannan; +Cc: Jonathan Cameron, devicetree, linux-kernel

On Thu, Apr 4, 2024 at 6:22 PM Saravana Kannan <saravanak@google.com> wrote:
>
> On Thu, Apr 4, 2024 at 7:15 AM Rob Herring <robh@kernel.org> 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.
> >
> > Signed-off-by: Rob Herring <robh@kernel.org>
> > ---
> >  drivers/of/address.c  | 60 ++++++++++++++++-----------------------------------
> >  drivers/of/property.c | 22 ++++++-------------
> >  2 files changed, 26 insertions(+), 56 deletions(-)
> >
> > diff --git a/drivers/of/address.c b/drivers/of/address.c
> > index ae46a3605904..f7b2d535a6d1 100644
> > --- a/drivers/of/address.c
> > +++ b/drivers/of/address.c
> > @@ -491,7 +491,6 @@ static u64 __of_translate_address(struct device_node *dev,
> >                                   const __be32 *in_addr, const char *rprop,
> >                                   struct device_node **host)
> >  {
> > -       struct device_node *parent = NULL;
> >         struct of_bus *bus, *pbus;
> >         __be32 addr[OF_MAX_ADDR_CELLS];
> >         int na, ns, pna, pns;
> > @@ -504,7 +503,7 @@ static u64 __of_translate_address(struct device_node *dev,
> >
> >         *host = NULL;
> >         /* Get parent & match bus type */
> > -       parent = get_parent(dev);
> > +       struct device_node *parent __free(device_node) = get_parent(dev);
>
> Can we leave the variable definition where it was? We generally define
> all the variables up top. So, defining the one variable in the middle
> feels weird. I at least get when we do this inside for/if blocks. But
> randomly in the middle feels weird.

There's an 'of_node_get(dev);' before this. Ordering wise, we need to
hold the ref on the child before we get its parent. I suppose I can
also convert that to use the cleanups. I'll have to add another local
ptr to do that though.

>
> Similar comments in other places. Since both kfree() and of_put() can
> both handle NULL pointers, I'd be surprised if we HAVE to combine
> these lines.

https://lore.kernel.org/all/CAHk-=wgRHiV5VSxtfXA4S6aLUmcQYEuB67u3BJPJPtuESs1JyA@mail.gmail.com/

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] of: Use scope based kfree() cleanups
  2024-04-05 12:43     ` Rob Herring
@ 2024-04-05 19:12       ` Saravana Kannan
  0 siblings, 0 replies; 14+ messages in thread
From: Saravana Kannan @ 2024-04-05 19:12 UTC (permalink / raw)
  To: Rob Herring; +Cc: Jonathan Cameron, devicetree, linux-kernel

On Fri, Apr 5, 2024 at 5:44 AM Rob Herring <robh@kernel.org> wrote:
>
> On Thu, Apr 4, 2024 at 6:16 PM Saravana Kannan <saravanak@google.com> wrote:
> >
> > On Thu, Apr 4, 2024 at 7:15 AM Rob Herring <robh@kernel.org> wrote:
> > >
> > > 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.
> > >
> > > Signed-off-by: Rob Herring <robh@kernel.org>
> > > ---
> > >  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);
> >
> > With the scoped stuff, do these function calls need to be in the same
> > line we are defining these variables? If not, I'd rather that the
> > calls remain where they were. It feels like a lote to visually parse
> > and take in from a readability perspective.
>
> They don't have to be, but if you don't want to get yelled at by the
> chief penguin, then yes, they should be together. See the discussions
> on adding the scoped iterators. But with the C99 adoption, we can move
> the declaration to where the assignment was original.

Thanks for the context and the link in the other email.

Review-by without reservations.

-Saravana

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] of: Use scope based of_node_put() cleanups
  2024-04-05 13:00     ` Rob Herring
@ 2024-04-05 19:12       ` Saravana Kannan
  0 siblings, 0 replies; 14+ messages in thread
From: Saravana Kannan @ 2024-04-05 19:12 UTC (permalink / raw)
  To: Rob Herring; +Cc: Jonathan Cameron, devicetree, linux-kernel

On Fri, Apr 5, 2024 at 6:01 AM Rob Herring <robh@kernel.org> wrote:
>
> On Thu, Apr 4, 2024 at 6:22 PM Saravana Kannan <saravanak@google.com> wrote:
> >
> > On Thu, Apr 4, 2024 at 7:15 AM Rob Herring <robh@kernel.org> 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.
> > >
> > > Signed-off-by: Rob Herring <robh@kernel.org>
> > > ---
> > >  drivers/of/address.c  | 60 ++++++++++++++++-----------------------------------
> > >  drivers/of/property.c | 22 ++++++-------------
> > >  2 files changed, 26 insertions(+), 56 deletions(-)
> > >
> > > diff --git a/drivers/of/address.c b/drivers/of/address.c
> > > index ae46a3605904..f7b2d535a6d1 100644
> > > --- a/drivers/of/address.c
> > > +++ b/drivers/of/address.c
> > > @@ -491,7 +491,6 @@ static u64 __of_translate_address(struct device_node *dev,
> > >                                   const __be32 *in_addr, const char *rprop,
> > >                                   struct device_node **host)
> > >  {
> > > -       struct device_node *parent = NULL;
> > >         struct of_bus *bus, *pbus;
> > >         __be32 addr[OF_MAX_ADDR_CELLS];
> > >         int na, ns, pna, pns;
> > > @@ -504,7 +503,7 @@ static u64 __of_translate_address(struct device_node *dev,
> > >
> > >         *host = NULL;
> > >         /* Get parent & match bus type */
> > > -       parent = get_parent(dev);
> > > +       struct device_node *parent __free(device_node) = get_parent(dev);
> >
> > Can we leave the variable definition where it was? We generally define
> > all the variables up top. So, defining the one variable in the middle
> > feels weird. I at least get when we do this inside for/if blocks. But
> > randomly in the middle feels weird.
>
> There's an 'of_node_get(dev);' before this. Ordering wise, we need to
> hold the ref on the child before we get its parent. I suppose I can
> also convert that to use the cleanups. I'll have to add another local
> ptr to do that though.
>
> >
> > Similar comments in other places. Since both kfree() and of_put() can
> > both handle NULL pointers, I'd be surprised if we HAVE to combine
> > these lines.
>
> https://lore.kernel.org/all/CAHk-=wgRHiV5VSxtfXA4S6aLUmcQYEuB67u3BJPJPtuESs1JyA@mail.gmail.com/

Review-by without reservations.

-Saravana

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] of: Add a helper to free property struct
  2024-04-04 14:15 ` [PATCH 1/3] of: Add a helper to free property struct Rob Herring
  2024-04-04 23:09   ` Saravana Kannan
@ 2024-04-06 16:47   ` Jonathan Cameron
  1 sibling, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2024-04-06 16:47 UTC (permalink / raw)
  To: Rob Herring; +Cc: Saravana Kannan, devicetree, linux-kernel

On Thu, 04 Apr 2024 09:15:10 -0500
Rob Herring <robh@kernel.org> wrote:

> 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.
> 
> Signed-off-by: Rob Herring <robh@kernel.org>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] of: Use scope based kfree() cleanups
  2024-04-04 14:15 ` [PATCH 2/3] of: Use scope based kfree() cleanups Rob Herring
  2024-04-04 23:15   ` Saravana Kannan
@ 2024-04-06 16:51   ` Jonathan Cameron
  1 sibling, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2024-04-06 16:51 UTC (permalink / raw)
  To: Rob Herring; +Cc: Saravana Kannan, devicetree, linux-kernel

On Thu, 04 Apr 2024 09:15:11 -0500
Rob Herring <robh@kernel.org> wrote:

> 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.
> 
> Signed-off-by: Rob Herring <robh@kernel.org>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] of: Use scope based of_node_put() cleanups
  2024-04-04 14:15 ` [PATCH 3/3] of: Use scope based of_node_put() cleanups Rob Herring
  2024-04-04 23:21   ` Saravana Kannan
@ 2024-04-06 17:17   ` Jonathan Cameron
  1 sibling, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2024-04-06 17:17 UTC (permalink / raw)
  To: Rob Herring; +Cc: Saravana Kannan, devicetree, linux-kernel

On Thu, 04 Apr 2024 09:15:12 -0500
Rob Herring <robh@kernel.org> 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.
> 
> Signed-off-by: Rob Herring <robh@kernel.org>

Hi Rob,

Looks good in general. A few suggestions inline.
First one is a little more complex, but I think will give you a better end result

The others are readability improvements enabled by the changes you've made
that I think you could validly change in this same patch.

Jonathan

> ---
>  drivers/of/address.c  | 60 ++++++++++++++++-----------------------------------
>  drivers/of/property.c | 22 ++++++-------------
>  2 files changed, 26 insertions(+), 56 deletions(-)
> 
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index ae46a3605904..f7b2d535a6d1 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -491,7 +491,6 @@ static u64 __of_translate_address(struct device_node *dev,
>  				  const __be32 *in_addr, const char *rprop,
>  				  struct device_node **host)
>  {
> -	struct device_node *parent = NULL;
>  	struct of_bus *bus, *pbus;
>  	__be32 addr[OF_MAX_ADDR_CELLS];
>  	int na, ns, pna, pns;
> @@ -504,7 +503,7 @@ static u64 __of_translate_address(struct device_node *dev,
>  
>  	*host = NULL;
>  	/* Get parent & match bus type */
> -	parent = get_parent(dev);
> +	struct device_node *parent __free(device_node) = get_parent(dev);

This is an order change as we'll put this node after dev

Whilst probably fine, I'd call that out in the patch description or just throw
in an earlier
struct device_node *dev_node __free(device_node) = of_node_get(dev);


Obviously the release order doesn't actually matter but a reader has to think
about it briefly to be sure.

Bonus if you do that is that you get to do direct returns at the error condition
and potentially in the breaks out of the loop. To my eye that's a readability
advantage.

In at least one place you could also steal the pointer rather than
getting another reference to dev (taking it to at least 2) then dropping
one of them in the exit path. Can use no_free_ptr() for that.

From readability point of view you'd only want to do that with a direct return.
 		
			*host = no_free_ptr(dev_node);
			return result;
		}




>  	if (parent == NULL)
>  		goto bail;
>  	bus = of_match_bus(parent);
> @@ -573,7 +572,6 @@ 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);
>  


> @@ -1016,11 +999,9 @@ 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;
> +	struct device_node *node __free(device_node) = of_node_get(np);
>  	bool is_coherent = dma_default_coherent;
>  
> -	node = of_node_get(np);
> -
>  	while (node) {
>  		if (of_property_read_bool(node, "dma-coherent")) {
>  			is_coherent = true;

			return true;

and same in the other branch given you break out the loop and return it directly.


> @@ -1032,7 +1013,6 @@ bool of_dma_is_coherent(struct device_node *np)
>  		}
>  		node = of_get_next_dma_parent(node);
>  	}
> -	of_node_put(node);
>  	return is_coherent;
With above early returns

	return dma_default_coherent;

and drop the is_coherent variable as no longer used.

This sort of related cleanup is one reason I really like the cleanup.h magic.


>  }
>  EXPORT_SYMBOL_GPL(of_dma_is_coherent);
> @@ -1049,19 +1029,17 @@ 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()

>  }
>  

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2024-04-06 17:17 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-04 14:15 [PATCH 0/3] of: Use __free() based cleanups Rob Herring
2024-04-04 14:15 ` [PATCH 1/3] of: Add a helper to free property struct Rob Herring
2024-04-04 23:09   ` Saravana Kannan
2024-04-06 16:47   ` Jonathan Cameron
2024-04-04 14:15 ` [PATCH 2/3] of: Use scope based kfree() cleanups Rob Herring
2024-04-04 23:15   ` Saravana Kannan
2024-04-05 12:43     ` Rob Herring
2024-04-05 19:12       ` Saravana Kannan
2024-04-06 16:51   ` Jonathan Cameron
2024-04-04 14:15 ` [PATCH 3/3] of: Use scope based of_node_put() cleanups Rob Herring
2024-04-04 23:21   ` Saravana Kannan
2024-04-05 13:00     ` Rob Herring
2024-04-05 19:12       ` Saravana Kannan
2024-04-06 17:17   ` Jonathan Cameron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).