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

regulator: Fix lockdep warning resolving supplies

With commit eaa7995c529b54 (regulator: core: avoid
regulator_resolve_supply() race condition) we started holding the rdev
lock while resolving supplies, an operation that requires holding the
regulator_list_mutex. This results in lockdep warnings since in other
places we take the list mutex then the mutex on an individual rdev.

Since the goal is to make sure that we don't call set_supply() twice
rather than a concern about the cost of resolution pull the rdev lock
and check for duplicate resolution down to immediately before we do the
set_supply() and drop it again once the allocation is done.

Fixes: eaa7995c529b54 (regulator: core: avoid regulator_resolve_supply() race condition)
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20210122132042.10306-1-broonie@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>

+19 -14
+19 -14
drivers/regulator/core.c
··· 1823 1823 if (rdev->supply) 1824 1824 return 0; 1825 1825 1826 - /* 1827 - * Recheck rdev->supply with rdev->mutex lock held to avoid a race 1828 - * between rdev->supply null check and setting rdev->supply in 1829 - * set_supply() from concurrent tasks. 1830 - */ 1831 - regulator_lock(rdev); 1832 - 1833 - /* Supply just resolved by a concurrent task? */ 1834 - if (rdev->supply) 1835 - goto out; 1836 - 1837 1826 r = regulator_dev_lookup(dev, rdev->supply_name); 1838 1827 if (IS_ERR(r)) { 1839 1828 ret = PTR_ERR(r); ··· 1874 1885 goto out; 1875 1886 } 1876 1887 1877 - ret = set_supply(rdev, r); 1878 - if (ret < 0) { 1888 + /* 1889 + * Recheck rdev->supply with rdev->mutex lock held to avoid a race 1890 + * between rdev->supply null check and setting rdev->supply in 1891 + * set_supply() from concurrent tasks. 1892 + */ 1893 + regulator_lock(rdev); 1894 + 1895 + /* Supply just resolved by a concurrent task? */ 1896 + if (rdev->supply) { 1897 + regulator_unlock(rdev); 1879 1898 put_device(&r->dev); 1880 1899 goto out; 1881 1900 } 1901 + 1902 + ret = set_supply(rdev, r); 1903 + if (ret < 0) { 1904 + regulator_unlock(rdev); 1905 + put_device(&r->dev); 1906 + goto out; 1907 + } 1908 + 1909 + regulator_unlock(rdev); 1882 1910 1883 1911 /* 1884 1912 * In set_machine_constraints() we may have turned this regulator on ··· 1912 1906 } 1913 1907 1914 1908 out: 1915 - regulator_unlock(rdev); 1916 1909 return ret; 1917 1910 } 1918 1911