Skip to contentSkip to conversation

powerpc/powermac: Add missing of_node_put

PATCH In review Nicolas Palix 5 participants 9 messages Dec 2, 2008 – Dec 7, 2008

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 powerpc/powermac: Add missing of_node_put

of_node_put is needed before discarding a value received from of_find_node_by_name, eg in error handling code or when the device node is no longer used.

The semantic match that catches the bug is as follows:
(http://www.emn.fr/x-info/coccinelle/)

// <smpl>
@r exists@
local idexpression struct device_node *n;
position p1, p2;
struct device_node *n1;
statement S;
identifier f;
expression E;
expression *ptr != NULL;
@@

n@p1 = of_find_node_by_name(...)
...
if (!n) S
... when != of_node_put(n)

    when != n1 = f(n,...)
    when != E = n
    when any
    when strict

(
return \(0\|<+...n...+>\|ptr\);
|
return@p2 ...;
|
of_node_put(n);
|
n1 = f(n,...)
|
E = n
)

@script:python@
p1 << r.p1;
p2 << r.p2;
@@

print "* file: %s of_find_node_by_name %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // </smpl>

---
 arch/powerpc/platforms/powermac/pci.c     |    2 ++
 arch/powerpc/platforms/powermac/time.c    |    4 +++-
 2 files changed, 5 insertions(+), 1 deletion(-)
arch/powerpc/platforms/powermac/pci.c +2 -0
index bcf50d7..800fcce 100644
@@ -661,6 +661,7 @@ static void __init init_second_ohare(void)
 			pci_find_hose_for_OF_device(np);
 		if (!hose) {
 			printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
+			of_node_put(np);
 			return;
 		}
 		early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
@@ -669,6 +670,7 @@ static void __init init_second_ohare(void)
 		early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
 	}
 	has_second_ohare = 1;
