pinctrl: Fix two deadlocks

This patch is to fix two deadlock cases.
Deadlock 1:
CPU #1
 pinctrl_register-> pinctrl_get ->
 create_pinctrl
 (Holding lock pinctrl_maps_mutex)
 -> get_pinctrl_dev_from_devname
 (Trying to acquire lock pinctrldev_list_mutex)
CPU #0
 pinctrl_unregister
 (Holding lock pinctrldev_list_mutex)
 -> pinctrl_put ->> pinctrl_free ->
 pinctrl_dt_free_maps -> pinctrl_unregister_map
 (Trying to acquire lock pinctrl_maps_mutex)

Simply to say
CPU#1 is holding lock A and trying to acquire lock B,
CPU#0 is holding lock B and trying to acquire lock A.

Deadlock 2:
CPU #3
 pinctrl_register-> pinctrl_get ->
 create_pinctrl
 (Holding lock pinctrl_maps_mutex)
 -> get_pinctrl_dev_from_devname
 (Trying to acquire lock pinctrldev_list_mutex)
CPU #2
 pinctrl_unregister
 (Holding lock pctldev->mutex)
 -> pinctrl_put ->> pinctrl_free ->
 pinctrl_dt_free_maps -> pinctrl_unregister_map
 (Trying to acquire lock pinctrl_maps_mutex)
CPU #0
 tegra_gpio_request
 (Holding lock pinctrldev_list_mutex)
 -> pinctrl_get_device_gpio_range
 (Trying to acquire lock pctldev->mutex)

Simply to say
CPU#3 is holding lock A and trying to acquire lock D,
CPU#2 is holding lock B and trying to acquire lock A,
CPU#0 is holding lock D and trying to acquire lock B.

Cc: Stable <stable@vger.kernel.org>
Signed-off-by: Jim Lin <jilin@nvidia.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
Jim Lin 2015-01-08 20:25:05 +08:00 committed by Linus Walleij
parent 53b1bfc76d
commit db93facfb0

View File

@ -1801,14 +1801,15 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
if (pctldev == NULL) if (pctldev == NULL)
return; return;
mutex_lock(&pinctrldev_list_mutex);
mutex_lock(&pctldev->mutex); mutex_lock(&pctldev->mutex);
pinctrl_remove_device_debugfs(pctldev); pinctrl_remove_device_debugfs(pctldev);
mutex_unlock(&pctldev->mutex);
if (!IS_ERR(pctldev->p)) if (!IS_ERR(pctldev->p))
pinctrl_put(pctldev->p); pinctrl_put(pctldev->p);
mutex_lock(&pinctrldev_list_mutex);
mutex_lock(&pctldev->mutex);
/* TODO: check that no pinmuxes are still active? */ /* TODO: check that no pinmuxes are still active? */
list_del(&pctldev->node); list_del(&pctldev->node);
/* Destroy descriptor tree */ /* Destroy descriptor tree */