summaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
authorFrank Rowand <frank.rowand@sony.com>2018-12-18 14:40:03 -0500
committerRob Herring <robh@kernel.org>2018-12-21 13:42:36 -0500
commit5801169a2ed20003f771acecf3ac00574cf10a38 (patch)
tree56bcdc99f2d669033eea3c4308e52419a44ddc7e /drivers/of
parentb8a9ac1a5b99a2fcbed19fd29d2d59270c281a31 (diff)
of: __of_detach_node() - remove node from phandle cache
Non-overlay dynamic devicetree node removal may leave the node in the phandle cache. Subsequent calls to of_find_node_by_phandle() will incorrectly find the stale entry. Remove the node from the cache. Add paranoia checks in of_find_node_by_phandle() as a second level of defense (do not return cached node if detached, do not add node to cache if detached). Fixes: 0b3ce78e90fc ("of: cache phandle nodes to reduce cost of of_find_node_by_phandle()") Reported-by: Michael Bringmann <mwb@linux.vnet.ibm.com> Cc: stable@vger.kernel.org # v4.17+ Signed-off-by: Frank Rowand <frank.rowand@sony.com> Signed-off-by: Rob Herring <robh@kernel.org>
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/base.c31
-rw-r--r--drivers/of/dynamic.c3
-rw-r--r--drivers/of/of_private.h4
3 files changed, 37 insertions, 1 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 4da1c688995b..5226e898476e 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -169,6 +169,28 @@ int of_free_phandle_cache(void)
169late_initcall_sync(of_free_phandle_cache); 169late_initcall_sync(of_free_phandle_cache);
170#endif 170#endif
171 171
172/*
173 * Caller must hold devtree_lock.
174 */
175void __of_free_phandle_cache_entry(phandle handle)
176{
177 phandle masked_handle;
178 struct device_node *np;
179
180 if (!handle)
181 return;
182
183 masked_handle = handle & phandle_cache_mask;
184
185 if (phandle_cache) {
186 np = phandle_cache[masked_handle];
187 if (np && handle == np->phandle) {
188 of_node_put(np);
189 phandle_cache[masked_handle] = NULL;
190 }
191 }
192}
193
172void of_populate_phandle_cache(void) 194void of_populate_phandle_cache(void)
173{ 195{
174 unsigned long flags; 196 unsigned long flags;
@@ -1214,11 +1236,18 @@ struct device_node *of_find_node_by_phandle(phandle handle)
1214 if (phandle_cache[masked_handle] && 1236 if (phandle_cache[masked_handle] &&
1215 handle == phandle_cache[masked_handle]->phandle) 1237 handle == phandle_cache[masked_handle]->phandle)
1216 np = phandle_cache[masked_handle]; 1238 np = phandle_cache[masked_handle];
1239 if (np && of_node_check_flag(np, OF_DETACHED)) {
1240 WARN_ON(1); /* did not uncache np on node removal */
1241 of_node_put(np);
1242 phandle_cache[masked_handle] = NULL;
1243 np = NULL;
1244 }
1217 } 1245 }
1218 1246
1219 if (!np) { 1247 if (!np) {
1220 for_each_of_allnodes(np) 1248 for_each_of_allnodes(np)
1221 if (np->phandle == handle) { 1249 if (np->phandle == handle &&
1250 !of_node_check_flag(np, OF_DETACHED)) {
1222 if (phandle_cache) { 1251 if (phandle_cache) {
1223 /* will put when removed from cache */ 1252 /* will put when removed from cache */
1224 of_node_get(np); 1253 of_node_get(np);
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index b4e5b90cb314..a09c1c3cf831 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -277,6 +277,9 @@ void __of_detach_node(struct device_node *np)
277 } 277 }
278 278
279 of_node_set_flag(np, OF_DETACHED); 279 of_node_set_flag(np, OF_DETACHED);
280
281 /* race with of_find_node_by_phandle() prevented by devtree_lock */
282 __of_free_phandle_cache_entry(np->phandle);
280} 283}
281 284
282/** 285/**
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 5d1567025358..24786818e32e 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -84,6 +84,10 @@ static inline void __of_detach_node_sysfs(struct device_node *np) {}
84int of_resolve_phandles(struct device_node *tree); 84int of_resolve_phandles(struct device_node *tree);
85#endif 85#endif
86 86
87#if defined(CONFIG_OF_DYNAMIC)
88void __of_free_phandle_cache_entry(phandle handle);
89#endif
90
87#if defined(CONFIG_OF_OVERLAY) 91#if defined(CONFIG_OF_OVERLAY)
88void of_overlay_mutex_lock(void); 92void of_overlay_mutex_lock(void);
89void of_overlay_mutex_unlock(void); 93void of_overlay_mutex_unlock(void);