Commit c31a0c052205e3ec24efc3fe18ef70c3e913f2d4

Authored by Stephen Warren
Committed by Grant Likely
1 parent bfc4a58986

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

... ... @@ -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;