2024-01-28 16:06:17

by Jonathan Cameron

[permalink] [raw]
Subject: [RFC PATCH 0/5] of: automate of_node_put() - new approach to loops.

From: Jonathan Cameron <[email protected]>

+CC includes peopleinterested in property.h equivalents to minimize
duplication of discussion. Outcome of this discussion will affect:
https://lore.kernel.org/all/[email protected]/
[PATCH 00/13] device property / IIO: Use cleanup.h magic for fwnode_handle_put() handling.

In discussion of previous approach with Rob Herring we talked about various
ways to avoid a disconnect between the declaration of the __free(device_node)
and the first non NULL assignment. Making this connection clear is useful for 2
reasons:
1) Avoids out of order cleanup with respect to other cleanup.h usage.
2) Avoids disconnect between how cleanup is to be done and how the reference
was acquired in the first place.

https://lore.kernel.org/all/[email protected]/

The options we discussed are:

1) Ignore this issue and merge original set.

2) Always put the declaration just before the for loop and don't set it NULL.

{
int ret;

ret = ... and other fun code.

struct device_node *child __free(device_node);
for_each_child_of_node(np, child) {
}
}

This works but careful review is needed to ensure that this unusual pattern is
followed. We don't set it to NULL as the loop will do that anyway if there are
no child nodes, or the loop finishes without an early break or return.

3) Introduced the pointer to auto put device_node only within the
for loop scope.

+#define for_each_child_of_node_scoped(parent, child) \
+ for (struct device_node *child __free(device_node) = \
+ of_get_next_child(parent, NULL); \
+ child != NULL; \
+ child = of_get_next_available_child(parent, child))
+

This series is presenting option 3. I only implemented this loop out of
all the similar ones and it is only compile tested.

Disadvantage Rob raised is that it isn't obvious this macro will instantiate
a struct device_node *child. I can't see a way around that other than option 2
above, but all suggestions welcome. Note that if a conversion leaves an
'external' struct device_node *child variable, in many cases the compiler
will catch that as an unused variable. We don't currently run shaddow
variable detection in normal kernel builds, but that could also be used
to catch such bugs.

All comments welcome.

Jonathan Cameron (5):
of: Add cleanup.h based auto release via __free(device_node) markings.
of: Introduce for_each_child_of_node_scoped() to automate
of_node_put() handling
of: unittest: Use __free(device_node)
iio: adc: fsl-imx25-gcq: Use for_each_child_node_scoped()
iio: adc: rcar-gyroadc: use for_each_child_node_scoped()

drivers/iio/adc/fsl-imx25-gcq.c | 13 +++----------
drivers/iio/adc/rcar-gyroadc.c | 21 ++++++---------------
drivers/of/unittest.c | 11 +++--------
include/linux/of.h | 8 ++++++++
4 files changed, 20 insertions(+), 33 deletions(-)

--
2.43.0



2024-01-28 16:06:35

by Jonathan Cameron

[permalink] [raw]
Subject: [RFC PATCH 1/5] of: Add cleanup.h based auto release via __free(device_node) markings.

From: Jonathan Cameron <[email protected]>

The recent addition of scope based cleanup support to the kernel
provides a convenient tool to reduce the chances of leaking reference
counts where of_node_put() should have been called in an error path.

This enables
struct device_node *child __free(device_node) = NULL;

for_each_child_of_node(np, child) {
if (test)
return test;
}

with no need for a manual call of of_node_put().
A following patch will reduce the scope of the child variable to the
for loop, to avoid an issues with ordering of autocleanup, and make it
obvious when this assigned a non NULL value.

In this simple example the gains are small but there are some very
complex error handling cases buried in these loops that will be
greatly simplified by enabling early returns with out the need
for this manual of_node_put() call.

Note that there are coccinelle checks in
scripts/coccinelle/iterators/for_each_child.cocci to detect a failure
to call of_node_put(). This new approach does not cause false positives.
Longer term we may want to add scripting to check this new approach is
done correctly with no double of_node_put() calls being introduced due
to the auto cleanup. It may also be useful to script finding places
this new approach is useful.

Signed-off-by: Jonathan Cameron <[email protected]>
---
include/linux/of.h | 2 ++
1 file changed, 2 insertions(+)

diff --git a/include/linux/of.h b/include/linux/of.h
index 6a9ddf20e79a..50e882ee91da 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -13,6 +13,7 @@
*/
#include <linux/types.h>
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/errno.h>
#include <linux/kobject.h>
#include <linux/mod_devicetable.h>
@@ -134,6 +135,7 @@ static inline struct device_node *of_node_get(struct device_node *node)
}
static inline void of_node_put(struct device_node *node) { }
#endif /* !CONFIG_OF_DYNAMIC */
+DEFINE_FREE(device_node, struct device_node *, if (_T) of_node_put(_T))

/* Pointer for first entry in chain of all nodes. */
extern struct device_node *of_root;
--
2.43.0


2024-01-28 16:06:52

by Jonathan Cameron

[permalink] [raw]
Subject: [RFC PATCH 2/5] of: Introduce for_each_child_of_node_scoped() to automate of_node_put() handling

From: Jonathan Cameron <[email protected]>

To avoid issues with out of order cleanup, or ambiguity about when the
auto freed data is first instantiated, do it within the for loop definition.

The disadvantage is that the struct device_node *child variable creation
is not immediately obvious where this is used.
However, in many cases, if there is another definition of
struct device_node *child; the compiler / static analysers will notify us
that it is unused, or uninitialized.

Signed-off-by: Jonathan Cameron <[email protected]>
---
include/linux/of.h | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/include/linux/of.h b/include/linux/of.h
index 50e882ee91da..f822226eac6d 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1434,6 +1434,12 @@ static inline int of_property_read_s32(const struct device_node *np,
for (child = of_get_next_available_child(parent, NULL); child != NULL; \
child = of_get_next_available_child(parent, child))

+#define for_each_child_of_node_scoped(parent, child) \
+ for (struct device_node *child __free(device_node) = \
+ of_get_next_child(parent, NULL); \
+ child != NULL; \
+ child = of_get_next_available_child(parent, child))
+
#define for_each_of_cpu_node(cpu) \
for (cpu = of_get_next_cpu_node(NULL); cpu != NULL; \
cpu = of_get_next_cpu_node(cpu))
--
2.43.0


2024-01-28 16:07:08

by Jonathan Cameron

[permalink] [raw]
Subject: [RFC PATCH 3/5] of: unittest: Use for_each_child_of_node_scoped()

From: Jonathan Cameron <[email protected]>

A simple example of the utility of this autocleanup approach to
handling of_node_put()

Signed-off-by: Jonathan Cameron <[email protected]>
---
drivers/of/unittest.c | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index cfd60e35a899..d353327767b3 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -233,27 +233,22 @@ static void __init of_unittest_dynamic(void)

static int __init of_unittest_check_node_linkage(struct device_node *np)
{
- struct device_node *child;
int count = 0, rc;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
if (child->parent != np) {
pr_err("Child node %pOFn links to wrong parent %pOFn\n",
child, np);
- rc = -EINVAL;
- goto put_child;
+ return -EINVAL;
}

rc = of_unittest_check_node_linkage(child);
if (rc < 0)
- goto put_child;
+ return rc;
count += rc;
}

return count + 1;
-put_child:
- of_node_put(child);
- return rc;
}

static void __init of_unittest_check_tree_linkage(void)
--
2.43.0


2024-01-28 16:07:26

by Jonathan Cameron

[permalink] [raw]
Subject: [RFC PATCH 4/5] iio: adc: fsl-imx25-gcq: Use for_each_child_node_scoped()

From: Jonathan Cameron <[email protected]>

Using automated cleanup reduces chance of an reference count leak
and simplfies the code.

Signed-off-by: Jonathan Cameron <[email protected]>

---
Chances since v1: Use new for_each_child_node_scoped()
---
drivers/iio/adc/fsl-imx25-gcq.c | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c
index 68c813de0605..a32b5f68768e 100644
--- a/drivers/iio/adc/fsl-imx25-gcq.c
+++ b/drivers/iio/adc/fsl-imx25-gcq.c
@@ -199,7 +199,6 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
struct mx25_gcq_priv *priv)
{
struct device_node *np = pdev->dev.of_node;
- struct device_node *child;
struct device *dev = &pdev->dev;
int ret, i;

@@ -216,7 +215,7 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
MX25_ADCQ_CFG_IN(i) |
MX25_ADCQ_CFG_REFN_NGND2);

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
u32 reg;
u32 refp = MX25_ADCQ_CFG_REFP_INT;
u32 refn = MX25_ADCQ_CFG_REFN_NGND2;
@@ -224,14 +223,12 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
ret = of_property_read_u32(child, "reg", &reg);
if (ret) {
dev_err(dev, "Failed to get reg property\n");
- of_node_put(child);
return ret;
}

if (reg >= MX25_NUM_CFGS) {
dev_err(dev,
"reg value is greater than the number of available configuration registers\n");
- of_node_put(child);
return -EINVAL;
}

@@ -243,10 +240,9 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
case MX25_ADC_REFP_XP:
case MX25_ADC_REFP_YP:
ret = mx25_gcq_ext_regulator_setup(&pdev->dev, priv, refp);
- if (ret) {
- of_node_put(child);
+ if (ret)
return ret;
- }
+
priv->channel_vref_mv[reg] =
regulator_get_voltage(priv->vref[refp]);
/* Conversion from uV to mV */
@@ -257,7 +253,6 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
break;
default:
dev_err(dev, "Invalid positive reference %d\n", refp);
- of_node_put(child);
return -EINVAL;
}

@@ -270,12 +265,10 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,

if ((refp & MX25_ADCQ_CFG_REFP_MASK) != refp) {
dev_err(dev, "Invalid fsl,adc-refp property value\n");
- of_node_put(child);
return -EINVAL;
}
if ((refn & MX25_ADCQ_CFG_REFN_MASK) != refn) {
dev_err(dev, "Invalid fsl,adc-refn property value\n");
- of_node_put(child);
return -EINVAL;
}

--
2.43.0


2024-01-28 16:07:43

by Jonathan Cameron

[permalink] [raw]
Subject: [RFC PATCH 5/5] iio: adc: rcar-gyroadc: use for_each_child_node_scoped()

From: Jonathan Cameron <[email protected]>

Using automated cleanup to replace of_node_put() handling allows for
a simplfied flow by enabling direct returns on errors.

Signed-off-by: Jonathan Cameron <[email protected]>
---
drivers/iio/adc/rcar-gyroadc.c | 21 ++++++---------------
1 file changed, 6 insertions(+), 15 deletions(-)

diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c
index d524f2e8e927..6d9d286cb5df 100644
--- a/drivers/iio/adc/rcar-gyroadc.c
+++ b/drivers/iio/adc/rcar-gyroadc.c
@@ -318,7 +318,6 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
struct rcar_gyroadc *priv = iio_priv(indio_dev);
struct device *dev = priv->dev;
struct device_node *np = dev->of_node;
- struct device_node *child;
struct regulator *vref;
unsigned int reg;
unsigned int adcmode = -1, childmode;
@@ -326,7 +325,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
unsigned int num_channels;
int ret, first = 1;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
of_id = of_match_node(rcar_gyroadc_child_match, child);
if (!of_id) {
dev_err(dev, "Ignoring unsupported ADC \"%pOFn\".",
@@ -352,7 +351,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_3);
break;
default:
- goto err_e_inval;
+ return -EINVAL;
}

/*
@@ -369,7 +368,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
dev_err(dev,
"Failed to get child reg property of ADC \"%pOFn\".\n",
child);
- goto err_of_node_put;
+ return ret;
}

/* Channel number is too high. */
@@ -377,7 +376,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
dev_err(dev,
"Only %i channels supported with %pOFn, but reg = <%i>.\n",
num_channels, child, reg);
- goto err_e_inval;
+ return -EINVAL;
}
}

@@ -386,7 +385,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
dev_err(dev,
"Channel %i uses different ADC mode than the rest.\n",
reg);
- goto err_e_inval;
+ return -EINVAL;
}

/* Channel is valid, grab the regulator. */
@@ -396,8 +395,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
if (IS_ERR(vref)) {
dev_dbg(dev, "Channel %i 'vref' supply not connected.\n",
reg);
- ret = PTR_ERR(vref);
- goto err_of_node_put;
+ return PTR_ERR(vref);
}

priv->vref[reg] = vref;
@@ -422,7 +420,6 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
* we can stop parsing here.
*/
if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) {
- of_node_put(child);
break;
}
}
@@ -433,12 +430,6 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
}

return 0;
-
-err_e_inval:
- ret = -EINVAL;
-err_of_node_put:
- of_node_put(child);
- return ret;
}

static void rcar_gyroadc_deinit_supplies(struct iio_dev *indio_dev)
--
2.43.0


2024-01-28 18:07:48

by Julia Lawall

[permalink] [raw]
Subject: Re: [RFC PATCH 0/5] of: automate of_node_put() - new approach to loops.



On Sun, 28 Jan 2024, Jonathan Cameron wrote:

> From: Jonathan Cameron <[email protected]>
>
> +CC includes peopleinterested in property.h equivalents to minimize
> duplication of discussion. Outcome of this discussion will affect:
> https://lore.kernel.org/all/[email protected]/
> [PATCH 00/13] device property / IIO: Use cleanup.h magic for fwnode_handle_put() handling.
>
> In discussion of previous approach with Rob Herring we talked about various
> ways to avoid a disconnect between the declaration of the __free(device_node)
> and the first non NULL assignment. Making this connection clear is useful for 2
> reasons:
> 1) Avoids out of order cleanup with respect to other cleanup.h usage.
> 2) Avoids disconnect between how cleanup is to be done and how the reference
> was acquired in the first place.
>
> https://lore.kernel.org/all/[email protected]/
>
> The options we discussed are:
>
> 1) Ignore this issue and merge original set.
>
> 2) Always put the declaration just before the for loop and don't set it NULL.
>
> {
> int ret;
>
> ret = ... and other fun code.
>
> struct device_node *child __free(device_node);
> for_each_child_of_node(np, child) {
> }
> }
>
> This works but careful review is needed to ensure that this unusual pattern is
> followed. We don't set it to NULL as the loop will do that anyway if there are
> no child nodes, or the loop finishes without an early break or return.
>
> 3) Introduced the pointer to auto put device_node only within the
> for loop scope.
>
> +#define for_each_child_of_node_scoped(parent, child) \
> + for (struct device_node *child __free(device_node) = \
> + of_get_next_child(parent, NULL); \
> + child != NULL; \
> + child = of_get_next_available_child(parent, child))
> +
>
> This series is presenting option 3. I only implemented this loop out of
> all the similar ones and it is only compile tested.
>
> Disadvantage Rob raised is that it isn't obvious this macro will instantiate
> a struct device_node *child. I can't see a way around that other than option 2
> above, but all suggestions welcome. Note that if a conversion leaves an
> 'external' struct device_node *child variable, in many cases the compiler
> will catch that as an unused variable. We don't currently run shaddow
> variable detection in normal kernel builds, but that could also be used
> to catch such bugs.
>
> All comments welcome.

It looks promising to get rid of a lot of clunky and error-prone
error-handling code.

I guess that

for_each_child_of_node_scoped(parent, struct device_node *, child)

would seem too verbose?

There are a lot of opportunities for device_node loops, but also for some
more obscure loops over other types. And there are a lot of of_node_puts
that could be eliminated independent of loops.

julia

>
> Jonathan Cameron (5):
> of: Add cleanup.h based auto release via __free(device_node) markings.
> of: Introduce for_each_child_of_node_scoped() to automate
> of_node_put() handling
> of: unittest: Use __free(device_node)
> iio: adc: fsl-imx25-gcq: Use for_each_child_node_scoped()
> iio: adc: rcar-gyroadc: use for_each_child_node_scoped()
>
> drivers/iio/adc/fsl-imx25-gcq.c | 13 +++----------
> drivers/iio/adc/rcar-gyroadc.c | 21 ++++++---------------
> drivers/of/unittest.c | 11 +++--------
> include/linux/of.h | 8 ++++++++
> 4 files changed, 20 insertions(+), 33 deletions(-)
>
> --
> 2.43.0
>
>

2024-01-28 21:11:40

by David Lechner

[permalink] [raw]
Subject: Re: [RFC PATCH 2/5] of: Introduce for_each_child_of_node_scoped() to automate of_node_put() handling

