Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/cell: Add missing of_node_put()s in cbe_regs.c

There are several bugs as following:

(1) In cbe_get_be_node(), hold the reference returned by of_find_xxx and
of_get_xxx OF APIs and use it to call of_node_put().
(2) In cbe_fill_regs_map(), same as above.
(3) In cbe_regs_init(), during the iteration of for_each_node_by_type(),
the refcount of 'cpu' will be automatically increased and decreased.
However, there is a reference escaped out into 'map->cpu_node' and
it should be properly handled.

Signed-off-by: Liang He <windhl@126.com>
[mpe: Drop references before pointer equality test in cbe_get_be_node()]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20220701144949.252364-1-windhl@126.com

authored by

Liang He and committed by
Michael Ellerman
ad4b3236 d9e1c610

+27 -10
+27 -10
arch/powerpc/platforms/cell/cbe_regs.c
··· 182 182 if (WARN_ON_ONCE(!cpu_handle)) 183 183 return np; 184 184 185 - for (i=0; i<len; i++) 186 - if (of_find_node_by_phandle(cpu_handle[i]) == of_get_cpu_node(cpu_id, NULL)) 185 + for (i = 0; i < len; i++) { 186 + struct device_node *ch_np = of_find_node_by_phandle(cpu_handle[i]); 187 + struct device_node *ci_np = of_get_cpu_node(cpu_id, NULL); 188 + 189 + of_node_put(ch_np); 190 + of_node_put(ci_np); 191 + 192 + if (ch_np == ci_np) 187 193 return np; 194 + } 188 195 } 189 196 190 197 return NULL; ··· 200 193 static void __init cbe_fill_regs_map(struct cbe_regs_map *map) 201 194 { 202 195 if(map->be_node) { 203 - struct device_node *be, *np; 196 + struct device_node *be, *np, *parent_np; 204 197 205 198 be = map->be_node; 206 199 207 - for_each_node_by_type(np, "pervasive") 208 - if (of_get_parent(np) == be) 200 + for_each_node_by_type(np, "pervasive") { 201 + parent_np = of_get_parent(np); 202 + if (parent_np == be) 209 203 map->pmd_regs = of_iomap(np, 0); 204 + of_node_put(parent_np); 205 + } 210 206 211 - for_each_node_by_type(np, "CBEA-Internal-Interrupt-Controller") 212 - if (of_get_parent(np) == be) 207 + for_each_node_by_type(np, "CBEA-Internal-Interrupt-Controller") { 208 + parent_np = of_get_parent(np); 209 + if (parent_np == be) 213 210 map->iic_regs = of_iomap(np, 2); 211 + of_node_put(parent_np); 212 + } 214 213 215 - for_each_node_by_type(np, "mic-tm") 216 - if (of_get_parent(np) == be) 214 + for_each_node_by_type(np, "mic-tm") { 215 + parent_np = of_get_parent(np); 216 + if (parent_np == be) 217 217 map->mic_tm_regs = of_iomap(np, 0); 218 + of_node_put(parent_np); 219 + } 218 220 } else { 219 221 struct device_node *cpu; 220 222 /* That hack must die die die ! */ ··· 277 261 of_node_put(cpu); 278 262 return; 279 263 } 280 - map->cpu_node = cpu; 264 + of_node_put(map->cpu_node); 265 + map->cpu_node = of_node_get(cpu); 281 266 282 267 for_each_possible_cpu(i) { 283 268 struct cbe_thread_map *thread = &cbe_thread_map[i];