• David Collins's avatar
    regulator: core: avoid regulator_resolve_supply() race condition · eaa7995c
    David Collins authored
    The final step in regulator_register() is to call
    regulator_resolve_supply() for each registered regulator
    (including the one in the process of being registered).  The
    regulator_resolve_supply() function first checks if rdev->supply
    is NULL, then it performs various steps to try to find the supply.
    If successful, rdev->supply is set inside of set_supply().
    
    This procedure can encounter a race condition if two concurrent
    tasks call regulator_register() near to each other on separate CPUs
    and one of the regulators has rdev->supply_name specified.  There
    is currently nothing guaranteeing atomicity between the rdev->supply
    check and set steps.  Thus, both tasks can observe rdev->supply==NULL
    in their regulator_resolve_supply() calls.  This then results in
    both creating a struct regulator for the supply.  One ends up
    actually stored in rdev->supply and the other is lost (though still
    present in the supply's consumer_list).
    
    Here is a kernel log snippet showing the issue:
    
    [   12.421768] gpu_cc_gx_gdsc: supplied by pm8350_s5_level
    [   12.425854] gpu_cc_gx_gdsc: supplied by pm8350_s5_level
    [   12.429064] debugfs: Directory 'regulator.4-SUPPLY' with parent
                   '17a00000.rsc:rpmh-regulator-gfxlvl-pm8350_s5_level'
                   already present!
    
    Avoid this race condition by holding the rdev->mutex lock inside
    of regulator_resolve_supply() while checking and setting
    rdev->supply.
    Signed-off-by: default avatarDavid Collins <collinsd@codeaurora.org>
    Link: https://lore.kernel.org/r/1610068562-4410-1-git-send-email-collinsd@codeaurora.orgSigned-off-by: default avatarMark Brown <broonie@kernel.org>
    eaa7995c
core.c 152 KB