On Sun, Jan 28, 2024 at 10:06 AM Jonathan Cameron <[email protected]> wrote:
>
> From: Jonathan Cameron <[email protected]>
>
> To avoid issues with out of order cleanup, or ambiguity about when the
> auto freed data is first instantiated, do it within the for loop definition.
>
> The disadvantage is that the struct device_node *child variable creation
> is not immediately obvious where this is used.
> However, in many cases, if there is another definition of
> struct device_node *child; the compiler / static analysers will notify us
> that it is unused, or uninitialized.
>
> Signed-off-by: Jonathan Cameron <[email protected]>
> ---
> include/linux/of.h | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/include/linux/of.h b/include/linux/of.h
> index 50e882ee91da..f822226eac6d 100644
> --- a/include/linux/of.h
> +++ b/include/linux/of.h
> @@ -1434,6 +1434,12 @@ static inline int of_property_read_s32(const struct device_node *np,
> for (child = of_get_next_available_child(parent, NULL); child != NULL; \
> child = of_get_next_available_child(parent, child))
>
> +#define for_each_child_of_node_scoped(parent, child) \
> + for (struct device_node *child __free(device_node) = \
> + of_get_next_child(parent, NULL); \
> + child != NULL; \
> + child = of_get_next_available_child(parent, child))

Doesn't this need to match the initializer (of_get_next_child)?
Otherwise it seems like the first node could be a disabled node but no
other disabled nodes would be included in the iteration.

It seems like we would want two macros, one for each variation,
analogous to for_each_child_of_node() and
for_each_available_child_of_node().


> +
> #define for_each_of_cpu_node(cpu) \
> for (cpu = of_get_next_cpu_node(NULL); cpu != NULL; \
> cpu = of_get_next_cpu_node(cpu))
> --
> 2.43.0
>
>

2024-01-29 06:55:31

by Julia Lawall

[permalink] [raw]
Subject: Re: [RFC PATCH 2/5] of: Introduce for_each_child_of_node_scoped() to automate of_node_put() handling



On Sun, 28 Jan 2024, David Lechner wrote:

> On Sun, Jan 28, 2024 at 10:06 AM Jonathan Cameron <[email protected]> wrote:
> >
> > From: Jonathan Cameron <[email protected]>
> >
> > To avoid issues with out of order cleanup, or ambiguity about when the
> > auto freed data is first instantiated, do it within the for loop definition.
> >
> > The disadvantage is that the struct device_node *child variable creation
> > is not immediately obvious where this is used.
> > However, in many cases, if there is another definition of
> > struct device_node *child; the compiler / static analysers will notify us
> > that it is unused, or uninitialized.
> >
> > Signed-off-by: Jonathan Cameron <[email protected]>
> > ---
> > include/linux/of.h | 6 ++++++
> > 1 file changed, 6 insertions(+)
> >
> > diff --git a/include/linux/of.h b/include/linux/of.h
> > index 50e882ee91da..f822226eac6d 100644
> > --- a/include/linux/of.h
> > +++ b/include/linux/of.h
> > @@ -1434,6 +1434,12 @@ static inline int of_property_read_s32(const struct device_node *np,
> > for (child = of_get_next_available_child(parent, NULL); child != NULL; \
> > child = of_get_next_available_child(parent, child))
> >
> > +#define for_each_child_of_node_scoped(parent, child) \
> > + for (struct device_node *child __free(device_node) = \
> > + of_get_next_child(parent, NULL); \
> > + child != NULL; \
> > + child = of_get_next_available_child(parent, child))
>
> Doesn't this need to match the initializer (of_get_next_child)?
> Otherwise it seems like the first node could be a disabled node but no
> other disabled nodes would be included in the iteration.
>
> It seems like we would want two macros, one for each variation,
> analogous to for_each_child_of_node() and
> for_each_available_child_of_node().

There are a bunch of iterators, and I guess a scoped version is needed for
each of them?

julia


>
>
> > +
> > #define for_each_of_cpu_node(cpu) \
> > for (cpu = of_get_next_cpu_node(NULL); cpu != NULL; \
> > cpu = of_get_next_cpu_node(cpu))
> > --
> > 2.43.0
> >
> >
>

2024-01-29 19:52:59

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [RFC PATCH 0/5] of: automate of_node_put() - new approach to loops.

On Mon, 29 Jan 2024 15:02:19 +0100 (CET)
Julia Lawall <[email protected]> wrote:

> On Mon, 29 Jan 2024, Jonathan Cameron wrote:
>
> > On Sun, 28 Jan 2024 19:06:53 +0100 (CET)
> > Julia Lawall <[email protected]> wrote:
> >
> > > On Sun, 28 Jan 2024, Jonathan Cameron wrote:
> > >
> > > > From: Jonathan Cameron <[email protected]>
> > > >
> > > > +CC includes peopleinterested in property.h equivalents to minimize
> > > > duplication of discussion. Outcome of this discussion will affect:
> > > > https://lore.kernel.org/all/[email protected]/
> > > > [PATCH 00/13] device property / IIO: Use cleanup.h magic for fwnode_handle_put() handling.
> > > >
> > > > In discussion of previous approach with Rob Herring we talked about various
> > > > ways to avoid a disconnect between the declaration of the __free(device_node)
> > > > and the first non NULL assignment. Making this connection clear is useful for 2
> > > > reasons:
> > > > 1) Avoids out of order cleanup with respect to other cleanup.h usage.
> > > > 2) Avoids disconnect between how cleanup is to be done and how the reference
> > > > was acquired in the first place.
> > > >
> > > > https://lore.kernel.org/all/[email protected]/
> > > >
> > > > The options we discussed are:
> > > >
> > > > 1) Ignore this issue and merge original set.
> > > >
> > > > 2) Always put the declaration just before the for loop and don't set it NULL.
> > > >
> > > > {
> > > > int ret;
> > > >
> > > > ret = ... and other fun code.
> > > >
> > > > struct device_node *child __free(device_node);
> > > > for_each_child_of_node(np, child) {
> > > > }
> > > > }
> > > >
> > > > This works but careful review is needed to ensure that this unusual pattern is
> > > > followed. We don't set it to NULL as the loop will do that anyway if there are
> > > > no child nodes, or the loop finishes without an early break or return.
> > > >
> > > > 3) Introduced the pointer to auto put device_node only within the
> > > > for loop scope.
> > > >
> > > > +#define for_each_child_of_node_scoped(parent, child) \
> > > > + for (struct device_node *child __free(device_node) = \
> > > > + of_get_next_child(parent, NULL); \
> > > > + child != NULL; \
> > > > + child = of_get_next_available_child(parent, child))
> > > > +
> > > >
> > > > This series is presenting option 3. I only implemented this loop out of
> > > > all the similar ones and it is only compile tested.
> > > >
> > > > Disadvantage Rob raised is that it isn't obvious this macro will instantiate
> > > > a struct device_node *child. I can't see a way around that other than option 2
> > > > above, but all suggestions welcome. Note that if a conversion leaves an
> > > > 'external' struct device_node *child variable, in many cases the compiler
> > > > will catch that as an unused variable. We don't currently run shaddow
> > > > variable detection in normal kernel builds, but that could also be used
> > > > to catch such bugs.
> > > >
> > > > All comments welcome.
> > >
> > > It looks promising to get rid of a lot of clunky and error-prone
> > > error-handling code.
> >
> > Absolutely. I think I spotted 2 bugs whilst just looking for places this pattern
> > doesn't apply. Will circle back to those once this discussion is resolved.
> > I think I've taken dozen's of fixes for cases where these were missed over the years
> > so hoping this means I'll never see another one!
> >
> > >
> > > I guess that
> > >
> > > for_each_child_of_node_scoped(parent, struct device_node *, child)
> > >
> > > would seem too verbose?
> >
> > Intent just to make the allocated internal type clear? Sure we can do that if
> > it helps with making it clear something is being allocated.
> > I can't think of a way this could be used with anything other than
> > a struct device_node * as the second parameter but I guess it still helps
> > 'hint' at what is going on..

To touch back on this, I'm still not sure what your intent was in suggesting
having the explicit struct device_node *

> >
> > >
> > > There are a lot of opportunities for device_node loops, but also for some
> > > more obscure loops over other types.
> >
> > > And there are a lot of of_node_puts
> > > that could be eliminated independent of loops.
> >
> > The non loop cases should be handled via the __free(device_node) as provided
> > by patch 1. We'll need to keep the declaration local and initial assignment
> > together but that is easy enough to do and similar to the many other cleanup.h
> > usecases that are surfacing.
>
> I tried the following semantic patch:
>
> @@
> identifier x,f;
> attribute name __free;
> expression list es;
> expression e;
> statement S;
> @@
>
> {
> ... when != S
> struct device_node *x
> + __free(device_node)
> ;
> ... when strict
> x = f(es);
> <... when any
> when != x = e
> -of_node_put(x);
> ...>
> -of_node_put(x);
> }
>
Nice.
> It is written defensively in various ways:
>
> when != S means tha tthe device_node declaration has t be at the top of
> the block, perhaps with other declarations before it.
>
> when strict means that all paths must lead from the declaration to the
> initialization. So there is no need to intiialize the variable to NULL,
> as far as I understand.
>
> when != x = e means that the declared variable is not reinitialized, which
> would require keeping the previous of_node_put.
>
> There is an of_node_put at the end of the block, so the use of __free
> doesn't change the lifetime.
>
> An unfortunate aspect of the last constraint is that some functions may
> declare multiple device_node variables, and only one of the of_not_puts
> can come at the very end of the block. This can be solved by just running
> the semantic patch again.
>
> An alternative would be to move the initialization up to the declaration,
> but the result was often a bit ugly, due to the various initialization
> function calls having long names and argument lists.

You have to do that in order to ensure there is no window for someone to
easily insert code that leaves them uninitialized.

Linus had some rather specific comments on that being the only right way to
do it.

>
> The output is below. I have looked quickly through all of the changes and
> they all look reasonable, but have not tried compiling anything (which I
> guess wouldn't currently work anyway).
>
> julia
>

I picked a couple from the end. They show the sort of things that
would want cleaning up. The script is great for finding low hanging
fruit but as you've identified there is often some stuff that isn't
easy to automate.

> diff -u -p a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c
> --- a/drivers/clk/clk-nomadik.c
> +++ b/drivers/clk/clk-nomadik.c
> @@ -87,7 +87,7 @@ static const struct of_device_id nomadik
>
> static void __init nomadik_src_init(void)
> {
> - struct device_node *np;
> + struct device_node *np __free(device_node);
> u32 val;
>
> np = of_find_matching_node(NULL, nomadik_src_match);
> @@ -134,7 +134,6 @@ static void __init nomadik_src_init(void
> register_reboot_notifier(&nomadik_clk_reboot_notifier);
>
> out_put:
Can avoid the label given nothing to do any more.
> - of_node_put(np);
> }
>
> /**
> diff -u -p a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
> --- a/arch/powerpc/platforms/chrp/setup.c
> +++ b/arch/powerpc/platforms/chrp/setup.c
> @@ -99,7 +99,7 @@ static void chrp_show_cpuinfo(struct seq
> {
> int i, sdramen;
> unsigned int t;
> - struct device_node *root;
> + struct device_node *root __free(device_node);

Same as next 2.

> const char *model = "";
>
> root = of_find_node_by_path("/");
> @@ -152,7 +152,6 @@ static void chrp_show_cpuinfo(struct seq
> gg2_cachetypes[(t>>2) & 3],
> gg2_cachemodes[t & 3]);
> }
> - of_node_put(root);
> }
>
> /*
> @@ -195,7 +194,7 @@ static void __init sio_fixup_irq(const c
>
> static void __init sio_init(void)
> {
> - struct device_node *root;
> + struct device_node *root __free(device_node);

As below needs to be
struct device_node *root __free(device_node) = of_find_node_by_path("/");
so there is no space for code to be added inbetween that might return before
this is set.

> const char *model;
>
> root = of_find_node_by_path("/");
> @@ -209,8 +208,6 @@ static void __init sio_init(void)
> /* select logical device 1 (KBC/Mouse) */
> sio_fixup_irq("mouse", 1, 12, 2);
> }
> -
> - of_node_put(root);
> }
>
>
> @@ -364,7 +361,7 @@ static void chrp_8259_cascade(struct irq
> */
> static void __init chrp_find_openpic(void)
> {
> - struct device_node *np, *root;
> + struct device_node *np __free(device_node), *root;

This one looks dangerous because of the chance of other code
getting added between here and the point where it is set.

Better to move that down so we have

struct device_node *np __free(device_node) = of_find_node_by_type(NULL, "open-pic");

Also there is a nicer use in:
https://elixir.bootlin.com/linux/v6.8-rc2/source/arch/powerpc/platforms/chrp/setup.c#L217

> int len, i, j;
> int isu_size;
> const unsigned int *iranges, *opprop = NULL;
> @@ -438,7 +435,6 @@ static void __init chrp_find_openpic(voi
> ppc_md.get_irq = mpic_get_irq;
> bail:
> of_node_put(root);
With root covered this can return early.

> - of_node_put(np);
> }
>


2024-01-29 20:29:43

by Julia Lawall

[permalink] [raw]
Subject: Re: [RFC PATCH 0/5] of: automate of_node_put() - new approach to loops.



On Mon, 29 Jan 2024, Jonathan Cameron wrote:

> On Mon, 29 Jan 2024 15:02:19 +0100 (CET)
> Julia Lawall <[email protected]> wrote:
>
> > On Mon, 29 Jan 2024, Jonathan Cameron wrote:
> >
> > > On Sun, 28 Jan 2024 19:06:53 +0100 (CET)
> > > Julia Lawall <[email protected]> wrote:
> > >
> > > > On Sun, 28 Jan 2024, Jonathan Cameron wrote:
> > > >
> > > > > From: Jonathan Cameron <[email protected]>
> > > > >
> > > > > +CC includes peopleinterested in property.h equivalents to minimize
> > > > > duplication of discussion. Outcome of this discussion will affect:
> > > > > https://lore.kernel.org/all/[email protected]/
> > > > > [PATCH 00/13] device property / IIO: Use cleanup.h magic for fwnode_handle_put() handling.
> > > > >
> > > > > In discussion of previous approach with Rob Herring we talked about various
> > > > > ways to avoid a disconnect between the declaration of the __free(device_node)
> > > > > and the first non NULL assignment. Making this connection clear is useful for 2
> > > > > reasons:
> > > > > 1) Avoids out of order cleanup with respect to other cleanup.h usage.
> > > > > 2) Avoids disconnect between how cleanup is to be done and how the reference
> > > > > was acquired in the first place.
> > > > >
> > > > > https://lore.kernel.org/all/[email protected]/
> > > > >
> > > > > The options we discussed are:
> > > > >
> > > > > 1) Ignore this issue and merge original set.
> > > > >
> > > > > 2) Always put the declaration just before the for loop and don't set it NULL.
> > > > >
> > > > > {
> > > > > int ret;
> > > > >
> > > > > ret = ... and other fun code.
> > > > >
> > > > > struct device_node *child __free(device_node);
> > > > > for_each_child_of_node(np, child) {
> > > > > }
> > > > > }
> > > > >
> > > > > This works but careful review is needed to ensure that this unusual pattern is
> > > > > followed. We don't set it to NULL as the loop will do that anyway if there are
> > > > > no child nodes, or the loop finishes without an early break or return.
> > > > >
> > > > > 3) Introduced the pointer to auto put device_node only within the
> > > > > for loop scope.
> > > > >
> > > > > +#define for_each_child_of_node_scoped(parent, child) \
> > > > > + for (struct device_node *child __free(device_node) = \
> > > > > + of_get_next_child(parent, NULL); \
> > > > > + child != NULL; \
> > > > > + child = of_get_next_available_child(parent, child))
> > > > > +
> > > > >
> > > > > This series is presenting option 3. I only implemented this loop out of
> > > > > all the similar ones and it is only compile tested.
> > > > >
> > > > > Disadvantage Rob raised is that it isn't obvious this macro will instantiate
> > > > > a struct device_node *child. I can't see a way around that other than option 2
> > > > > above, but all suggestions welcome. Note that if a conversion leaves an
> > > > > 'external' struct device_node *child variable, in many cases the compiler
> > > > > will catch that as an unused variable. We don't currently run shaddow
> > > > > variable detection in normal kernel builds, but that could also be used
> > > > > to catch such bugs.
> > > > >
> > > > > All comments welcome.
> > > >
> > > > It looks promising to get rid of a lot of clunky and error-prone
> > > > error-handling code.
> > >
> > > Absolutely. I think I spotted 2 bugs whilst just looking for places this pattern
> > > doesn't apply. Will circle back to those once this discussion is resolved.
> > > I think I've taken dozen's of fixes for cases where these were missed over the years
> > > so hoping this means I'll never see another one!
> > >
> > > >
> > > > I guess that
> > > >
> > > > for_each_child_of_node_scoped(parent, struct device_node *, child)
> > > >
> > > > would seem too verbose?
> > >
> > > Intent just to make the allocated internal type clear? Sure we can do that if
> > > it helps with making it clear something is being allocated.
> > > I can't think of a way this could be used with anything other than
> > > a struct device_node * as the second parameter but I guess it still helps
> > > 'hint' at what is going on..
>
> To touch back on this, I'm still not sure what your intent was in suggesting
> having the explicit struct device_node *

Well, I wanted struct device_node * child, but then there wouldn't be the
macro argument that would give the variable name. So perhaps even with
the comma it would look a little more like a declaration.

It does seem problematic to have eg two freestanding occurrences of child
that are not in the same scope, if there is a child in the iterator
argument list and a use elsewhere in the function.