+	of_node_put(np);
 }
 
 /*
arch/powerpc/platforms/powermac/time.c +3 -1
index 59eb840..394593c 100644
@@ -265,12 +265,14 @@ int __init via_calibrate_decr(void)
 	struct resource rsrc;
 
 	vias = of_find_node_by_name(NULL, "via-cuda");
 	if (vias = 0)
 		vias = of_find_node_by_name(NULL, "via-pmu");
 	if (vias = 0)
 		vias = of_find_node_by_name(NULL, "via");
 	if (vias = 0 || of_address_to_resource(vias, 0, &rsrc))
 		return 0;
+	of_node_put(vias);
+
 	via = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
 	if (via = NULL) {
 		printk(KERN_ERR "Failed to map VIA for timer calibration !\n");
@@ -297,7 +299,7 @@ int __init via_calibrate_decr(void)
 	ppc_tb_freq = (dstart - dend) * 100 / 6;
 
 	iounmap(via);
-	
+
 	return 1;
 }
 #endif
Signature · 1 line
Nicolas Palix
#1 lore raw

Hi Nicolas,

Thanks for all this work.

I think this particular patch is also required against Linus' kernel (not just linux-next).

Quoted 14 lines · On Tue, 2 Dec 2008 14:45:18 +0100 Nicolas Palix <[email protected]> wrote:
arch/powerpc/platforms/powermac/pci.c +1 -0
index bcf50d7..800fcce 100644
@@ -661,6 +661,7 @@ static void __init init_second_ohare(void)
 			pci_find_hose_for_OF_device(np);
 		if (!hose) {
 			printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
+			of_node_put(np);
 			return;
 		}
 		early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);

arch/powerpc/platforms/powermac/pci.c static void __init init_second_ohare(void) · line 674

Quoted 5 lines
arch/powerpc/platforms/powermac/pci.c +1 -0
@@ -669,6 +670,7 @@ static void __init init_second_ohare(void)
 		early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
 	}
 	has_second_ohare = 1;
+	of_node_put(np);
 }

This part looks good.

Quoted 6 lines
arch/powerpc/platforms/powermac/time.c +0 -0
index 59eb840..394593c 100644
@@ -265,12 +265,14 @@ int __init via_calibrate_decr(void)
 	struct resource rsrc;

arch/powerpc/platforms/powermac/time.c int __init via_calibrate_decr(void) · line 275

Quoted 10 lines
arch/powerpc/platforms/powermac/time.c +2 -0
 
 	vias = of_find_node_by_name(NULL, "via-cuda");
 	if (vias == 0)
 		vias = of_find_node_by_name(NULL, "via-pmu");
 	if (vias == 0)
 		vias = of_find_node_by_name(NULL, "via");
 	if (vias == 0 || of_address_to_resource(vias, 0, &rsrc))
 		return 0;
+	of_node_put(vias);
+

But this needs to also do the of_node_put() if the above "return 0" is taken i.e. if of_address_to_resource() fails.

Signature · 3 lines
Cheers,
Stephen Rothwell                    [email protected]
http://www.canb.auug.org.au/~sfr/
#2 lore raw

Hi Nicolas,

Quoted 3 lines · On Wed, 3 Dec 2008 10:19:01 +1100 Stephen Rothwell <[email protected]> wrote:

I think this particular patch is also required against Linus' kernel (not just linux-next).

In fact, I think all these patches can apply to Linus' current tree.

Signature · 3 lines
Cheers,
Stephen Rothwell                    [email protected]
http://www.canb.auug.org.au/~sfr/
#3 lore raw

Hi Stephen,

I fix the patch. I also change the "vias = 0" in "vias = NULL". Is "!vias" better ?

Quoted 9 lines · On Wednesday 03 December 2008 00:25:08 Stephen Rothwell wrote:

Hi Nicolas,

Quoted 3 lines · On Wed, 3 Dec 2008 10:19:01 +1100 Stephen Rothwell <[email protected]> wrote:

I think this particular patch is also required against Linus' kernel (not just linux-next).

In fact, I think all these patches can apply to Linus' current tree.

---
 arch/powerpc/platforms/powermac/pci.c  |    2 +
 arch/powerpc/platforms/powermac/time.c |   11 ++++++----
 2 files changed, 9 insertions(+), 4 deletions(-)
arch/powerpc/platforms/powermac/pci.c +2 -0
index bcf50d7..800fcce 100644
@@ -661,6 +661,7 @@ static void __init init_second_ohare(void)
 			pci_find_hose_for_OF_device(np);
 		if (!hose) {
 			printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
+			of_node_put(np);
 			return;
 		}
 		early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
@@ -669,6 +670,7 @@ static void __init init_second_ohare(void)
 		early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
 	}
 	has_second_ohare = 1;
+	of_node_put(np);
 }
 
 /*
arch/powerpc/platforms/powermac/time.c +7 -4
index 59eb840..1810e42 100644
@@ -265,12 +265,15 @@ int __init via_calibrate_decr(void)
 	struct resource rsrc;
 
 	vias = of_find_node_by_name(NULL, "via-cuda");
-	if (vias = 0)
+	if (vias = NULL)
 		vias = of_find_node_by_name(NULL, "via-pmu");
-	if (vias = 0)
+	if (vias = NULL)
 		vias = of_find_node_by_name(NULL, "via");
-	if (vias = 0 || of_address_to_resource(vias, 0, &rsrc))
+	if (vias = NULL || of_address_to_resource(vias, 0, &rsrc)) {
+	        of_node_put(vias);
 		return 0;
+	}
+	of_node_put(vias);
 	via = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
 	if (via = NULL) {
 		printk(KERN_ERR "Failed to map VIA for timer calibration !\n");
@@ -297,7 +300,7 @@ int __init via_calibrate_decr(void)
 	ppc_tb_freq = (dstart - dend) * 100 / 6;
 
 	iounmap(via);
-	
+
 	return 1;
 }
 #endif
Signature · 1 line
Nicolas Palix
#4 lore raw
In reply to Nicolas Palix
Quoted 4 lines · On Tue, 2 Dec 2008 14:45:18 +0100 Nicolas Palix <[email protected]> wrote:
arch/powerpc/platforms/powermac/time.c +0 -0
@@ -265,12 +265,14 @@ int __init via_calibrate_decr(void)
 	struct resource rsrc;

arch/powerpc/platforms/powermac/time.c int __init via_calibrate_decr(void) · line 275

Quoted 10 lines
arch/powerpc/platforms/powermac/time.c +2 -0
 
 	vias = of_find_node_by_name(NULL, "via-cuda");
 	if (vias = 0)
 		vias = of_find_node_by_name(NULL, "via-pmu");
 	if (vias = 0)
 		vias = of_find_node_by_name(NULL, "via");
 	if (vias = 0 || of_address_to_resource(vias, 0, &rsrc))
 		return 0;
+	of_node_put(vias);
+

This still misses a path - if that `return 0' is taken, we still leak the reference.

This is reason #345 why sprinkling return statements all over your code is bad.

I fixed it up thusly. Please check.

of_node_put is needed before discarding a value received from of_find_node_by_name, eg in error handling code or when the device node is no longer used.

The semantic match that catches the bug is as follows:
(http://www.emn.fr/x-info/coccinelle/)

// <smpl>
@r exists@
local idexpression struct device_node *n;
position p1, p2;
struct device_node *n1;
statement S;
identifier f;
expression E;
expression *ptr != NULL;
@@

n@p1 = of_find_node_by_name(...)
...
if (!n) S
... when != of_node_put(n)

    when != n1 = f(n,...)
    when != E = n
    when any
    when strict

(
return \(0\|<+...n...+>\|ptr\);
|
return@p2 ...;
|
of_node_put(n);
|
n1 = f(n,...)
|
E = n
)

@script:python@
p1 << r.p1;
p2 << r.p2;
@@

print "* file: %s of_find_node_by_name %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // </smpl>

---

index bcf50d7..800fcce 100644

---

 arch/powerpc/platforms/powermac/pci.c  |    2 ++
 arch/powerpc/platforms/powermac/time.c |    9 ++++++---
 2 files changed, 8 insertions(+), 3 deletions(-)
arch/powerpc/platforms/powermac/pci.c renamed from arch/powerpc/platforms/powermac/pci.c~powerpc-powermac-add-missing-of_node_put +2 -0
diff -puN arch/powerpc/platforms/powermac/pci.c~powerpc-powermac-add-missing-of_node_put arch/powerpc/platforms/powermac/pci.c
@@ -661,6 +661,7 @@ static void __init init_second_ohare(voi
 			pci_find_hose_for_OF_device(np);
 		if (!hose) {
 			printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
+			of_node_put(np);
 			return;
 		}
 		early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
@@ -669,6 +670,7 @@ static void __init init_second_ohare(voi
 		early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
 	}
 	has_second_ohare = 1;
+	of_node_put(np);
 }
 
 /*
arch/powerpc/platforms/powermac/time.c renamed from arch/powerpc/platforms/powermac/time.c~powerpc-powermac-add-missing-of_node_put +6 -3
diff -puN arch/powerpc/platforms/powermac/time.c~powerpc-powermac-add-missing-of_node_put arch/powerpc/platforms/powermac/time.c
@@ -270,11 +270,11 @@ int __init via_calibrate_decr(void)
 	if (vias = 0)
 		vias = of_find_node_by_name(NULL, "via");
 	if (vias = 0 || of_address_to_resource(vias, 0, &rsrc))
-		return 0;
+		goto fail;
 	via = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
 	if (via = NULL) {
 		printk(KERN_ERR "Failed to map VIA for timer calibration !\n");
-		return 0;
+		goto fail;
 	}
 
 	/* set timer 1 for continuous interrupts */
