• Charles Keepax's avatar
    regulator: core: Avoid potential deadlock on regulator_unregister · 06377301
    Charles Keepax authored
    Lockdep reports the following issue on my setup:
    
    Possible unsafe locking scenario:
    
    CPU0                    CPU1
    ----                    ----
    lock((work_completion)(&(&rdev->disable_work)->work));
                            lock(regulator_list_mutex);
                            lock((work_completion)(&(&rdev->disable_work)->work));
    lock(regulator_list_mutex);
    
    The problem is that regulator_unregister takes the
    regulator_list_mutex and then calls flush_work on disable_work. But
    regulator_disable_work calls regulator_lock_dependent which will
    also take the regulator_list_mutex. Resulting in a deadlock if the
    flush_work call actually needs to flush the work.
    
    Fix this issue by moving the flush_work outside of the
    regulator_list_mutex. The list mutex is not used to guard the point at
    which the delayed work is queued, so its use adds no additional safety.
    
    Fixes: f8702f9e ("regulator: core: Use ww_mutex for regulators locking")
    Signed-off-by: default avatarCharles Keepax <ckeepax@opensource.cirrus.com>
    Reviewed-by: default avatarDmitry Osipenko <digetx@gmail.com>
    Signed-off-by: default avatarMark Brown <broonie@kernel.org>
    06377301
core.c 142 KB