>
> > >
> > > >
> > > > There are a lot of opportunities for device_node loops, but also for some
> > > > more obscure loops over other types.
> > >
> > > > And there are a lot of of_node_puts
> > > > that could be eliminated independent of loops.
> > >
> > > The non loop cases should be handled via the __free(device_node) as provided
> > > by patch 1. We'll need to keep the declaration local and initial assignment
> > > together but that is easy enough to do and similar to the many other cleanup.h
> > > usecases that are surfacing.
> >
> > I tried the following semantic patch:
> >
> > @@
> > identifier x,f;
> > attribute name __free;
> > expression list es;
> > expression e;
> > statement S;
> > @@
> >
> > {
> > ... when != S
> > struct device_node *x
> > + __free(device_node)
> > ;
> > ... when strict
> > x = f(es);
> > <... when any
> > when != x = e
> > -of_node_put(x);
> > ...>
> > -of_node_put(x);
> > }
> >
> Nice.
> > It is written defensively in various ways:
> >
> > when != S means tha tthe device_node declaration has t be at the top of
> > the block, perhaps with other declarations before it.
> >
> > when strict means that all paths must lead from the declaration to the
> > initialization. So there is no need to intiialize the variable to NULL,
> > as far as I understand.
> >
> > when != x = e means that the declared variable is not reinitialized, which
> > would require keeping the previous of_node_put.
> >
> > There is an of_node_put at the end of the block, so the use of __free
> > doesn't change the lifetime.
> >
> > An unfortunate aspect of the last constraint is that some functions may
> > declare multiple device_node variables, and only one of the of_not_puts
> > can come at the very end of the block. This can be solved by just running
> > the semantic patch again.
> >
> > An alternative would be to move the initialization up to the declaration,
> > but the result was often a bit ugly, due to the various initialization
> > function calls having long names and argument lists.
>
> You have to do that in order to ensure there is no window for someone to
> easily insert code that leaves them uninitialized.
>
> Linus had some rather specific comments on that being the only right way to
> do it.

OK, the semantic patch can be changed to do that. It would have to be a
bit more complex or a bit more defensive, to be sure that no variables are
used between the declaration and the current call site.

>
> >
> > The output is below. I have looked quickly through all of the changes and
> > they all look reasonable, but have not tried compiling anything (which I
> > guess wouldn't currently work anyway).
> >
> > julia
> >
>
> I picked a couple from the end. They show the sort of things that
> would want cleaning up. The script is great for finding low hanging
> fruit but as you've identified there is often some stuff that isn't
> easy to automate.
>
> > diff -u -p a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c
> > --- a/drivers/clk/clk-nomadik.c
> > +++ b/drivers/clk/clk-nomadik.c
> > @@ -87,7 +87,7 @@ static const struct of_device_id nomadik
> >
> > static void __init nomadik_src_init(void)
> > {
> > - struct device_node *np;
> > + struct device_node *np __free(device_node);
> > u32 val;
> >
> > np = of_find_matching_node(NULL, nomadik_src_match);
> > @@ -134,7 +134,6 @@ static void __init nomadik_src_init(void
> > register_reboot_notifier(&nomadik_clk_reboot_notifier);
> >
> > out_put:
> Can avoid the label given nothing to do any more.

Indeed.

> > - of_node_put(np);
> > }
> >
> > /**
> > diff -u -p a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
> > --- a/arch/powerpc/platforms/chrp/setup.c
> > +++ b/arch/powerpc/platforms/chrp/setup.c
> > @@ -99,7 +99,7 @@ static void chrp_show_cpuinfo(struct seq
> > {
> > int i, sdramen;
> > unsigned int t;
> > - struct device_node *root;
> > + struct device_node *root __free(device_node);
>
> Same as next 2.
>
> > const char *model = "";
> >
> > root = of_find_node_by_path("/");
> > @@ -152,7 +152,6 @@ static void chrp_show_cpuinfo(struct seq
> > gg2_cachetypes[(t>>2) & 3],
> > gg2_cachemodes[t & 3]);
> > }
> > - of_node_put(root);
> > }
> >
> > /*
> > @@ -195,7 +194,7 @@ static void __init sio_fixup_irq(const c
> >
> > static void __init sio_init(void)
> > {
> > - struct device_node *root;
> > + struct device_node *root __free(device_node);
>
> As below needs to be
> struct device_node *root __free(device_node) = of_find_node_by_path("/");
> so there is no space for code to be added inbetween that might return before
> this is set.

OK

> > const char *model;
> >
> > root = of_find_node_by_path("/");
> > @@ -209,8 +208,6 @@ static void __init sio_init(void)
> > /* select logical device 1 (KBC/Mouse) */
> > sio_fixup_irq("mouse", 1, 12, 2);
> > }
> > -
> > - of_node_put(root);
> > }
> >
> >
> > @@ -364,7 +361,7 @@ static void chrp_8259_cascade(struct irq
> > */
> > static void __init chrp_find_openpic(void)
> > {
> > - struct device_node *np, *root;
> > + struct device_node *np __free(device_node), *root;
>
> This one looks dangerous because of the chance of other code
> getting added between here and the point where it is set.
>
> Better to move that down so we have
>
> struct device_node *np __free(device_node) = of_find_node_by_type(NULL, "open-pic");
>
> Also there is a nicer use in:
> https://elixir.bootlin.com/linux/v6.8-rc2/source/arch/powerpc/platforms/chrp/setup.c#L217

So the point is that we now allow declarations at random places, and not
only at the top of a function?

>
> > int len, i, j;
> > int isu_size;
> > const unsigned int *iranges, *opprop = NULL;
> > @@ -438,7 +435,6 @@ static void __init chrp_find_openpic(voi
> > ppc_md.get_irq = mpic_get_irq;
> > bail:
> > of_node_put(root);
> With root covered this can return early.

Yes, this could be addressed by running the rule more than once.

Thanks for the feedback!

julia

>
> > - of_node_put(np);
> > }
> >
>
>

2024-01-30 10:27:03

by Julia Lawall

[permalink] [raw]
Subject: Re: [RFC PATCH 0/5] of: automate of_node_put() - new approach to loops.



On Tue, 30 Jan 2024, Jonathan Cameron wrote:

> On Mon, 29 Jan 2024 21:29:13 +0100 (CET)
> Julia Lawall <[email protected]> wrote:
>
> > On Mon, 29 Jan 2024, Jonathan Cameron wrote:
> >
> > > On Mon, 29 Jan 2024 15:02:19 +0100 (CET)
> > > Julia Lawall <[email protected]> wrote:
> > >
> > > > On Mon, 29 Jan 2024, Jonathan Cameron wrote:
> > > >
> > > > > On Sun, 28 Jan 2024 19:06:53 +0100 (CET)
> > > > > Julia Lawall <[email protected]> wrote:
> > > > >
> > > > > > On Sun, 28 Jan 2024, Jonathan Cameron wrote:
> > > > > >
> > > > > > > From: Jonathan Cameron <[email protected]>
> > > > > > >
> > > > > > > +CC includes peopleinterested in property.h equivalents to minimize
> > > > > > > duplication of discussion. Outcome of this discussion will affect:
> > > > > > > https://lore.kernel.org/all/[email protected]/
> > > > > > > [PATCH 00/13] device property / IIO: Use cleanup.h magic for fwnode_handle_put() handling.
> > > > > > >
> > > > > > > In discussion of previous approach with Rob Herring we talked about various
> > > > > > > ways to avoid a disconnect between the declaration of the __free(device_node)
> > > > > > > and the first non NULL assignment. Making this connection clear is useful for 2
> > > > > > > reasons:
> > > > > > > 1) Avoids out of order cleanup with respect to other cleanup.h usage.
> > > > > > > 2) Avoids disconnect between how cleanup is to be done and how the reference
> > > > > > > was acquired in the first place.
> > > > > > >
> > > > > > > https://lore.kernel.org/all/[email protected]/
> > > > > > >
> > > > > > > The options we discussed are:
> > > > > > >
> > > > > > > 1) Ignore this issue and merge original set.
> > > > > > >
> > > > > > > 2) Always put the declaration just before the for loop and don't set it NULL.
> > > > > > >
> > > > > > > {
> > > > > > > int ret;
> > > > > > >
> > > > > > > ret = ... and other fun code.
> > > > > > >
> > > > > > > struct device_node *child __free(device_node);
> > > > > > > for_each_child_of_node(np, child) {
> > > > > > > }
> > > > > > > }
> > > > > > >
> > > > > > > This works but careful review is needed to ensure that this unusual pattern is
> > > > > > > followed. We don't set it to NULL as the loop will do that anyway if there are
> > > > > > > no child nodes, or the loop finishes without an early break or return.
> > > > > > >
> > > > > > > 3) Introduced the pointer to auto put device_node only within the
> > > > > > > for loop scope.
> > > > > > >
> > > > > > > +#define for_each_child_of_node_scoped(parent, child) \
> > > > > > > + for (struct device_node *child __free(device_node) = \
> > > > > > > + of_get_next_child(parent, NULL); \
> > > > > > > + child != NULL; \
> > > > > > > + child = of_get_next_available_child(parent, child))
> > > > > > > +
> > > > > > >
> > > > > > > This series is presenting option 3. I only implemented this loop out of
> > > > > > > all the similar ones and it is only compile tested.
> > > > > > >
> > > > > > > Disadvantage Rob raised is that it isn't obvious this macro will instantiate
> > > > > > > a struct device_node *child. I can't see a way around that other than option 2
> > > > > > > above, but all suggestions welcome. Note that if a conversion leaves an
> > > > > > > 'external' struct device_node *child variable, in many cases the compiler
> > > > > > > will catch that as an unused variable. We don't currently run shaddow
> > > > > > > variable detection in normal kernel builds, but that could also be used
> > > > > > > to catch such bugs.
> > > > > > >
> > > > > > > All comments welcome.
> > > > > >
> > > > > > It looks promising to get rid of a lot of clunky and error-prone
> > > > > > error-handling code.
> > > > >
> > > > > Absolutely. I think I spotted 2 bugs whilst just looking for places this pattern
> > > > > doesn't apply. Will circle back to those once this discussion is resolved.
> > > > > I think I've taken dozen's of fixes for cases where these were missed over the years
> > > > > so hoping this means I'll never see another one!
> > > > >
> > > > > >
> > > > > > I guess that
> > > > > >
> > > > > > for_each_child_of_node_scoped(parent, struct device_node *, child)
> > > > > >
> > > > > > would seem too verbose?
> > > > >
> > > > > Intent just to make the allocated internal type clear? Sure we can do that if
> > > > > it helps with making it clear something is being allocated.
> > > > > I can't think of a way this could be used with anything other than
> > > > > a struct device_node * as the second parameter but I guess it still helps
> > > > > 'hint' at what is going on..
> > >
> > > To touch back on this, I'm still not sure what your intent was in suggesting
> > > having the explicit struct device_node *
> >
> > Well, I wanted struct device_node * child, but then there wouldn't be the
> > macro argument that would give the variable name. So perhaps even with
> > the comma it would look a little more like a declaration.
> >
> > It does seem problematic to have eg two freestanding occurrences of child
> > that are not in the same scope, if there is a child in the iterator
> > argument list and a use elsewhere in the function.
> Hi Julia,
>
>
> Would be nice to have shadow variable detection enabled (QEMU did
> that recently and it caught various bugs).
>
> I'm not sure if this helps or not with readability and get the feeling
> that people will perpetually send patches to remove the pointless
> macro argument. I guess a comment on why it is there might avoid that
> well enough though.

OK, it was a suggestion. Even I was not convinced that it was a good
suggestion :)