@@ -297,8 +297,11 @@ int __init via_calibrate_decr(void)
 	ppc_tb_freq = (dstart - dend) * 100 / 6;
 
 	iounmap(via);
-	
+
 	return 1;
+fail:
+	of_node_put(vias);
+	return 0;
 }
 #endif
 

_

#5 lore raw
Quoted 7 lines · Andrew Morton

This still misses a path - if that `return 0' is taken, we still leak the reference.

This is reason #345 why sprinkling return statements all over your code is bad.

I fixed it up thusly. Please check.

I'm really in two minds about applying any of the of_node_put patches that only affect powermacs. The reference counts only matter on platforms where we update the OF device tree at runtime, which is currently only IBM pSeries machines. Since we don't have any hotplug on powermacs, and never will have, the OF device tree is completely static and we don't actually need refcounts on the nodes at all, so who cares if they're a bit higher than they might be?

In particular, the VIA whose node we're looking for here is built-in on the motherboard, and there can never be more than one, and it can never be removed.

Paul.

#6 lore raw

Hi Paul,

Quoted 9 lines · On Sun, 7 Dec 2008 13:31:00 +1100 Paul Mackerras <[email protected]> wrote:

I'm really in two minds about applying any of the of_node_put patches that only affect powermacs. The reference counts only matter on platforms where we update the OF device tree at runtime, which is currently only IBM pSeries machines. Since we don't have any hotplug on powermacs, and never will have, the OF device tree is completely static and we don't actually need refcounts on the nodes at all, so who cares if they're a bit higher than they might be?

Quoted 3 lines

In particular, the VIA whose node we're looking for here is built-in on the motherboard, and there can never be more than one, and it can never be removed.

I my mind it is about consistent use of the API and good examples for people to copy. Also, in about a year you will be presented with the same set of patches when a new pair of eyes looks at the same code and notices the discrepancy ...

Signature · 3 lines
Cheers,
Stephen Rothwell                    [email protected]
http://www.canb.auug.org.au/~sfr/
#7 lore raw
Quoted 12 lines · On Sunday 07 December 2008 06:43:33 Stephen Rothwell wrote:

Hi Paul,

Quoted 9 lines · On Sun, 7 Dec 2008 13:31:00 +1100 Paul Mackerras <[email protected]> wrote:

I'm really in two minds about applying any of the of_node_put patches that only affect powermacs. The reference counts only matter on platforms where we update the OF device tree at runtime, which is currently only IBM pSeries machines. Since we don't have any hotplug on powermacs, and never will have, the OF device tree is completely static and we don't actually need refcounts on the nodes at all, so who cares if they're a bit higher than they might be?

Quoted 9 lines
Quoted 3 lines

In particular, the VIA whose node we're looking for here is built-in on the motherboard, and there can never be more than one, and it can never be removed.

I my mind it is about consistent use of the API and good examples for people to copy. Also, in about a year you will be presented with the same set of patches when a new pair of eyes looks at the same code and notices the discrepancy ...

Hi Andrew,

Indeed, there is an updated version of this patch in my second mail which fixes this issue.

http://lkml.org/lkml/2008/12/3/88

Moreover, there is still a reference count unbalanced with your patch in the case where the function returns 1.

Regards,

Signature · 1 line
Nicolas Palix
#8 lore raw
In reply to Stephen Rothwell
Quoted 12 lines · Stephen Rothwell

Hi Paul,

Quoted 9 lines · On Sun, 7 Dec 2008 13:31:00 +1100 Paul Mackerras <[email protected]> wrote:

I'm really in two minds about applying any of the of_node_put patches that only affect powermacs. The reference counts only matter on platforms where we update the OF device tree at runtime, which is currently only IBM pSeries machines. Since we don't have any hotplug on powermacs, and never will have, the OF device tree is completely static and we don't actually need refcounts on the nodes at all, so who cares if they're a bit higher than they might be?

Quoted 8 lines
Quoted 3 lines

In particular, the VIA whose node we're looking for here is built-in on the motherboard, and there can never be more than one, and it can never be removed.

I my mind it is about consistent use of the API and good examples for people to copy. Also, in about a year you will be presented with the same set of patches when a new pair of eyes looks at the same code and notices the discrepancy ...

what-he-said++

Allowing the ref counting to be broken in one part of the code is just asking for it to be broken everywhere.

cheers

Signature · 8 lines
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person