Commit c31a0c052205e3ec24efc3fe18ef70c3e913f2d4
Committed by
Grant Likely
1 parent
bfc4a58986
Exists in
master
and in
20 other branches
of: fix recursive locking in of_get_next_available_child()
of_get_next_available_child() acquires devtree_lock, then calls of_device_is_available() which calls of_get_property() which calls of_find_property() which tries to re-acquire devtree_lock, thus causing deadlock. To avoid this, create a new __of_device_is_available() which calls __of_get_property() instead, which calls __of_find_property(), which does not take the lock,. Update of_get_next_available_child() to call the new __of_device_is_available() since it already owns the lock. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Showing 1 changed file with 25 additions and 5 deletions Side-by-side Diff
drivers/of/base.c
... | ... | @@ -290,19 +290,19 @@ |
290 | 290 | EXPORT_SYMBOL(of_machine_is_compatible); |
291 | 291 | |
292 | 292 | /** |
293 | - * of_device_is_available - check if a device is available for use | |
293 | + * __of_device_is_available - check if a device is available for use | |
294 | 294 | * |
295 | - * @device: Node to check for availability | |
295 | + * @device: Node to check for availability, with locks already held | |
296 | 296 | * |
297 | 297 | * Returns 1 if the status property is absent or set to "okay" or "ok", |
298 | 298 | * 0 otherwise |
299 | 299 | */ |
300 | -int of_device_is_available(const struct device_node *device) | |
300 | +static int __of_device_is_available(const struct device_node *device) | |
301 | 301 | { |
302 | 302 | const char *status; |
303 | 303 | int statlen; |
304 | 304 | |
305 | - status = of_get_property(device, "status", &statlen); | |
305 | + status = __of_get_property(device, "status", &statlen); | |
306 | 306 | if (status == NULL) |
307 | 307 | return 1; |
308 | 308 | |
... | ... | @@ -313,6 +313,26 @@ |
313 | 313 | |
314 | 314 | return 0; |
315 | 315 | } |
316 | + | |
317 | +/** | |
318 | + * of_device_is_available - check if a device is available for use | |
319 | + * | |
320 | + * @device: Node to check for availability | |
321 | + * | |
322 | + * Returns 1 if the status property is absent or set to "okay" or "ok", | |
323 | + * 0 otherwise | |
324 | + */ | |
325 | +int of_device_is_available(const struct device_node *device) | |
326 | +{ | |
327 | + unsigned long flags; | |
328 | + int res; | |
329 | + | |
330 | + raw_spin_lock_irqsave(&devtree_lock, flags); | |
331 | + res = __of_device_is_available(device); | |
332 | + raw_spin_unlock_irqrestore(&devtree_lock, flags); | |
333 | + return res; | |
334 | + | |
335 | +} | |
316 | 336 | EXPORT_SYMBOL(of_device_is_available); |
317 | 337 | |
318 | 338 | /** |
... | ... | @@ -404,7 +424,7 @@ |
404 | 424 | raw_spin_lock(&devtree_lock); |
405 | 425 | next = prev ? prev->sibling : node->child; |
406 | 426 | for (; next; next = next->sibling) { |
407 | - if (!of_device_is_available(next)) | |
427 | + if (!__of_device_is_available(next)) | |
408 | 428 | continue; |
409 | 429 | if (of_node_get(next)) |
410 | 430 | break; |