> > > > > > There are a lot of opportunities for device_node loops, but also for some
> > > > > > more obscure loops over other types.
> > > > >
> > > > > > And there are a lot of of_node_puts
> > > > > > that could be eliminated independent of loops.
> > > > >
> > > > > The non loop cases should be handled via the __free(device_node) as provided
> > > > > by patch 1. We'll need to keep the declaration local and initial assignment
> > > > > together but that is easy enough to do and similar to the many other cleanup.h
> > > > > usecases that are surfacing.
> > > >
> > > > I tried the following semantic patch:
> > > >
> > > > @@
> > > > identifier x,f;
> > > > attribute name __free;
> > > > expression list es;
> > > > expression e;
> > > > statement S;
> > > > @@
> > > >
> > > > {
> > > > ... when != S
> > > > struct device_node *x
> > > > + __free(device_node)
> > > > ;
> > > > ... when strict
> > > > x = f(es);
> > > > <... when any
> > > > when != x = e
> > > > -of_node_put(x);
> > > > ...>
> > > > -of_node_put(x);
> > > > }
> > > >
> > > Nice.
> > > > It is written defensively in various ways:
> > > >
> > > > when != S means tha tthe device_node declaration has t be at the top of
> > > > the block, perhaps with other declarations before it.
> > > >
> > > > when strict means that all paths must lead from the declaration to the
> > > > initialization. So there is no need to intiialize the variable to NULL,
> > > > as far as I understand.
> > > >
> > > > when != x = e means that the declared variable is not reinitialized, which
> > > > would require keeping the previous of_node_put.
> > > >
> > > > There is an of_node_put at the end of the block, so the use of __free
> > > > doesn't change the lifetime.
> > > >
> > > > An unfortunate aspect of the last constraint is that some functions may
> > > > declare multiple device_node variables, and only one of the of_not_puts
> > > > can come at the very end of the block. This can be solved by just running
> > > > the semantic patch again.
> > > >
> > > > An alternative would be to move the initialization up to the declaration,
> > > > but the result was often a bit ugly, due to the various initialization
> > > > function calls having long names and argument lists.
> > >
> > > You have to do that in order to ensure there is no window for someone to
> > > easily insert code that leaves them uninitialized.
> > >
> > > Linus had some rather specific comments on that being the only right way to
> > > do it.
> >
> > OK, the semantic patch can be changed to do that. It would have to be a
> > bit more complex or a bit more defensive, to be sure that no variables are
> > used between the declaration and the current call site.
> >
> > >
> > > >
> > > > The output is below. I have looked quickly through all of the changes and
> > > > they all look reasonable, but have not tried compiling anything (which I
> > > > guess wouldn't currently work anyway).
> > > >
> > > > julia
> > > >
> > >
> > > I picked a couple from the end. They show the sort of things that
> > > would want cleaning up. The script is great for finding low hanging
> > > fruit but as you've identified there is often some stuff that isn't
> > > easy to automate.
> > >
> > > > diff -u -p a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c
> > > > --- a/drivers/clk/clk-nomadik.c
> > > > +++ b/drivers/clk/clk-nomadik.c
> > > > @@ -87,7 +87,7 @@ static const struct of_device_id nomadik
> > > >
> > > > static void __init nomadik_src_init(void)
> > > > {
> > > > - struct device_node *np;
> > > > + struct device_node *np __free(device_node);
> > > > u32 val;
> > > >
> > > > np = of_find_matching_node(NULL, nomadik_src_match);
> > > > @@ -134,7 +134,6 @@ static void __init nomadik_src_init(void
> > > > register_reboot_notifier(&nomadik_clk_reboot_notifier);
> > > >
> > > > out_put:
> > > Can avoid the label given nothing to do any more.
> >
> > Indeed.
> >
> > > > - of_node_put(np);
> > > > }
> > > >
> > > > /**
> > > > diff -u -p a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
> > > > --- a/arch/powerpc/platforms/chrp/setup.c
> > > > +++ b/arch/powerpc/platforms/chrp/setup.c
> > > > @@ -99,7 +99,7 @@ static void chrp_show_cpuinfo(struct seq
> > > > {
> > > > int i, sdramen;
> > > > unsigned int t;
> > > > - struct device_node *root;
> > > > + struct device_node *root __free(device_node);
> > >
> > > Same as next 2.
> > >
> > > > const char *model = "";
> > > >
> > > > root = of_find_node_by_path("/");
> > > > @@ -152,7 +152,6 @@ static void chrp_show_cpuinfo(struct seq
> > > > gg2_cachetypes[(t>>2) & 3],
> > > > gg2_cachemodes[t & 3]);
> > > > }
> > > > - of_node_put(root);
> > > > }
> > > >
> > > > /*
> > > > @@ -195,7 +194,7 @@ static void __init sio_fixup_irq(const c
> > > >
> > > > static void __init sio_init(void)
> > > > {
> > > > - struct device_node *root;
> > > > + struct device_node *root __free(device_node);
> > >
> > > As below needs to be
> > > struct device_node *root __free(device_node) = of_find_node_by_path("/");
> > > so there is no space for code to be added inbetween that might return before
> > > this is set.
> >
> > OK
> >
> > > > const char *model;
> > > >
> > > > root = of_find_node_by_path("/");
> > > > @@ -209,8 +208,6 @@ static void __init sio_init(void)
> > > > /* select logical device 1 (KBC/Mouse) */
> > > > sio_fixup_irq("mouse", 1, 12, 2);
> > > > }
> > > > -
> > > > - of_node_put(root);
> > > > }
> > > >
> > > >
> > > > @@ -364,7 +361,7 @@ static void chrp_8259_cascade(struct irq
> > > > */
> > > > static void __init chrp_find_openpic(void)
> > > > {
> > > > - struct device_node *np, *root;
> > > > + struct device_node *np __free(device_node), *root;
> > >
> > > This one looks dangerous because of the chance of other code
> > > getting added between here and the point where it is set.
> > >
> > > Better to move that down so we have
> > >
> > > struct device_node *np __free(device_node) = of_find_node_by_type(NULL, "open-pic");
> > >
> > > Also there is a nicer use in:
> > > https://elixir.bootlin.com/linux/v6.8-rc2/source/arch/powerpc/platforms/chrp/setup.c#L217
> >
> > So the point is that we now allow declarations at random places, and not
> > only at the top of a function?
>
> yes.
>
> https://lore.kernel.org/all/CAHk-=wgRHiV5VSxtfXA4S6aLUmcQYEuB67u3BJPJPtuESs1JyA@mail.gmail.com/
> And onwards in that thread.
>
> Linus was pretty clear that constructor and destructor should come together
> and gave an example at the end of that email
>
> + lines = gpio_sim_count_lines(bank);
> + char **line_names __free(kfree) = kcalloc(lines, sizeof(*line_names), GFP_KERNEL);
>
> Reality was that the cleanup.h macros were doing this anyway it just was
> somewhat hidden in guard() and friends.
>
> >
> > >
> > > > int len, i, j;
> > > > int isu_size;
> > > > const unsigned int *iranges, *opprop = NULL;
> > > > @@ -438,7 +435,6 @@ static void __init chrp_find_openpic(voi
> > > > ppc_md.get_irq = mpic_get_irq;
> > > > bail:
> > > > of_node_put(root);
> > > With root covered this can return early.
> >
> > Yes, this could be addressed by running the rule more than once.
> >
> > Thanks for the feedback!
>
> Thanks for putting together a script so quickly.

I have updated it to take into account most of the mentioned issues
(gotos, etc).

In my version, I move the call up to the original declaration site, when
that is safe to do. A negative aspect is that the original call site may
have been preceeded by comments, which get removed. It's hard to know
what should be done with comments, so that has to be addressed manually.
But if we can leave the call site where it is, the comments should
naturally stay there too.

There remains the problem of very long lines. Coccinelle has some
heuristics for dealing with this, but they don't fit well with this case,
where something before the function name is already very long.

Anyway, I will send a new version later today to illustrate what can be
done. No implication that the semantic patch should be sent off to Linus
for immediate application across the kernel. This seems like something
that should be checked more carefully, especially since there is the
opportunity to fix bugs along the way (I saw one case with a missing
of_node_put on an error path).

julia


>
> Jonathan
>
> >
> > julia
> >
> > >
> > > > - of_node_put(np);
> > > > }
> > > >
> > >
> > >
>
>

2024-01-31 21:38:42

by Julia Lawall

[permalink] [raw]
Subject: Re: [RFC PATCH 0/5] of: automate of_node_put() - new approach to loops.

Here are some loop cases. The semantic patch is as follows:

#spatch --allow-inconsistent-paths

@@
expression node;
identifier child;
symbol drop_me;
iterator name for_each_child_of_node;
@@

for_each_child_of_node(node,child) {
...
+ of_node_put(drop_me, child);
}

@@
expression node;
identifier child;
symbol drop_me;
iterator name for_each_child_of_node, for_each_child_of_node_scoped;
identifier L;
@@

- struct device_node *child;
... when != child
-for_each_child_of_node
+for_each_child_of_node_scoped
(node,child) {
... when strict
(
- {
- of_node_put(child);
return ...;
- }
|
- {
- of_node_put(child);
goto L;
- }
|
- {
- of_node_put(child);
break;
- }
|
continue;
|
- of_node_put(child);
return ...;
|
- of_node_put(child);
break;
|
- of_node_put(drop_me, child);
)
}
... when != child

@@
expression child;
@@

- of_node_put(drop_me, child);

-------------------------------

This is quite conservative, in that it requires the only use of the child
variable to be in a single for_each_child_of_node loop at top level.

The drop_me thing is a hack to be able to refer to the bottom of the loop
in the same way as of_node_puts in front of returns etc are referenced.

This works fine when multiple device_node variables are declared at once.

The result is below.

julia

diff -u -p a/drivers/of/unittest.c b/drivers/of/unittest.c
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -2789,7 +2789,7 @@ static int unittest_i2c_mux_probe(struct
int i, nchans;
struct device *dev = &client->dev;
struct i2c_adapter *adap = client->adapter;
- struct device_node *np = client->dev.of_node, *child;
+ struct device_node *np = client->dev.of_node;
struct i2c_mux_core *muxc;
u32 reg, max_reg;

@@ -2801,7 +2801,7 @@ static int unittest_i2c_mux_probe(struct
}

max_reg = (u32)-1;
- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
if (of_property_read_u32(child, "reg", &reg))
continue;
if (max_reg == (u32)-1 || reg > max_reg)
diff -u -p a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c
--- a/drivers/mtd/devices/spear_smi.c
+++ b/drivers/mtd/devices/spear_smi.c
@@ -793,7 +793,6 @@ static int spear_smi_probe_config_dt(str
struct device_node *np)
{
struct spear_smi_plat_data *pdata = dev_get_platdata(&pdev->dev);
- struct device_node *pp;
const __be32 *addr;
u32 val;
int len;
@@ -812,7 +811,7 @@ static int spear_smi_probe_config_dt(str
return -ENOMEM;

/* Fill structs for each subnode (flash device) */
- for_each_child_of_node(np, pp) {
+ for_each_child_of_node_scoped(np, pp) {
pdata->np[i] = pp;

/* Read base-addr and size from DT */
diff -u -p a/drivers/cpuidle/cpuidle-psci-domain.c b/drivers/cpuidle/cpuidle-psci-domain.c
--- a/drivers/cpuidle/cpuidle-psci-domain.c
+++ b/drivers/cpuidle/cpuidle-psci-domain.c
@@ -137,7 +137,6 @@ static const struct of_device_id psci_of
static int psci_cpuidle_domain_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct device_node *node;
bool use_osi = psci_has_osi_support();
int ret = 0, pd_count = 0;

@@ -148,15 +147,13 @@ static int psci_cpuidle_domain_probe(str
* Parse child nodes for the "#power-domain-cells" property and
* initialize a genpd/genpd-of-provider pair when it's found.
*/
- for_each_child_of_node(np, node) {
+ for_each_child_of_node_scoped(np, node) {
if (!of_property_present(node, "#power-domain-cells"))
continue;

ret = psci_pd_init(node, use_osi);
- if (ret) {
- of_node_put(node);
+ if (ret)
goto exit;
- }

pd_count++;
}
diff -u -p a/drivers/pinctrl/renesas/pinctrl.c b/drivers/pinctrl/renesas/pinctrl.c
--- a/drivers/pinctrl/renesas/pinctrl.c
+++ b/drivers/pinctrl/renesas/pinctrl.c
@@ -241,7 +241,6 @@ static int sh_pfc_dt_node_to_map(struct
{
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
struct device *dev = pmx->pfc->dev;
- struct device_node *child;
unsigned int index;
int ret;

@@ -249,13 +248,11 @@ static int sh_pfc_dt_node_to_map(struct
*num_maps = 0;
index = 0;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
ret = sh_pfc_dt_subnode_to_map(pctldev, child, map, num_maps,
&index);
- if (ret < 0) {
- of_node_put(child);
+ if (ret < 0)
goto done;
- }
}

/* If no mapping has been found in child nodes try the config node. */
diff -u -p a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -2715,19 +2715,16 @@ static int lm90_parse_dt_channel_info(st
struct lm90_data *data)
{
int err;
- struct device_node *child;
struct device *dev = &client->dev;
const struct device_node *np = dev->of_node;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
if (strcmp(child->name, "channel"))
continue;

err = lm90_probe_channel_from_dt(client, child, data);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }
}

return 0;
diff -u -p a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -410,7 +410,6 @@ static int cmp_timings(const void *_a, c
static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
struct device_node *node)
{
- struct device_node *child;
struct emc_timing *timing;
int child_count;
int err;
@@ -428,15 +427,13 @@ static int tegra_emc_load_timings_from_d

timing = emc->timings;

- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
if (of_node_name_eq(child, "lpddr2"))
continue;

err = load_one_timing_from_dt(emc, timing++, child);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }

emc->num_timings++;
}
diff -u -p a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -895,7 +895,7 @@ static int smu_i2c_xfer(struct pmac_i2c_

static void __init smu_i2c_probe(void)
{
- struct device_node *controller, *busnode;
+ struct device_node *controller;
struct pmac_i2c_bus *bus;
const u32 *reg;
int sz;
@@ -915,7 +915,7 @@ static void __init smu_i2c_probe(void)
* type as older device trees mix i2c busses and other things
* at the same level
*/
- for_each_child_of_node(controller, busnode) {
+ for_each_child_of_node_scoped(controller, busnode) {
if (!of_node_is_type(busnode, "i2c") &&
!of_node_is_type(busnode, "i2c-bus"))
continue;
@@ -925,10 +925,8 @@ static void __init smu_i2c_probe(void)

sz = sizeof(struct pmac_i2c_bus) + sizeof(struct smu_i2c_cmd);
bus = kzalloc(sz, GFP_KERNEL);
- if (bus == NULL) {
- of_node_put(busnode);
+ if (bus == NULL)
return;
- }

bus->controller = controller;
bus->busnode = of_node_get(busnode);
diff -u -p a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c
--- a/drivers/regulator/scmi-regulator.c
+++ b/drivers/regulator/scmi-regulator.c
@@ -297,7 +297,7 @@ static int process_scmi_regulator_of_nod
static int scmi_regulator_probe(struct scmi_device *sdev)
{
int d, ret, num_doms;
- struct device_node *np, *child;
+ struct device_node *np;
const struct scmi_handle *handle = sdev->handle;
struct scmi_regulator_info *rinfo;
struct scmi_protocol_handle *ph;
@@ -341,13 +341,11 @@ static int scmi_regulator_probe(struct s
*/
of_node_get(handle->dev->of_node);
np = of_find_node_by_name(handle->dev->of_node, "regulators");
- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo);
/* abort on any mem issue */
- if (ret == -ENOMEM) {
- of_node_put(child);
+ if (ret == -ENOMEM)
return ret;
- }
}
of_node_put(np);
/*
diff -u -p a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -244,7 +244,7 @@ samsung_keypad_parse_dt(struct device *d
struct samsung_keypad_platdata *pdata;
struct matrix_keymap_data *keymap_data;
uint32_t *keymap, num_rows = 0, num_cols = 0;
- struct device_node *np = dev->of_node, *key_np;
+ struct device_node *np = dev->of_node;
unsigned int key_count;

if (!np) {
@@ -283,7 +283,7 @@ samsung_keypad_parse_dt(struct device *d
}
keymap_data->keymap = keymap;

- for_each_child_of_node(np, key_np) {
+ for_each_child_of_node_scoped(np, key_np) {
u32 row, col, key_code;
of_property_read_u32(key_np, "keypad,row", &row);
of_property_read_u32(key_np, "keypad,column", &col);
diff -u -p a/drivers/crypto/nx/nx-common-powernv.c b/drivers/crypto/nx/nx-common-powernv.c
--- a/drivers/crypto/nx/nx-common-powernv.c
+++ b/drivers/crypto/nx/nx-common-powernv.c
@@ -907,7 +907,6 @@ static int __init nx_powernv_probe_vas(s
{
int chip_id, vasid, ret = 0;
int ct_842 = 0, ct_gzip = 0;
- struct device_node *dn;

chip_id = of_get_ibm_chip_id(pn);
if (chip_id < 0) {
@@ -921,7 +920,7 @@ static int __init nx_powernv_probe_vas(s
return -EINVAL;
}

- for_each_child_of_node(pn, dn) {
+ for_each_child_of_node_scoped(pn, dn) {
ret = find_nx_device_tree(dn, chip_id, vasid, NX_CT_842,
"ibm,p9-nx-842", &ct_842);

@@ -929,10 +928,8 @@ static int __init nx_powernv_probe_vas(s
ret = find_nx_device_tree(dn, chip_id, vasid,
NX_CT_GZIP, "ibm,p9-nx-gzip", &ct_gzip);

- if (ret) {
- of_node_put(dn);
+ if (ret)
return ret;
- }
}

if (!ct_842 || !ct_gzip) {
diff -u -p a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -1271,7 +1271,6 @@ static int st_pctl_parse_functions(struc
struct st_pinctrl *info, u32 index, int *grp_index)
{
struct device *dev = info->dev;
- struct device_node *child;
struct st_pmx_func *func;
struct st_pctl_group *grp;
int ret, i;
@@ -1286,15 +1285,13 @@ static int st_pctl_parse_functions(struc
return -ENOMEM;

i = 0;
- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
func->groups[i] = child->name;
grp = &info->groups[*grp_index];
*grp_index += 1;
ret = st_pctl_dt_parse_groups(child, grp, info, i++);
- if (ret) {
- of_node_put(child);
+ if (ret)
return ret;
- }
}
dev_info(dev, "Function[%d\t name:%s,\tgroups:%d]\n", index, func->name, func->ngroups);

diff -u -p a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
--- a/drivers/slimbus/qcom-ngd-ctrl.c
+++ b/drivers/slimbus/qcom-ngd-ctrl.c
@@ -1230,9 +1230,8 @@ static int qcom_slim_ngd_power_up(struct
static void qcom_slim_ngd_notify_slaves(struct qcom_slim_ngd_ctrl *ctrl)
{
struct slim_device *sbdev;
- struct device_node *node;

- for_each_child_of_node(ctrl->ngd->pdev->dev.of_node, node) {
+ for_each_child_of_node_scoped(ctrl->ngd->pdev->dev.of_node, node) {
sbdev = of_slim_get_device(&ctrl->ctrl, node);
if (!sbdev)
continue;
diff -u -p a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -154,7 +154,6 @@ static const struct of_device_id cell_bu
static int __init cell_publish_devices(void)
{
struct device_node *root = of_find_node_by_path("/");
- struct device_node *np;
int node;

/* Publish OF platform devices for southbridge IOs */
@@ -163,7 +162,7 @@ static int __init cell_publish_devices(v
/* On spider based blades, we need to manually create the OF
* platform devices for the PCI host bridges
*/
- for_each_child_of_node(root, np) {
+ for_each_child_of_node_scoped(root, np) {
if (!of_node_is_type(np, "pci") && !of_node_is_type(np, "pciex"))
continue;
of_platform_device_create(np, NULL, NULL);
diff -u -p a/drivers/of/platform.c b/drivers/of/platform.c
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -336,7 +336,6 @@ static int of_platform_bus_create(struct
struct device *parent, bool strict)
{
const struct of_dev_auxdata *auxdata;
- struct device_node *child;
struct platform_device *dev;
const char *bus_id = NULL;
void *platform_data = NULL;
@@ -380,13 +379,11 @@ static int of_platform_bus_create(struct
if (!dev || !of_match_node(matches, bus))
return 0;

- for_each_child_of_node(bus, child) {
+ for_each_child_of_node_scoped(bus, child) {
pr_debug(" create child: %pOF\n", child);
rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
- if (rc) {
- of_node_put(child);
+ if (rc)
break;
- }
}
of_node_set_flag(bus, OF_POPULATED_BUS);
return rc;
@@ -457,7 +454,6 @@ int of_platform_populate(struct device_n
const struct of_dev_auxdata *lookup,
struct device *parent)
{
- struct device_node *child;
int rc = 0;

root = root ? of_node_get(root) : of_find_node_by_path("/");
@@ -468,12 +464,10 @@ int of_platform_populate(struct device_n
pr_debug(" starting at: %pOF\n", root);

device_links_supplier_sync_state_pause();
- for_each_child_of_node(root, child) {
+ for_each_child_of_node_scoped(root, child) {
rc = of_platform_bus_create(child, matches, lookup, parent, true);
- if (rc) {
- of_node_put(child);
+ if (rc)
break;
- }
}
device_links_supplier_sync_state_resume();

diff -u -p a/drivers/cpuidle/dt_idle_genpd.c b/drivers/cpuidle/dt_idle_genpd.c
--- a/drivers/cpuidle/dt_idle_genpd.c
+++ b/drivers/cpuidle/dt_idle_genpd.c
@@ -130,11 +130,10 @@ out:

int dt_idle_pd_init_topology(struct device_node *np)
{
- struct device_node *node;
struct of_phandle_args child, parent;
int ret;

- for_each_child_of_node(np, node) {
+ for_each_child_of_node_scoped(np, node) {
if (of_parse_phandle_with_args(node, "power-domains",
"#power-domain-cells", 0, &parent))
continue;
@@ -143,10 +142,8 @@ int dt_idle_pd_init_topology(struct devi
child.args_count = 0;
ret = of_genpd_add_subdomain(&parent, &child);
of_node_put(parent.np);
- if (ret) {
- of_node_put(node);
+ if (ret)
return ret;
- }
}

return 0;
@@ -154,11 +151,10 @@ int dt_idle_pd_init_topology(struct devi

int dt_idle_pd_remove_topology(struct device_node *np)
{
- struct device_node *node;
struct of_phandle_args child, parent;
int ret;

- for_each_child_of_node(np, node) {
+ for_each_child_of_node_scoped(np, node) {
if (of_parse_phandle_with_args(node, "power-domains",
"#power-domain-cells", 0, &parent))
continue;
@@ -167,10 +163,8 @@ int dt_idle_pd_remove_topology(struct de
child.args_count = 0;
ret = of_genpd_remove_subdomain(&parent, &child);
of_node_put(parent.np);
- if (ret) {
- of_node_put(node);
+ if (ret)
return ret;
- }
}

return 0;
diff -u -p a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c
--- a/sound/soc/meson/axg-card.c
+++ b/sound/soc/meson/axg-card.c
@@ -221,7 +221,6 @@ static int axg_card_parse_codecs_masks(s
struct axg_dai_link_tdm_data *be)
{
struct axg_dai_link_tdm_mask *codec_mask;
- struct device_node *np;

codec_mask = devm_kcalloc(card->dev, link->num_codecs,
sizeof(*codec_mask), GFP_KERNEL);
@@ -230,7 +229,7 @@ static int axg_card_parse_codecs_masks(s

be->codec_masks = codec_mask;

- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask",
&codec_mask->rx);
snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask",
diff -u -p a/drivers/mtd/nand/raw/renesas-nand-controller.c b/drivers/mtd/nand/raw/renesas-nand-controller.c
--- a/drivers/mtd/nand/raw/renesas-nand-controller.c
+++ b/drivers/mtd/nand/raw/renesas-nand-controller.c
@@ -1297,15 +1297,12 @@ static void rnandc_chips_cleanup(struct

static int rnandc_chips_init(struct rnandc *rnandc)
{
- struct device_node *np;
int ret;

- for_each_child_of_node(rnandc->dev->of_node, np) {
+ for_each_child_of_node_scoped(rnandc->dev->of_node, np) {
ret = rnandc_chip_init(rnandc, np);
- if (ret) {
- of_node_put(np);
+ if (ret)
goto cleanup_chips;
- }
}

return 0;
diff -u -p a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c
--- a/drivers/mfd/tc3589x.c
+++ b/drivers/mfd/tc3589x.c
@@ -330,7 +330,6 @@ tc3589x_of_probe(struct device *dev, enu
{
struct device_node *np = dev->of_node;
struct tc3589x_platform_data *pdata;
- struct device_node *child;
const struct of_device_id *of_id;

pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -342,7 +341,7 @@ tc3589x_of_probe(struct device *dev, enu
return ERR_PTR(-ENODEV);
*version = (uintptr_t) of_id->data;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
if (of_device_is_compatible(child, "toshiba,tc3589x-gpio"))
pdata->block |= TC3589x_BLOCK_GPIO;
if (of_device_is_compatible(child, "toshiba,tc3589x-keypad"))
diff -u -p a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c
--- a/drivers/memory/tegra/tegra30-emc.c
+++ b/drivers/memory/tegra/tegra30-emc.c
@@ -979,7 +979,6 @@ static int emc_check_mc_timings(struct t
static int emc_load_timings_from_dt(struct tegra_emc *emc,
struct device_node *node)
{
- struct device_node *child;
struct emc_timing *timing;
int child_count;
int err;
@@ -998,12 +997,10 @@ static int emc_load_timings_from_dt(stru
emc->num_timings = child_count;
timing = emc->timings;

- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
err = load_one_timing_from_dt(emc, timing++, child);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }
}

sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
diff -u -p a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -665,7 +665,6 @@ static int stm32_adc_probe_identificatio
struct stm32_adc_priv *priv)
{
struct device_node *np = pdev->dev.of_node;
- struct device_node *child;
const char *compat;
int ret, count = 0;
u32 id, val;
@@ -680,7 +679,7 @@ static int stm32_adc_probe_identificatio
return -EINVAL;
}

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
ret = of_property_read_string(child, "compatible", &compat);
if (ret)
continue;
diff -u -p a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -3054,7 +3054,7 @@ static int xilinx_dma_probe(struct platf
= axivdma_clk_init;
struct device_node *node = pdev->dev.of_node;
struct xilinx_dma_device *xdev;
- struct device_node *child, *np = pdev->dev.of_node;
+ struct device_node *np = pdev->dev.of_node;
u32 num_frames, addr_width, len_width;
int i, err;

@@ -3189,12 +3189,10 @@ static int xilinx_dma_probe(struct platf
platform_set_drvdata(pdev, xdev);

/* Initialize the channels */
- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
err = xilinx_dma_child_probe(xdev, child);
- if (err < 0) {
- of_node_put(child);
+ if (err < 0)
goto error;
- }
}

if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
diff -u -p a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -478,17 +478,14 @@ void rsnd_parse_connect_ssiu(struct rsnd

/* use rcar_sound,ssiu if exist */
if (node) {
- struct device_node *np;
int i = 0;

- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
struct rsnd_mod *mod;

i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i);
- if (i < 0) {
- of_node_put(np);
+ if (i < 0)
break;
- }

mod = rsnd_ssiu_mod_get(priv, i);

diff -u -p a/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c b/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c
--- a/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c
@@ -238,20 +238,17 @@ static int tegra_xusb_padctl_dt_node_to_
{
struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
unsigned int reserved_maps = 0;
- struct device_node *np;
int err;

*num_maps = 0;
*maps = NULL;

- for_each_child_of_node(parent, np) {
+ for_each_child_of_node_scoped(parent, np) {
err = tegra_xusb_padctl_parse_subnode(padctl, np, maps,
&reserved_maps,
num_maps);
- if (err < 0) {
- of_node_put(np);
+ if (err < 0)
return err;
- }
}

return 0;
diff -u -p a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
--- a/drivers/gpu/drm/rockchip/rockchip_rgb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
@@ -76,7 +76,7 @@ struct rockchip_rgb *rockchip_rgb_init(s
{
struct rockchip_rgb *rgb;
struct drm_encoder *encoder;
- struct device_node *port, *endpoint;
+ struct device_node *port;
u32 endpoint_id;
int ret = 0, child_count = 0;
struct drm_panel *panel;
@@ -94,7 +94,7 @@ struct rockchip_rgb *rockchip_rgb_init(s
if (!port)
return ERR_PTR(-EINVAL);

- for_each_child_of_node(port, endpoint) {
+ for_each_child_of_node_scoped(port, endpoint) {
if (of_property_read_u32(endpoint, "reg", &endpoint_id))
endpoint_id = 0;

@@ -105,10 +105,8 @@ struct rockchip_rgb *rockchip_rgb_init(s
child_count++;
ret = drm_of_find_panel_or_bridge(dev->of_node, video_port,
endpoint_id, &panel, &bridge);
- if (!ret) {
- of_node_put(endpoint);
+ if (!ret)
break;
- }
}

of_node_put(port);
diff -u -p a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -544,7 +544,6 @@ static void pci_of_scan_bus(struct pci_p
struct device_node *node,
struct pci_bus *bus)
{
- struct device_node *child;
const u32 *reg;
int reglen, devfn, prev_devfn;
struct pci_dev *dev;
@@ -554,7 +553,7 @@ static void pci_of_scan_bus(struct pci_p
node, bus->number);

prev_devfn = -1;
- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
if (ofpci_verbose)
pci_info(bus, " * %pOF\n", child);
reg = of_get_property(child, "reg", &reglen);
diff -u -p a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -1437,7 +1437,7 @@ static int tegra_powergate_init(struct t
struct device_node *parent)
{
struct of_phandle_args child_args, parent_args;
- struct device_node *np, *child;
+ struct device_node *np;
int err = 0;

/*
@@ -1456,12 +1456,10 @@ static int tegra_powergate_init(struct t
if (!np)
return 0;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
err = tegra_powergate_add(pmc, child);
- if (err < 0) {
- of_node_put(child);
+ if (err < 0)
break;
- }

if (of_parse_phandle_with_args(child, "power-domains",
"#power-domain-cells",
@@ -1473,10 +1471,8 @@ static int tegra_powergate_init(struct t

err = of_genpd_add_subdomain(&parent_args, &child_args);
of_node_put(parent_args.np);
- if (err) {
- of_node_put(child);
+ if (err)
break;
- }
}

of_node_put(np);
@@ -1503,13 +1499,13 @@ static void tegra_powergate_remove(struc
static void tegra_powergate_remove_all(struct device_node *parent)
{
struct generic_pm_domain *genpd;
- struct device_node *np, *child;
+ struct device_node *np;

np = of_get_child_by_name(parent, "powergates");
if (!np)
return;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
of_genpd_del_provider(child);

genpd = of_genpd_remove_last(child);
diff -u -p a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -80,7 +80,7 @@ static int i2c_mux_reg_probe_dt(struct r
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct device_node *adapter_np, *child;
+ struct device_node *adapter_np;
struct i2c_adapter *adapter;
struct resource res;
unsigned *values;
@@ -126,7 +126,7 @@ static int i2c_mux_reg_probe_dt(struct r
if (!values)
return -ENOMEM;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
of_property_read_u32(child, "reg", values + i);
i++;
}
diff -u -p a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -410,7 +410,6 @@ static int ahci_platform_get_regulator(s
static int ahci_platform_get_firmware(struct ahci_host_priv *hpriv,
struct device *dev)
{
- struct device_node *child;
u32 port;

if (!of_property_read_u32(dev->of_node, "hba-cap", &hpriv->saved_cap))
@@ -419,14 +418,12 @@ static int ahci_platform_get_firmware(st
of_property_read_u32(dev->of_node,
"ports-implemented", &hpriv->saved_port_map);

- for_each_child_of_node(dev->of_node, child) {
+ for_each_child_of_node_scoped(dev->of_node, child) {
if (!of_device_is_available(child))
continue;

- if (of_property_read_u32(child, "reg", &port)) {
- of_node_put(child);
+ if (of_property_read_u32(child, "reg", &port))
return -EINVAL;
- }

if (!of_property_read_u32(child, "hba-port-cap", &hpriv->saved_port_cap[port]))
hpriv->saved_port_cap[port] &= PORT_CMD_CAP;
diff -u -p a/drivers/power/supply/lp8727_charger.c b/drivers/power/supply/lp8727_charger.c
--- a/drivers/power/supply/lp8727_charger.c
+++ b/drivers/power/supply/lp8727_charger.c
@@ -507,7 +507,6 @@ out:
static struct lp8727_platform_data *lp8727_parse_dt(struct device *dev)
{
struct device_node *np = dev->of_node;
- struct device_node *child;
struct lp8727_platform_data *pdata;
const char *type;

@@ -521,7 +520,7 @@ static struct lp8727_platform_data *lp87
if (of_get_child_count(np) == 0)
return pdata;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
of_property_read_string(child, "charger-type", &type);

if (!strcmp(type, "ac"))
diff -u -p a/drivers/pinctrl/freescale/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c
--- a/drivers/pinctrl/freescale/pinctrl-imx1-core.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c
@@ -508,7 +508,6 @@ static int imx1_pinctrl_parse_functions(
struct imx1_pinctrl_soc_info *info,
u32 index)
{
- struct device_node *child;
struct imx1_pmx_func *func;
struct imx1_pin_group *grp;
int ret;
@@ -531,14 +530,12 @@ static int imx1_pinctrl_parse_functions(
if (!func->groups)
return -ENOMEM;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
func->groups[i] = child->name;
grp = &info->groups[grp_index++];
ret = imx1_pinctrl_parse_groups(child, grp, info, i++);
- if (ret == -ENOMEM) {
- of_node_put(child);
+ if (ret == -ENOMEM)
return ret;
- }
}

return 0;
diff -u -p a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c
--- a/drivers/pci/hotplug/pnv_php.c
+++ b/drivers/pci/hotplug/pnv_php.c
@@ -133,9 +133,7 @@ EXPORT_SYMBOL_GPL(pnv_php_find_slot);
*/
static void pnv_php_rmv_pdns(struct device_node *dn)
{
- struct device_node *child;
-
- for_each_child_of_node(dn, child) {
+ for_each_child_of_node_scoped(dn, child) {
pnv_php_rmv_pdns(child);

pci_remove_device_node_info(child);
@@ -214,21 +212,16 @@ static void pnv_php_reverse_nodes(struct
static int pnv_php_populate_changeset(struct of_changeset *ocs,
struct device_node *dn)
{
- struct device_node *child;
int ret = 0;

- for_each_child_of_node(dn, child) {
+ for_each_child_of_node_scoped(dn, child) {
ret = of_changeset_attach_node(ocs, child);
- if (ret) {
- of_node_put(child);
+ if (ret)
break;
- }

ret = pnv_php_populate_changeset(ocs, child);
- if (ret) {
- of_node_put(child);
+ if (ret)
break;
- }
}

return ret;
@@ -974,13 +967,11 @@ free_slot:

static void pnv_php_register(struct device_node *dn)
{
- struct device_node *child;
-
/*
* The parent slots should be registered before their
* child slots.
*/
- for_each_child_of_node(dn, child) {
+ for_each_child_of_node_scoped(dn, child) {
pnv_php_register_one(child);
pnv_php_register(child);
}
@@ -1002,10 +993,8 @@ static void pnv_php_unregister_one(struc

static void pnv_php_unregister(struct device_node *dn)
{
- struct device_node *child;
-
/* The child slots should go before their parent slots */
- for_each_child_of_node(dn, child) {
+ for_each_child_of_node_scoped(dn, child) {
pnv_php_unregister(child);
pnv_php_unregister_one(child);
}
diff -u -p a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
--- a/drivers/hwmon/tmp421.c
+++ b/drivers/hwmon/tmp421.c
@@ -410,18 +410,15 @@ static int tmp421_probe_from_dt(struct i
{
struct device *dev = &client->dev;
const struct device_node *np = dev->of_node;
- struct device_node *child;
int err;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
if (strcmp(child->name, "channel"))
continue;

err = tmp421_probe_child_from_dt(client, child, data);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }
}

return 0;
diff -u -p a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c
--- a/drivers/media/platform/samsung/exynos4-is/media-dev.c
+++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c
@@ -482,15 +482,12 @@ static int fimc_md_parse_one_endpoint(st
static int fimc_md_parse_port_node(struct fimc_md *fmd,
struct device_node *port)
{
- struct device_node *ep;
int ret;

- for_each_child_of_node(port, ep) {
+ for_each_child_of_node_scoped(port, ep) {
ret = fimc_md_parse_one_endpoint(fmd, ep);
- if (ret < 0) {
- of_node_put(ep);
+ if (ret < 0)
return ret;
- }
}

return 0;
diff -u -p a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -2979,9 +2979,7 @@ static const struct of_device_id rockchi
static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info,
struct device_node *np)
{
- struct device_node *child;
-
- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
if (of_match_node(rockchip_bank_match, child))
continue;

@@ -3057,7 +3055,6 @@ static int rockchip_pinctrl_parse_functi
u32 index)
{
struct device *dev = info->dev;
- struct device_node *child;
struct rockchip_pmx_func *func;
struct rockchip_pin_group *grp;
int ret;
@@ -3078,14 +3075,12 @@ static int rockchip_pinctrl_parse_functi
if (!func->groups)
return -ENOMEM;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
func->groups[i] = child->name;
grp = &info->groups[grp_index++];
ret = rockchip_pinctrl_parse_groups(child, grp, info, i++);
- if (ret) {
- of_node_put(child);
+ if (ret)
return ret;
- }
}

return 0;
diff -u -p a/drivers/of/overlay.c b/drivers/of/overlay.c
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -1083,16 +1083,12 @@ EXPORT_SYMBOL_GPL(of_overlay_fdt_apply);
*/
static int find_node(struct device_node *tree, struct device_node *np)
{
- struct device_node *child;
-
if (tree == np)
return 1;

- for_each_child_of_node(tree, child) {
- if (find_node(child, np)) {
- of_node_put(child);
+ for_each_child_of_node_scoped(tree, child) {
+ if (find_node(child, np))
return 1;
- }
}

return 0;
diff -u -p a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -450,7 +450,6 @@ static int load_one_timing(struct tegra_

static int load_timings(struct tegra_mc *mc, struct device_node *node)
{
- struct device_node *child;
struct tegra_mc_timing *timing;
int child_count = of_get_child_count(node);
int i = 0, err;
@@ -462,14 +461,12 @@ static int load_timings(struct tegra_mc

mc->num_timings = child_count;

- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
timing = &mc->timings[i++];

err = load_one_timing(mc, timing, child);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }
}

return 0;
diff -u -p a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -549,7 +549,7 @@ static int rockchip_lvds_bind(struct dev
struct drm_encoder *encoder;
struct drm_connector *connector;
struct device_node *remote = NULL;
- struct device_node *port, *endpoint;
+ struct device_node *port;
int ret = 0, child_count = 0;
const char *name;
u32 endpoint_id = 0;
@@ -561,15 +561,13 @@ static int rockchip_lvds_bind(struct dev
"can't found port point, please init lvds panel port!\n");
return -EINVAL;
}
- for_each_child_of_node(port, endpoint) {
+ for_each_child_of_node_scoped(port, endpoint) {
child_count++;
of_property_read_u32(endpoint, "reg", &endpoint_id);
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, endpoint_id,
&lvds->panel, &lvds->bridge);
- if (!ret) {
- of_node_put(endpoint);
+ if (!ret)
break;
- }
}
if (!child_count) {
DRM_DEV_ERROR(dev, "lvds port does not have any children\n");
diff -u -p a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -763,14 +763,10 @@ static struct platform_driver qcom_iommu

static bool qcom_iommu_has_secure_context(struct qcom_iommu_dev *qcom_iommu)
{
- struct device_node *child;
-
- for_each_child_of_node(qcom_iommu->dev->of_node, child) {
+ for_each_child_of_node_scoped(qcom_iommu->dev->of_node, child) {
if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec") ||
- of_device_is_compatible(child, "qcom,msm-iommu-v2-sec")) {
- of_node_put(child);
+ of_device_is_compatible(child, "qcom,msm-iommu-v2-sec"))
return true;
- }
}

return false;
diff -u -p a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -23,7 +23,6 @@
static int of_find_trip_id(struct device_node *np, struct device_node *trip)
{
struct device_node *trips;
- struct device_node *t;
int i = 0;

trips = of_get_child_by_name(np, "trips");
@@ -35,12 +34,10 @@ static int of_find_trip_id(struct device
/*
* Find the trip id point associated with the cooling device map
*/
- for_each_child_of_node(trips, t) {
+ for_each_child_of_node_scoped(trips, t) {

- if (t == trip) {
- of_node_put(t);
+ if (t == trip)
goto out;
- }
i++;
}

@@ -388,7 +385,7 @@ static int thermal_of_for_each_cooling_m
int (*action)(struct device_node *, int, int,
struct thermal_zone_device *, struct thermal_cooling_device *))
{
- struct device_node *tz_np, *cm_np, *child;
+ struct device_node *tz_np, *cm_np;
int ret = 0;

tz_np = thermal_of_zone_get_by_name(tz);
@@ -401,12 +398,10 @@ static int thermal_of_for_each_cooling_m
if (!cm_np)
goto out;

- for_each_child_of_node(cm_np, child) {
+ for_each_child_of_node_scoped(cm_np, child) {
ret = thermal_of_for_each_cooling_device(tz_np, child, tz, cdev, action);
- if (ret) {
- of_node_put(child);
+ if (ret)
break;
- }
}

of_node_put(cm_np);
diff -u -p a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c
--- a/drivers/memory/tegra/tegra124-emc.c
+++ b/drivers/memory/tegra/tegra124-emc.c
@@ -992,7 +992,6 @@ static int tegra_emc_load_timings_from_d
struct device_node *node)
{
int child_count = of_get_child_count(node);
- struct device_node *child;
struct emc_timing *timing;
unsigned int i = 0;
int err;
@@ -1004,14 +1003,12 @@ static int tegra_emc_load_timings_from_d

emc->num_timings = child_count;

- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
timing = &emc->timings[i++];

err = load_one_timing_from_dt(emc, timing, child);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }
}

sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
diff -u -p a/drivers/i2c/i2c-core-slave.c b/drivers/i2c/i2c-core-slave.c
--- a/drivers/i2c/i2c-core-slave.c
+++ b/drivers/i2c/i2c-core-slave.c
@@ -109,15 +109,12 @@ EXPORT_SYMBOL_GPL(i2c_slave_event);
bool i2c_detect_slave_mode(struct device *dev)
{
if (IS_BUILTIN(CONFIG_OF) && dev->of_node) {
- struct device_node *child;
u32 reg;

- for_each_child_of_node(dev->of_node, child) {
+ for_each_child_of_node_scoped(dev->of_node, child) {
of_property_read_u32(child, "reg", &reg);
- if (reg & I2C_OWN_SLAVE_ADDRESS) {
- of_node_put(child);
+ if (reg & I2C_OWN_SLAVE_ADDRESS)
return true;
- }
}
} else if (IS_BUILTIN(CONFIG_ACPI) && ACPI_HANDLE(dev)) {
dev_dbg(dev, "ACPI slave is not supported yet\n");
diff -u -p a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c
--- a/drivers/hwmon/ina3221.c
+++ b/drivers/hwmon/ina3221.c
@@ -813,7 +813,6 @@ static int ina3221_probe_child_from_dt(s
static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina)
{
const struct device_node *np = dev->of_node;
- struct device_node *child;
int ret;

/* Compatible with non-DT platforms */
@@ -822,12 +821,10 @@ static int ina3221_probe_from_dt(struct

ina->single_shot = of_property_read_bool(np, "ti,single-shot");

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
ret = ina3221_probe_child_from_dt(dev, child, ina);
- if (ret) {
- of_node_put(child);
+ if (ret)
return ret;
- }
}

return 0;
diff -u -p a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c
--- a/arch/powerpc/kernel/pci_of_scan.c
+++ b/arch/powerpc/kernel/pci_of_scan.c
@@ -395,14 +395,13 @@ static struct pci_dev *of_scan_pci_dev(s
static void __of_scan_bus(struct device_node *node, struct pci_bus *bus,
int rescan_existing)
{
- struct device_node *child;
struct pci_dev *dev;

pr_debug("of_scan_bus(%pOF) bus no %d...\n",
node, bus->number);

/* Scan direct children */
- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
dev = of_scan_pci_dev(bus, child);
if (!dev)
continue;
diff -u -p a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c
--- a/arch/powerpc/platforms/pseries/vio.c
+++ b/arch/powerpc/platforms/pseries/vio.c
@@ -114,10 +114,9 @@ static int vio_cmo_num_OF_devs(void)
*/
node_vroot = of_find_node_by_name(NULL, "vdevice");
if (node_vroot) {
- struct device_node *of_node;
struct property *prop;

- for_each_child_of_node(node_vroot, of_node) {
+ for_each_child_of_node_scoped(node_vroot, of_node) {
prop = of_find_property(of_node, "ibm,my-dma-window",
NULL);
if (prop)
diff -u -p a/drivers/pinctrl/sprd/pinctrl-sprd.c b/drivers/pinctrl/sprd/pinctrl-sprd.c
--- a/drivers/pinctrl/sprd/pinctrl-sprd.c
+++ b/drivers/pinctrl/sprd/pinctrl-sprd.c
@@ -916,12 +916,11 @@ static int sprd_pinctrl_parse_groups(str

static unsigned int sprd_pinctrl_get_groups(struct device_node *np)
{
- struct device_node *child;
unsigned int group_cnt, cnt;

group_cnt = of_get_child_count(np);

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
cnt = of_get_child_count(child);
if (cnt > 0)
group_cnt += cnt;
diff -u -p a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c
--- a/drivers/pinctrl/nxp/pinctrl-s32cc.c
+++ b/drivers/pinctrl/nxp/pinctrl-s32cc.c
@@ -786,7 +786,6 @@ static int s32_pinctrl_parse_functions(s
struct s32_pinctrl_soc_info *info,
u32 index)
{
- struct device_node *child;
struct pinfunction *func;
struct s32_pin_group *grp;
const char **groups;
@@ -810,14 +809,12 @@ static int s32_pinctrl_parse_functions(s
if (!groups)
return -ENOMEM;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
groups[i] = child->name;
grp = &info->groups[info->grp_index++];
ret = s32_pinctrl_parse_groups(child, grp, info);
- if (ret) {
- of_node_put(child);
+ if (ret)
return ret;
- }
i++;
}

diff -u -p a/drivers/of/resolver.c b/drivers/of/resolver.c
--- a/drivers/of/resolver.c
+++ b/drivers/of/resolver.c
@@ -262,7 +262,7 @@ static int adjust_local_phandle_referenc
*/
int of_resolve_phandles(struct device_node *overlay)
{
- struct device_node *child, *local_fixups, *refnode;
+ struct device_node *local_fixups, *refnode;
struct device_node *tree_symbols, *overlay_fixups;
struct property *prop;
const char *refpath;
@@ -296,7 +296,7 @@ int of_resolve_phandles(struct device_no

overlay_fixups = NULL;

- for_each_child_of_node(overlay, child) {
+ for_each_child_of_node_scoped(overlay, child) {
if (of_node_name_eq(child, "__fixups__"))
overlay_fixups = child;
}
diff -u -p a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -2774,7 +2774,6 @@ static void marvell_nand_chips_cleanup(s
static int marvell_nand_chips_init(struct device *dev, struct marvell_nfc *nfc)
{
struct device_node *np = dev->of_node;
- struct device_node *nand_np;
int max_cs = nfc->caps->max_cs_nb;
int nchips;
int ret;
@@ -2801,12 +2800,10 @@ static int marvell_nand_chips_init(struc
return ret;
}

- for_each_child_of_node(np, nand_np) {
+ for_each_child_of_node_scoped(np, nand_np) {
ret = marvell_nand_chip_init(dev, nfc, nand_np);
- if (ret) {
- of_node_put(nand_np);
+ if (ret)
goto cleanup_chips;
- }
}

return 0;
diff -u -p a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c
--- a/drivers/hwmon/aspeed-pwm-tacho.c
+++ b/drivers/hwmon/aspeed-pwm-tacho.c
@@ -901,7 +901,7 @@ static void aspeed_pwm_tacho_remove(void
static int aspeed_pwm_tacho_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *np, *child;
+ struct device_node *np;
struct aspeed_pwm_tacho_data *priv;
void __iomem *regs;
struct device *hwmon;
@@ -944,12 +944,10 @@ static int aspeed_pwm_tacho_probe(struct

aspeed_create_type(priv);

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
ret = aspeed_create_fan(dev, child, priv);
- if (ret) {
- of_node_put(child);
+ if (ret)
return ret;
- }
}

priv->groups[0] = &pwm_dev_group;
diff -u -p a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c
--- a/drivers/video/backlight/lp855x_bl.c
+++ b/drivers/video/backlight/lp855x_bl.c
@@ -343,14 +343,13 @@ static int lp855x_parse_dt(struct lp855x
rom_length = of_get_child_count(node);
if (rom_length > 0) {
struct lp855x_rom_data *rom;
- struct device_node *child;
int i = 0;

rom = devm_kcalloc(dev, rom_length, sizeof(*rom), GFP_KERNEL);
if (!rom)
return -ENOMEM;

- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
of_property_read_u8(child, "rom-addr", &rom[i].addr);
of_property_read_u8(child, "rom-val", &rom[i].val);
i++;
diff -u -p a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c
--- a/drivers/hwmon/ibmpowernv.c
+++ b/drivers/hwmon/ibmpowernv.c
@@ -433,7 +433,7 @@ static int populate_attr_groups(struct p
{
struct platform_data *pdata = platform_get_drvdata(pdev);
const struct attribute_group **pgroups = pdata->attr_groups;
- struct device_node *opal, *np;
+ struct device_node *opal;
enum sensors type;
int ret;

@@ -442,7 +442,7 @@ static int populate_attr_groups(struct p
return ret;

opal = of_find_node_by_path("/ibm,opal/sensors");
- for_each_child_of_node(opal, np) {
+ for_each_child_of_node_scoped(opal, np) {
const char *label;

type = get_sensor_type(np);
diff -u -p a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
--- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c
+++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
@@ -1823,7 +1823,6 @@ static int stm32_fmc2_nfc_parse_child(st
static int stm32_fmc2_nfc_parse_dt(struct stm32_fmc2_nfc *nfc)
{
struct device_node *dn = nfc->dev->of_node;
- struct device_node *child;
int nchips = of_get_child_count(dn);
int ret = 0;

@@ -1837,12 +1836,10 @@ static int stm32_fmc2_nfc_parse_dt(struc
return -EINVAL;
}

- for_each_child_of_node(dn, child) {
+ for_each_child_of_node_scoped(dn, child) {
ret = stm32_fmc2_nfc_parse_child(nfc, child);
- if (ret < 0) {
- of_node_put(child);
+ if (ret < 0)
return ret;
- }
}

return ret;
diff -u -p a/drivers/hwmon/tmp464.c b/drivers/hwmon/tmp464.c
--- a/drivers/hwmon/tmp464.c
+++ b/drivers/hwmon/tmp464.c
@@ -565,18 +565,15 @@ static int tmp464_probe_child_from_dt(st
static int tmp464_probe_from_dt(struct device *dev, struct tmp464_data *data)
{
const struct device_node *np = dev->of_node;
- struct device_node *child;
int err;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
if (strcmp(child->name, "channel"))
continue;

err = tmp464_probe_child_from_dt(dev, child, data);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }
}

return 0;
diff -u -p a/drivers/pinctrl/renesas/pinctrl-rzn1.c b/drivers/pinctrl/renesas/pinctrl-rzn1.c
--- a/drivers/pinctrl/renesas/pinctrl-rzn1.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzn1.c
@@ -404,7 +404,6 @@ static int rzn1_dt_node_to_map(struct pi
struct pinctrl_map **map,
unsigned int *num_maps)
{
- struct device_node *child;
int ret;

*map = NULL;
@@ -414,12 +413,10 @@ static int rzn1_dt_node_to_map(struct pi
if (ret < 0)
return ret;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
ret = rzn1_dt_node_to_map_one(pctldev, child, map, num_maps);
- if (ret < 0) {
- of_node_put(child);
+ if (ret < 0)
return ret;
- }
}

return 0;
@@ -740,13 +737,12 @@ static int rzn1_pinctrl_parse_groups(str

static int rzn1_pinctrl_count_function_groups(struct device_node *np)
{
- struct device_node *child;
int count = 0;

if (of_property_count_u32_elems(np, RZN1_PINS_PROP) > 0)
count++;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
if (of_property_count_u32_elems(child, RZN1_PINS_PROP) > 0)
count++;
}
@@ -760,7 +756,6 @@ static int rzn1_pinctrl_parse_functions(
{
struct rzn1_pmx_func *func;
struct rzn1_pin_group *grp;
- struct device_node *child;
unsigned int i = 0;
int ret;

@@ -793,15 +788,13 @@ static int rzn1_pinctrl_parse_functions(
ipctl->ngroups++;
}

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
func->groups[i] = child->name;
grp = &ipctl->groups[ipctl->ngroups];
grp->func = func->name;
ret = rzn1_pinctrl_parse_groups(child, grp, ipctl);
- if (ret < 0) {
- of_node_put(child);
+ if (ret < 0)
return ret;
- }
i++;
ipctl->ngroups++;
}
diff -u -p a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c
--- a/sound/soc/meson/meson-card-utils.c
+++ b/sound/soc/meson/meson-card-utils.c
@@ -198,7 +198,6 @@ static int meson_card_add_links(struct s
{
struct meson_card *priv = snd_soc_card_get_drvdata(card);
struct device_node *node = card->dev->of_node;
- struct device_node *np;
int num, i, ret;

num = of_get_child_count(node);
@@ -212,12 +211,10 @@ static int meson_card_add_links(struct s
return ret;

i = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
ret = priv->match_data->add_link(card, np, &i);
- if (ret) {
- of_node_put(np);
+ if (ret)
return ret;
- }

i++;
}
diff -u -p a/drivers/net/pcs/pcs-rzn1-miic.c b/drivers/net/pcs/pcs-rzn1-miic.c
--- a/drivers/net/pcs/pcs-rzn1-miic.c
+++ b/drivers/net/pcs/pcs-rzn1-miic.c
@@ -434,7 +434,6 @@ static int miic_parse_dt(struct device *
{
s8 dt_val[MIIC_MODCTRL_CONF_CONV_NUM];
struct device_node *np = dev->of_node;
- struct device_node *conv;
u32 conf;
int port;

@@ -443,7 +442,7 @@ static int miic_parse_dt(struct device *
if (of_property_read_u32(np, "renesas,miic-switch-portin", &conf) == 0)
dt_val[0] = conf;

- for_each_child_of_node(np, conv) {
+ for_each_child_of_node_scoped(np, conv) {
if (of_property_read_u32(conv, "reg", &port))
continue;

diff -u -p a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c
--- a/drivers/mtd/nand/raw/denali_dt.c
+++ b/drivers/mtd/nand/raw/denali_dt.c
@@ -115,7 +115,6 @@ static int denali_dt_probe(struct platfo
struct denali_dt *dt;
const struct denali_dt_data *data;
struct denali_controller *denali;
- struct device_node *np;
int ret;

dt = devm_kzalloc(dev, sizeof(*dt), GFP_KERNEL);
@@ -204,12 +203,10 @@ static int denali_dt_probe(struct platfo
if (ret)
goto out_assert_rst;

- for_each_child_of_node(dev->of_node, np) {
+ for_each_child_of_node_scoped(dev->of_node, np) {
ret = denali_dt_chip_init(denali, np);
- if (ret) {
- of_node_put(np);
+ if (ret)
goto out_remove_denali;
- }
}

platform_set_drvdata(pdev, dt);
diff -u -p a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
--- a/drivers/mtd/nand/raw/mtk_nand.c
+++ b/drivers/mtd/nand/raw/mtk_nand.c
@@ -1432,15 +1432,12 @@ static int mtk_nfc_nand_chip_init(struct
static int mtk_nfc_nand_chips_init(struct device *dev, struct mtk_nfc *nfc)
{
struct device_node *np = dev->of_node;
- struct device_node *nand_np;
int ret;

- for_each_child_of_node(np, nand_np) {
+ for_each_child_of_node_scoped(np, nand_np) {
ret = mtk_nfc_nand_chip_init(dev, nfc, nand_np);
- if (ret) {
- of_node_put(nand_np);
+ if (ret)
return ret;
- }
}

return 0;
diff -u -p a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c
--- a/drivers/clk/at91/dt-compat.c
+++ b/drivers/clk/at91/dt-compat.c
@@ -129,7 +129,7 @@ static void __init of_sama5d2_clk_genera
struct clk_hw *hw;
unsigned int num_parents;
const char *parent_names[GENERATED_SOURCE_MAX];
- struct device_node *gcknp, *parent_np;
+ struct device_node *parent_np;
struct clk_range range = CLK_RANGE(0, 0);
struct regmap *regmap;

@@ -149,7 +149,7 @@ static void __init of_sama5d2_clk_genera
if (IS_ERR(regmap))
return;

- for_each_child_of_node(np, gcknp) {
+ for_each_child_of_node_scoped(np, gcknp) {
int chg_pid = INT_MIN;

if (of_property_read_u32(gcknp, "reg", &id))
@@ -219,7 +219,6 @@ static void __init of_sama5d2_clk_i2s_mu
struct regmap *regmap_sfr;
u8 bus_id;
const char *parent_names[2];
- struct device_node *i2s_mux_np;
struct clk_hw *hw;
int ret;

@@ -227,7 +226,7 @@ static void __init of_sama5d2_clk_i2s_mu
if (IS_ERR(regmap_sfr))
return;

- for_each_child_of_node(np, i2s_mux_np) {
+ for_each_child_of_node_scoped(np, i2s_mux_np) {
if (of_property_read_u8(i2s_mux_np, "reg", &bus_id))
continue;

@@ -743,7 +742,7 @@ of_at91_clk_prog_setup(struct device_nod
unsigned int num_parents;
const char *parent_names[PROG_SOURCE_MAX];
const char *name;
- struct device_node *progclknp, *parent_np;
+ struct device_node *parent_np;
struct regmap *regmap;

num_parents = of_clk_get_parent_count(np);
@@ -762,7 +761,7 @@ of_at91_clk_prog_setup(struct device_nod
if (IS_ERR(regmap))
return;

- for_each_child_of_node(np, progclknp) {
+ for_each_child_of_node_scoped(np, progclknp) {
if (of_property_read_u32(progclknp, "reg", &id))
continue;

@@ -875,7 +874,7 @@ static void __init of_at91rm9200_clk_sys
u32 id;
struct clk_hw *hw;
const char *name;
- struct device_node *sysclknp, *parent_np;
+ struct device_node *parent_np;
const char *parent_name;
struct regmap *regmap;

@@ -889,7 +888,7 @@ static void __init of_at91rm9200_clk_sys
if (IS_ERR(regmap))
return;

- for_each_child_of_node(np, sysclknp) {
+ for_each_child_of_node_scoped(np, sysclknp) {
unsigned long flags = 0;

if (of_property_read_u32(sysclknp, "reg", &id))
diff -u -p a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -497,11 +497,10 @@ void __init pseries_little_endian_except

static void __init pSeries_discover_phbs(void)
{
- struct device_node *node;
struct pci_controller *phb;
struct device_node *root = of_find_node_by_path("/");

- for_each_child_of_node(root, node) {
+ for_each_child_of_node_scoped(root, node) {
if (!of_node_is_type(node, "pci") &&
!of_node_is_type(node, "pciex"))
continue;
diff -u -p a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -1114,7 +1114,6 @@ void rsnd_parse_connect_ssi(struct rsnd_
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *node;
- struct device_node *np;
int i;

node = rsnd_ssi_of_node(priv);
@@ -1122,14 +1121,12 @@ void rsnd_parse_connect_ssi(struct rsnd_
return;

i = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
struct rsnd_mod *mod;

i = rsnd_node_fixed_index(dev, np, SSI_NAME, i);
- if (i < 0) {
- of_node_put(np);
+ if (i < 0)
break;
- }

mod = rsnd_ssi_mod_get(priv, i);

diff -u -p a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c
--- a/drivers/iio/adc/stm32-dfsdm-core.c
+++ b/drivers/iio/adc/stm32-dfsdm-core.c
@@ -308,7 +308,6 @@ static int stm32_dfsdm_probe_identificat
const struct stm32_dfsdm_dev_data *dev_data)
{
struct device_node *np = pdev->dev.of_node;
- struct device_node *child;
struct stm32_dfsdm *dfsdm = &priv->dfsdm;
const char *compat;
int ret, count = 0;
@@ -329,7 +328,7 @@ static int stm32_dfsdm_probe_identificat
return -EINVAL;
}

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
ret = of_property_read_string(child, "compatible", &compat);
if (ret)
continue;
diff -u -p a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -1244,7 +1244,6 @@ static int at91_pinctrl_parse_groups(str
static int at91_pinctrl_parse_functions(struct device_node *np,
struct at91_pinctrl *info, u32 index)
{
- struct device_node *child;
struct at91_pmx_func *func;
struct at91_pin_group *grp;
int ret;
@@ -1267,14 +1266,12 @@ static int at91_pinctrl_parse_functions(
if (!func->groups)
return -ENOMEM;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
func->groups[i] = child->name;
grp = &info->groups[grp_index++];
ret = at91_pinctrl_parse_groups(child, grp, info, i++);
- if (ret) {
- of_node_put(child);
+ if (ret)
return ret;
- }
}

return 0;
@@ -1296,7 +1293,6 @@ static int at91_pinctrl_probe_dt(struct
int i, j, ngpio_chips_enabled = 0;
uint32_t *tmp;
struct device_node *np = dev->of_node;
- struct device_node *child;

if (!np)
return -ENODEV;
@@ -1349,14 +1345,12 @@ static int at91_pinctrl_probe_dt(struct

i = 0;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
if (of_device_is_compatible(child, gpio_compat))
continue;
ret = at91_pinctrl_parse_functions(child, info, i++);
- if (ret) {
- of_node_put(child);
+ if (ret)
return dev_err_probe(dev, ret, "failed to parse function\n");
- }
}

return 0;
diff -u -p a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -521,7 +521,6 @@ static int rzg2l_dt_node_to_map(struct p
unsigned int *num_maps)
{
struct rzg2l_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- struct device_node *child;
unsigned int index;
int ret;

@@ -529,13 +528,11 @@ static int rzg2l_dt_node_to_map(struct p
*num_maps = 0;
index = 0;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
ret = rzg2l_dt_subnode_to_map(pctldev, child, np, map,
num_maps, &index);
- if (ret < 0) {
- of_node_put(child);
+ if (ret < 0)
goto done;
- }
}

if (*num_maps == 0) {
diff -u -p a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -436,7 +436,7 @@ static int cap11xx_led_set(struct led_cl
static int cap11xx_init_leds(struct device *dev,
struct cap11xx_priv *priv, int num_leds)
{
- struct device_node *node = dev->of_node, *child;
+ struct device_node *node = dev->of_node;
struct cap11xx_led *led;
int cnt = of_get_child_count(node);
int error;
@@ -465,7 +465,7 @@ static int cap11xx_init_leds(struct devi
if (error)
return error;

- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
u32 reg;

led->cdev.name =
@@ -478,19 +478,15 @@ static int cap11xx_init_leds(struct devi
led->cdev.brightness = LED_OFF;

error = of_property_read_u32(child, "reg", &reg);
- if (error != 0 || reg >= num_leds) {
- of_node_put(child);
+ if (error != 0 || reg >= num_leds)
return -EINVAL;
- }

led->reg = reg;
led->priv = priv;

error = devm_led_classdev_register(dev, &led->cdev);
- if (error) {
- of_node_put(child);
+ if (error)
return error;
- }

priv->num_leds++;
led++;
diff -u -p a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c
--- a/drivers/edac/xgene_edac.c
+++ b/drivers/edac/xgene_edac.c
@@ -1844,7 +1844,6 @@ static irqreturn_t xgene_edac_isr(int ir
static int xgene_edac_probe(struct platform_device *pdev)
{
struct xgene_edac *edac;
- struct device_node *child;
struct resource *res;
int rc;

@@ -1935,7 +1934,7 @@ static int xgene_edac_probe(struct platf

edac->dfs = edac_debugfs_create_dir(pdev->dev.kobj.name);

- for_each_child_of_node(pdev->dev.of_node, child) {
+ for_each_child_of_node_scoped(pdev->dev.of_node, child) {
if (!of_device_is_available(child))
continue;
if (of_device_is_compatible(child, "apm,xgene-edac-mc"))
diff -u -p a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -1171,21 +1171,18 @@ void rsnd_parse_connect_common(struct rs
{
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct device *dev = rsnd_priv_to_dev(priv);
- struct device_node *np;
int i;

if (!node)
return;

i = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
struct rsnd_mod *mod;

i = rsnd_node_fixed_index(dev, np, name, i);
- if (i < 0) {
- of_node_put(np);
+ if (i < 0)
break;
- }

mod = mod_get(priv, i);

@@ -1234,16 +1231,13 @@ int rsnd_node_fixed_index(struct device
int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name)
{
struct device *dev = rsnd_priv_to_dev(priv);
- struct device_node *np;
int i;

i = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
i = rsnd_node_fixed_index(dev, np, name, i);
- if (i < 0) {
- of_node_put(np);
+ if (i < 0)
return 0;
- }
i++;
}

diff -u -p a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -455,7 +455,6 @@ static int xvip_graph_dma_init_one(struc
static int xvip_graph_dma_init(struct xvip_composite_device *xdev)
{
struct device_node *ports;
- struct device_node *port;
int ret = 0;

ports = of_get_child_by_name(xdev->dev->of_node, "ports");
@@ -464,12 +463,10 @@ static int xvip_graph_dma_init(struct xv
return -EINVAL;
}

- for_each_child_of_node(ports, port) {
+ for_each_child_of_node_scoped(ports, port) {
ret = xvip_graph_dma_init_one(xdev, port);
- if (ret) {
- of_node_put(port);
+ if (ret)
break;
- }
}

of_node_put(ports);
diff -u -p a/drivers/pinctrl/renesas/pinctrl-rza1.c b/drivers/pinctrl/renesas/pinctrl-rza1.c
--- a/drivers/pinctrl/renesas/pinctrl-rza1.c
+++ b/drivers/pinctrl/renesas/pinctrl-rza1.c
@@ -852,7 +852,6 @@ static const struct gpio_chip rza1_gpioc
*/
static int rza1_dt_node_pin_count(struct device_node *np)
{
- struct device_node *child;
struct property *of_pins;
unsigned int npins;

@@ -861,12 +860,10 @@ static int rza1_dt_node_pin_count(struct
return of_pins->length / sizeof(u32);

npins = 0;
- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
of_pins = of_find_property(child, "pinmux", NULL);
- if (!of_pins) {
- of_node_put(child);
+ if (!of_pins)
return -EINVAL;
- }

npins += of_pins->length / sizeof(u32);
}
diff -u -p a/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c
--- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c
@@ -25,14 +25,13 @@
static unsigned int rcar_du_encoder_count_ports(struct device_node *node)
{
struct device_node *ports;
- struct device_node *port;
unsigned int num_ports = 0;

ports = of_get_child_by_name(node, "ports");
if (!ports)
ports = of_node_get(node);

- for_each_child_of_node(ports, port) {
+ for_each_child_of_node_scoped(ports, port) {
if (of_node_name_eq(port, "port"))
num_ports++;
}
diff -u -p a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -1027,7 +1027,7 @@ static const struct of_device_id altr_ed
static int __init __maybe_unused altr_init_a10_ecc_device_type(char *compat)
{
int irq;
- struct device_node *child, *np;
+ struct device_node *np;

np = of_find_compatible_node(NULL, NULL,
"altr,socfpga-a10-ecc-manager");
@@ -1036,7 +1036,7 @@ static int __init __maybe_unused altr_in
return -ENODEV;
}

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
const struct of_device_id *pdev_id;
const struct edac_device_prv_data *prv;

@@ -2109,7 +2109,6 @@ static int s10_edac_dberr_handler(struct
static int altr_edac_a10_probe(struct platform_device *pdev)
{
struct altr_arria10_edac *edac;
- struct device_node *child;

edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL);
if (!edac)
@@ -2180,7 +2179,7 @@ static int altr_edac_a10_probe(struct pl
altr_edac_a10_irq_handler, edac);
#endif

- for_each_child_of_node(pdev->dev.of_node, child) {
+ for_each_child_of_node_scoped(pdev->dev.of_node, child) {
if (!of_device_is_available(child))
continue;

diff -u -p a/drivers/pinctrl/renesas/pinctrl-rzv2m.c b/drivers/pinctrl/renesas/pinctrl-rzv2m.c
--- a/drivers/pinctrl/renesas/pinctrl-rzv2m.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzv2m.c
@@ -388,7 +388,6 @@ static int rzv2m_dt_node_to_map(struct p
unsigned int *num_maps)
{
struct rzv2m_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- struct device_node *child;
unsigned int index;
int ret;

@@ -396,13 +395,11 @@ static int rzv2m_dt_node_to_map(struct p
*num_maps = 0;
index = 0;

- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
ret = rzv2m_dt_subnode_to_map(pctldev, child, np, map,
num_maps, &index);
- if (ret < 0) {
- of_node_put(child);
+ if (ret < 0)
goto done;
- }
}

if (*num_maps == 0) {
diff -u -p a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -4727,7 +4727,6 @@ static int mtk_sgmii_init(struct mtk_eth
static int mtk_probe(struct platform_device *pdev)
{
struct resource *res = NULL, *res_sram;
- struct device_node *mac_np;
struct mtk_eth *eth;
int err, i;

@@ -4904,7 +4903,7 @@ static int mtk_probe(struct platform_dev

eth->hwlro = MTK_HAS_CAPS(eth->soc->caps, MTK_HWLRO);

- for_each_child_of_node(pdev->dev.of_node, mac_np) {
+ for_each_child_of_node_scoped(pdev->dev.of_node, mac_np) {
if (!of_device_is_compatible(mac_np,
"mediatek,eth-mac"))
continue;
@@ -4913,10 +4912,8 @@ static int mtk_probe(struct platform_dev
continue;

err = mtk_add_mac(eth, mac_np);
- if (err) {
- of_node_put(mac_np);
+ if (err)
goto err_deinit_hw;
- }
}

if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {

2024-01-31 23:52:00

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [RFC PATCH 2/5] of: Introduce for_each_child_of_node_scoped() to automate of_node_put() handling

On Sun, Jan 28, 2024 at 03:11:01PM -0600, David Lechner wrote:
> On Sun, Jan 28, 2024 at 10:06 AM Jonathan Cameron <[email protected]> wrote:
> >
> > From: Jonathan Cameron <[email protected]>
> >
> > To avoid issues with out of order cleanup, or ambiguity about when the
> > auto freed data is first instantiated, do it within the for loop definition.
> >
> > The disadvantage is that the struct device_node *child variable creation
> > is not immediately obvious where this is used.
> > However, in many cases, if there is another definition of
> > struct device_node *child; the compiler / static analysers will notify us
> > that it is unused, or uninitialized.
> >
> > Signed-off-by: Jonathan Cameron <[email protected]>
> > ---
> > include/linux/of.h | 6 ++++++
> > 1 file changed, 6 insertions(+)
> >
> > diff --git a/include/linux/of.h b/include/linux/of.h
> > index 50e882ee91da..f822226eac6d 100644
> > --- a/include/linux/of.h
> > +++ b/include/linux/of.h
> > @@ -1434,6 +1434,12 @@ static inline int of_property_read_s32(const struct device_node *np,
> > for (child = of_get_next_available_child(parent, NULL); child != NULL; \
> > child = of_get_next_available_child(parent, child))
> >
> > +#define for_each_child_of_node_scoped(parent, child) \
> > + for (struct device_node *child __free(device_node) = \
> > + of_get_next_child(parent, NULL); \
> > + child != NULL; \
> > + child = of_get_next_available_child(parent, child))
>
> Doesn't this need to match the initializer (of_get_next_child)?
> Otherwise it seems like the first node could be a disabled node but no
> other disabled nodes would be included in the iteration.
>
> It seems like we would want two macros, one for each variation,
> analogous to for_each_child_of_node() and
> for_each_available_child_of_node().

Yes, but really I'd like these the other way around. 'available' should
be the default as disabled should really be the same as a node not
present except for a few cases where it is not.

I bring it up only because if we're changing things then it is a
convenient time to change this. That's really a side issue to sorting
out how this new way should work.

Rob

2024-02-01 18:37:20

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [RFC PATCH 0/5] of: automate of_node_put() - new approach to loops.

On Sun, Jan 28, 2024 at 04:05:37PM +0000, Jonathan Cameron wrote:
> From: Jonathan Cameron <[email protected]>
>
> +CC includes peopleinterested in property.h equivalents to minimize
> duplication of discussion. Outcome of this discussion will affect:
> https://lore.kernel.org/all/[email protected]/
> [PATCH 00/13] device property / IIO: Use cleanup.h magic for fwnode_handle_put() handling.
>
> In discussion of previous approach with Rob Herring we talked about various
> ways to avoid a disconnect between the declaration of the __free(device_node)
> and the first non NULL assignment. Making this connection clear is useful for 2
> reasons:
> 1) Avoids out of order cleanup with respect to other cleanup.h usage.
> 2) Avoids disconnect between how cleanup is to be done and how the reference
> was acquired in the first place.
>
> https://lore.kernel.org/all/[email protected]/
>
> The options we discussed are:
>
> 1) Ignore this issue and merge original set.
>
> 2) Always put the declaration just before the for loop and don't set it NULL.
>
> {
> int ret;
>
> ret = ... and other fun code.
>
> struct device_node *child __free(device_node);
> for_each_child_of_node(np, child) {
> }
> }
>
> This works but careful review is needed to ensure that this unusual pattern is
> followed. We don't set it to NULL as the loop will do that anyway if there are
> no child nodes, or the loop finishes without an early break or return.
>
> 3) Introduced the pointer to auto put device_node only within the
> for loop scope.
>
> +#define for_each_child_of_node_scoped(parent, child) \
> + for (struct device_node *child __free(device_node) = \
> + of_get_next_child(parent, NULL); \
> + child != NULL; \

Just

child; \

> + child = of_get_next_available_child(parent, child))
> +
>
> This series is presenting option 3. I only implemented this loop out of
> all the similar ones and it is only compile tested.
>
> Disadvantage Rob raised is that it isn't obvious this macro will instantiate
> a struct device_node *child. I can't see a way around that other than option 2
> above, but all suggestions welcome. Note that if a conversion leaves an
> 'external' struct device_node *child variable, in many cases the compiler
> will catch that as an unused variable. We don't currently run shaddow
> variable detection in normal kernel builds, but that could also be used
> to catch such bugs.

--
With Best Regards,
Andy Shevchenko



2024-02-04 19:56:55

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [RFC PATCH 2/5] of: Introduce for_each_child_of_node_scoped() to automate of_node_put() handling

On Sun, 28 Jan 2024 15:11:01 -0600
David Lechner <[email protected]> wrote:

> On Sun, Jan 28, 2024 at 10:06 AM Jonathan Cameron <[email protected]> wrote:
> >
> > From: Jonathan Cameron <[email protected]>
> >
> > To avoid issues with out of order cleanup, or ambiguity about when the
> > auto freed data is first instantiated, do it within the for loop definition.
> >
> > The disadvantage is that the struct device_node *child variable creation
> > is not immediately obvious where this is used.
> > However, in many cases, if there is another definition of
> > struct device_node *child; the compiler / static analysers will notify us
> > that it is unused, or uninitialized.
> >
> > Signed-off-by: Jonathan Cameron <[email protected]>
> > ---
> > include/linux/of.h | 6 ++++++
> > 1 file changed, 6 insertions(+)
> >
> > diff --git a/include/linux/of.h b/include/linux/of.h
> > index 50e882ee91da..f822226eac6d 100644
> > --- a/include/linux/of.h
> > +++ b/include/linux/of.h
> > @@ -1434,6 +1434,12 @@ static inline int of_property_read_s32(const struct device_node *np,
> > for (child = of_get_next_available_child(parent, NULL); child != NULL; \
> > child = of_get_next_available_child(parent, child))
> >
> > +#define for_each_child_of_node_scoped(parent, child) \
> > + for (struct device_node *child __free(device_node) = \
> > + of_get_next_child(parent, NULL); \
> > + child != NULL; \
> > + child = of_get_next_available_child(parent, child))
>
> Doesn't this need to match the initializer (of_get_next_child)?
> Otherwise it seems like the first node could be a disabled node but no
> other disabled nodes would be included in the iteration.

FwIW that was was entirely unintentional. Not sure how it happened :(
Anyhow, now will be for_each_available_child_of_node_scoped() with the
right first call.

>
> It seems like we would want two macros, one for each variation,
> analogous to for_each_child_of_node() and
> for_each_available_child_of_node().
>
>
> > +
> > #define for_each_of_cpu_node(cpu) \
> > for (cpu = of_get_next_cpu_node(NULL); cpu != NULL; \
> > cpu = of_get_next_cpu_node(cpu))
> > --
> > 2.43.0
> >
> >


2024-02-04 20:52:52

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [RFC PATCH 2/5] of: Introduce for_each_child_of_node_scoped() to automate of_node_put() handling

On Sun, 4 Feb 2024 19:56:11 +0000
Jonathan Cameron <[email protected]> wrote:

> On Sun, 28 Jan 2024 15:11:01 -0600
> David Lechner <[email protected]> wrote:
>
> > On Sun, Jan 28, 2024 at 10:06 AM Jonathan Cameron <jic23@kernelorg> wrote:
> > >
> > > From: Jonathan Cameron <[email protected]>
> > >
> > > To avoid issues with out of order cleanup, or ambiguity about when the
> > > auto freed data is first instantiated, do it within the for loop definition.
> > >
> > > The disadvantage is that the struct device_node *child variable creation
> > > is not immediately obvious where this is used.
> > > However, in many cases, if there is another definition of
> > > struct device_node *child; the compiler / static analysers will notify us
> > > that it is unused, or uninitialized.
> > >
> > > Signed-off-by: Jonathan Cameron <[email protected]>
> > > ---
> > > include/linux/of.h | 6 ++++++
> > > 1 file changed, 6 insertions(+)
> > >
> > > diff --git a/include/linux/of.h b/include/linux/of.h
> > > index 50e882ee91da..f822226eac6d 100644
> > > --- a/include/linux/of.h
> > > +++ b/include/linux/of.h
> > > @@ -1434,6 +1434,12 @@ static inline int of_property_read_s32(const struct device_node *np,
> > > for (child = of_get_next_available_child(parent, NULL); child != NULL; \
> > > child = of_get_next_available_child(parent, child))
> > >
> > > +#define for_each_child_of_node_scoped(parent, child) \
> > > + for (struct device_node *child __free(device_node) = \
> > > + of_get_next_child(parent, NULL); \
> > > + child != NULL; \
> > > + child = of_get_next_available_child(parent, child))
> >
> > Doesn't this need to match the initializer (of_get_next_child)?
> > Otherwise it seems like the first node could be a disabled node but no
> > other disabled nodes would be included in the iteration.
>
> FwIW that was was entirely unintentional. Not sure how it happened :(
> Anyhow, now will be for_each_available_child_of_node_scoped() with the
> right first call.

*sigh* Which I can't use for the unittest case (tests fail as a result
as some nodes that need to be covered are not available) so both will need to exist
though we can hopefully review each change for whether the appropriate one
is used afterwards (ignoring whether it was with the non scoped versions)

Jonathan

>
> >
> > It seems like we would want two macros, one for each variation,
> > analogous to for_each_child_of_node() and
> > for_each_available_child_of_node().
> >
> >
> > > +
> > > #define for_each_of_cpu_node(cpu) \
> > > for (cpu = of_get_next_cpu_node(NULL); cpu != NULL; \
> > > cpu = of_get_next_cpu_node(cpu))
> > > --
> > > 2.43.0
> > >
> > >
>
>


2024-02-04 21:08:29

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [RFC PATCH 0/5] of: automate of_node_put() - new approach to loops.

On Wed, 31 Jan 2024 22:38:21 +0100 (CET)
Julia Lawall <[email protected]> wrote:

> Here are some loop cases. The semantic patch is as follows:
>
> #spatch --allow-inconsistent-paths
>
> @@
> expression node;
> identifier child;
> symbol drop_me;
> iterator name for_each_child_of_node;
> @@
>
> for_each_child_of_node(node,child) {
> ...
> + of_node_put(drop_me, child);
> }
>
> @@
> expression node;
> identifier child;
> symbol drop_me;
> iterator name for_each_child_of_node, for_each_child_of_node_scoped;
> identifier L;
> @@
>
> - struct device_node *child;
> ... when != child
> -for_each_child_of_node
> +for_each_child_of_node_scoped
> (node,child) {
> ... when strict
> (
> - {
> - of_node_put(child);
> return ...;
> - }
> |
> - {
> - of_node_put(child);
> goto L;
> - }
> |
> - {
> - of_node_put(child);
> break;
> - }
> |
> continue;
> |
> - of_node_put(child);
> return ...;
> |
> - of_node_put(child);
> break;
> |
> - of_node_put(drop_me, child);
> )
> }
> ... when != child
>
> @@
> expression child;
> @@
>
> - of_node_put(drop_me, child);
>
> -------------------------------
>
> This is quite conservative, in that it requires the only use of the child
> variable to be in a single for_each_child_of_node loop at top level.
>
> The drop_me thing is a hack to be able to refer to the bottom of the loop
> in the same way as of_node_puts in front of returns etc are referenced.
>
> This works fine when multiple device_node variables are declared at once.
>
> The result is below.
>
Very nice!

One issue is that Rob is keen that we also take this opportunity to
evaluate if the _available_ form is the more appropriate one.

Given that access either no defined "status" in the child node or
it being set to "okay" it is what should be used in the vast majority of
cases.

For reference, the property.h version only uses the available form.

So I think we'll need some hand checking of each case but for vast majority
it will be very straight forward.

One question is whether it is worth the scoped loops in cases
where there isn't a patch where we break out of or return from the loop
before it finishes. Do we put them in as a defensive measure?

Sometimes we are going to want to combine this refactor with
some of the ones your previous script caught in a single patch given
it's roughly the same sort of change.


> julia
>
> diff -u -p a/drivers/of/unittest.c b/drivers/of/unittest.c
> --- a/drivers/of/unittest.c
> +++ b/drivers/of/unittest.c
> @@ -2789,7 +2789,7 @@ static int unittest_i2c_mux_probe(struct
> int i, nchans;
> struct device *dev = &client->dev;
> struct i2c_adapter *adap = client->adapter;
> - struct device_node *np = client->dev.of_node, *child;
> + struct device_node *np = client->dev.of_node;
> struct i2c_mux_core *muxc;
> u32 reg, max_reg;
>
> @@ -2801,7 +2801,7 @@ static int unittest_i2c_mux_probe(struct
> }
>
> max_reg = (u32)-1;
> - for_each_child_of_node(np, child) {
> + for_each_child_of_node_scoped(np, child) {

This was a case I left alone in the original series because the auto
cleanup doesn't end up doing anything in any paths.

> if (of_property_read_u32(child, "reg", &reg))
> continue;
> if (max_reg == (u32)-1 || reg > max_reg)
>



> diff -u -p a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c
> --- a/drivers/regulator/scmi-regulator.c
> +++ b/drivers/regulator/scmi-regulator.c
> @@ -297,7 +297,7 @@ static int process_scmi_regulator_of_nod
> static int scmi_regulator_probe(struct scmi_device *sdev)
> {
> int d, ret, num_doms;
> - struct device_node *np, *child;
> + struct device_node *np;
> const struct scmi_handle *handle = sdev->handle;
> struct scmi_regulator_info *rinfo;
> struct scmi_protocol_handle *ph;
> @@ -341,13 +341,11 @@ static int scmi_regulator_probe(struct s
> */
> of_node_get(handle->dev->of_node);
> np = of_find_node_by_name(handle->dev->of_node, "regulators");
> - for_each_child_of_node(np, child) {
> + for_each_child_of_node_scoped(np, child) {
> ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo);
> /* abort on any mem issue */
> - if (ret == -ENOMEM) {
> - of_node_put(child);
> + if (ret == -ENOMEM)
> return ret;
> - }
Current code leaks np in this path :(

> }
> of_node_put(np);
> /*


> diff -u -p a/drivers/crypto/nx/nx-common-powernv.c b/drivers/crypto/nx/nx-common-powernv.c
> --- a/drivers/crypto/nx/nx-common-powernv.c
> +++ b/drivers/crypto/nx/nx-common-powernv.c
> @@ -907,7 +907,6 @@ static int __init nx_powernv_probe_vas(s
> {
> int chip_id, vasid, ret = 0;
> int ct_842 = 0, ct_gzip = 0;
> - struct device_node *dn;
>
> chip_id = of_get_ibm_chip_id(pn);
> if (chip_id < 0) {
> @@ -921,7 +920,7 @@ static int __init nx_powernv_probe_vas(s
> return -EINVAL;
> }
>
> - for_each_child_of_node(pn, dn) {
> + for_each_child_of_node_scoped(pn, dn) {
> ret = find_nx_device_tree(dn, chip_id, vasid, NX_CT_842,
> "ibm,p9-nx-842", &ct_842);
>
> @@ -929,10 +928,8 @@ static int __init nx_powernv_probe_vas(s
> ret = find_nx_device_tree(dn, chip_id, vasid,
> NX_CT_GZIP, "ibm,p9-nx-gzip", &ct_gzip);
The handling in here is odd (buggy?). There is an of_node_put()
in the failure path inside find_nx_device_tree() as well as out here.
>
> - if (ret) {
> - of_node_put(dn);
> + if (ret)
> return ret;
> - }
> }
>
> if (!ct_842 || !ct_gzip) {

I've glanced at a few of the others and some of them are hard.
This refactor is fine, but the other device_node handling often
is complex and I think fragile. So definitely room for improvement!

Jonathan

2024-02-04 21:36:14

by Julia Lawall

[permalink] [raw]
Subject: Re: [RFC PATCH 0/5] of: automate of_node_put() - new approach to loops.



On Sun, 4 Feb 2024, Jonathan Cameron wrote:

> On Wed, 31 Jan 2024 22:38:21 +0100 (CET)
> Julia Lawall <[email protected]> wrote:
>
> > Here are some loop cases. The semantic patch is as follows:
> >
> > #spatch --allow-inconsistent-paths
> >
> > @@
> > expression node;
> > identifier child;
> > symbol drop_me;
> > iterator name for_each_child_of_node;
> > @@
> >
> > for_each_child_of_node(node,child) {
> > ...
> > + of_node_put(drop_me, child);
> > }
> >
> > @@
> > expression node;
> > identifier child;
> > symbol drop_me;
> > iterator name for_each_child_of_node, for_each_child_of_node_scoped;
> > identifier L;
> > @@
> >
> > - struct device_node *child;
> > ... when != child
> > -for_each_child_of_node
> > +for_each_child_of_node_scoped
> > (node,child) {
> > ... when strict
> > (
> > - {
> > - of_node_put(child);
> > return ...;
> > - }
> > |
> > - {
> > - of_node_put(child);
> > goto L;
> > - }
> > |
> > - {
> > - of_node_put(child);
> > break;
> > - }
> > |
> > continue;
> > |
> > - of_node_put(child);
> > return ...;
> > |
> > - of_node_put(child);
> > break;
> > |
> > - of_node_put(drop_me, child);
> > )
> > }
> > ... when != child
> >
> > @@
> > expression child;
> > @@
> >
> > - of_node_put(drop_me, child);
> >
> > -------------------------------
> >
> > This is quite conservative, in that it requires the only use of the child
> > variable to be in a single for_each_child_of_node loop at top level.
> >
> > The drop_me thing is a hack to be able to refer to the bottom of the loop
> > in the same way as of_node_puts in front of returns etc are referenced.
> >
> > This works fine when multiple device_node variables are declared at once.
> >
> > The result is below.
> >
> Very nice!
>
> One issue is that Rob is keen that we also take this opportunity to
> evaluate if the _available_ form is the more appropriate one.
>
> Given that access either no defined "status" in the child node or
> it being set to "okay" it is what should be used in the vast majority of
> cases.
>
> For reference, the property.h version only uses the available form.
>
> So I think we'll need some hand checking of each case but for vast majority
> it will be very straight forward.

I'm not sure to follow this. If the check is straightforward, perhaps it
can be integrated into the rule? But I'm not sure what to check for.

> One question is whether it is worth the scoped loops in cases
> where there isn't a patch where we break out of or return from the loop
> before it finishes. Do we put them in as a defensive measure?

I wondered about this also. My thought was that it is better to be
uniform. And maybe a break would be added later.

> Sometimes we are going to want to combine this refactor with
> some of the ones your previous script caught in a single patch given
> it's roughly the same sort of change.

Agreed. Some blocks of code should indeed become much simpler.

>
>
> > julia
> >
> > diff -u -p a/drivers/of/unittest.c b/drivers/of/unittest.c
> > --- a/drivers/of/unittest.c
> > +++ b/drivers/of/unittest.c
> > @@ -2789,7 +2789,7 @@ static int unittest_i2c_mux_probe(struct
> > int i, nchans;
> > struct device *dev = &client->dev;
> > struct i2c_adapter *adap = client->adapter;
> > - struct device_node *np = client->dev.of_node, *child;
> > + struct device_node *np = client->dev.of_node;
> > struct i2c_mux_core *muxc;
> > u32 reg, max_reg;
> >
> > @@ -2801,7 +2801,7 @@ static int unittest_i2c_mux_probe(struct
> > }
> >
> > max_reg = (u32)-1;
> > - for_each_child_of_node(np, child) {
> > + for_each_child_of_node_scoped(np, child) {
>
> This was a case I left alone in the original series because the auto
> cleanup doesn't end up doing anything in any paths.
>
> > if (of_property_read_u32(child, "reg", &reg))
> > continue;
> > if (max_reg == (u32)-1 || reg > max_reg)
> >
>
>
>
> > diff -u -p a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c
> > --- a/drivers/regulator/scmi-regulator.c
> > +++ b/drivers/regulator/scmi-regulator.c
> > @@ -297,7 +297,7 @@ static int process_scmi_regulator_of_nod
> > static int scmi_regulator_probe(struct scmi_device *sdev)
> > {
> > int d, ret, num_doms;
> > - struct device_node *np, *child;
> > + struct device_node *np;
> > const struct scmi_handle *handle = sdev->handle;
> > struct scmi_regulator_info *rinfo;
> > struct scmi_protocol_handle *ph;
> > @@ -341,13 +341,11 @@ static int scmi_regulator_probe(struct s
> > */
> > of_node_get(handle->dev->of_node);
> > np = of_find_node_by_name(handle->dev->of_node, "regulators");
> > - for_each_child_of_node(np, child) {
> > + for_each_child_of_node_scoped(np, child) {
> > ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo);
> > /* abort on any mem issue */
> > - if (ret == -ENOMEM) {
> > - of_node_put(child);
> > + if (ret == -ENOMEM)
> > return ret;
> > - }
> Current code leaks np in this path :(
>
> > }
> > of_node_put(np);
> > /*
>
>
> > diff -u -p a/drivers/crypto/nx/nx-common-powernv.c b/drivers/crypto/nx/nx-common-powernv.c
> > --- a/drivers/crypto/nx/nx-common-powernv.c
> > +++ b/drivers/crypto/nx/nx-common-powernv.c
> > @@ -907,7 +907,6 @@ static int __init nx_powernv_probe_vas(s
> > {
> > int chip_id, vasid, ret = 0;
> > int ct_842 = 0, ct_gzip = 0;
> > - struct device_node *dn;
> >
> > chip_id = of_get_ibm_chip_id(pn);
> > if (chip_id < 0) {
> > @@ -921,7 +920,7 @@ static int __init nx_powernv_probe_vas(s
> > return -EINVAL;
> > }
> >
> > - for_each_child_of_node(pn, dn) {
> > + for_each_child_of_node_scoped(pn, dn) {
> > ret = find_nx_device_tree(dn, chip_id, vasid, NX_CT_842,
> > "ibm,p9-nx-842", &ct_842);
> >
> > @@ -929,10 +928,8 @@ static int __init nx_powernv_probe_vas(s
> > ret = find_nx_device_tree(dn, chip_id, vasid,
> > NX_CT_GZIP, "ibm,p9-nx-gzip", &ct_gzip);
> The handling in here is odd (buggy?). There is an of_node_put()
> in the failure path inside find_nx_device_tree() as well as out here.
> >
> > - if (ret) {
> > - of_node_put(dn);
> > + if (ret)
> > return ret;
> > - }
> > }
> >
> > if (!ct_842 || !ct_gzip) {
>
> I've glanced at a few of the others and some of them are hard.
> This refactor is fine, but the other device_node handling often
> is complex and I think fragile. So definitely room for improvement!

I agree with all the above comments.

julia