• Krzysztof Kozlowski's avatar
    power: charger-manager: Fix accessing invalidated power supply after fuel gauge unbind · bdbe8144
    Krzysztof Kozlowski authored
    The charger manager obtained reference to fuel gauge power supply in probe
    with power_supply_get_by_name() for later usage. However if fuel gauge
    driver was removed and re-added then this reference would point to old
    power supply (from driver which was removed).
    
    This lead to accessing old (and probably invalid) memory which could be
    observed with:
    $ echo "12-0036" > /sys/bus/i2c/drivers/max17042/unbind
    $ echo "12-0036" > /sys/bus/i2c/drivers/max17042/bind
    $ cat /sys/devices/virtual/power_supply/battery/capacity
    [  240.480084] INFO: task cat:1393 blocked for more than 120 seconds.
    [  240.484799]       Not tainted 3.17.0-next-20141007-00028-ge60b6dd79570 #203
    [  240.491782] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
    [  240.499589] cat             D c0469530     0  1393      1 0x00000000
    [  240.505947] [<c0469530>] (__schedule) from [<c0469d3c>] (schedule_preempt_disabled+0x14/0x20)
    [  240.514449] [<c0469d3c>] (schedule_preempt_disabled) from [<c046af08>] (mutex_lock_nested+0x1bc/0x458)
    [  240.523736] [<c046af08>] (mutex_lock_nested) from [<c0287a98>] (regmap_read+0x30/0x60)
    [  240.531647] [<c0287a98>] (regmap_read) from [<c032238c>] (max17042_get_property+0x2e8/0x350)
    [  240.540055] [<c032238c>] (max17042_get_property) from [<c03247d8>] (charger_get_property+0x264/0x348)
    [  240.549252] [<c03247d8>] (charger_get_property) from [<c0320764>] (power_supply_show_property+0x48/0x1e0)
    [  240.558808] [<c0320764>] (power_supply_show_property) from [<c027308c>] (dev_attr_show+0x1c/0x48)
    [  240.567664] [<c027308c>] (dev_attr_show) from [<c0141fb0>] (sysfs_kf_seq_show+0x84/0x104)
    [  240.575814] [<c0141fb0>] (sysfs_kf_seq_show) from [<c0140b18>] (kernfs_seq_show+0x24/0x28)
    [  240.584061] [<c0140b18>] (kernfs_seq_show) from [<c0104574>] (seq_read+0x1b0/0x484)
    [  240.591702] [<c0104574>] (seq_read) from [<c00e1e24>] (vfs_read+0x88/0x144)
    [  240.598640] [<c00e1e24>] (vfs_read) from [<c00e1f20>] (SyS_read+0x40/0x8c)
    [  240.605507] [<c00e1f20>] (SyS_read) from [<c000e760>] (ret_fast_syscall+0x0/0x48)
    [  240.612952] 4 locks held by cat/1393:
    [  240.616589]  #0:  (&p->lock){+.+.+.}, at: [<c01043f4>] seq_read+0x30/0x484
    [  240.623414]  #1:  (&of->mutex){+.+.+.}, at: [<c01417dc>] kernfs_seq_start+0x1c/0x8c
    [  240.631086]  #2:  (s_active#31){++++.+}, at: [<c01417e4>] kernfs_seq_start+0x24/0x8c
    [  240.638777]  #3:  (&map->mutex){+.+...}, at: [<c0287a98>] regmap_read+0x30/0x60
    
    The charger-manager should get reference to fuel gauge power supply on
    each use of get_property callback. The thermal zone 'tzd' field of
    power supply should not be used because of the same reason.
    
    Additionally this change solves also the issue with nested
    thermal_zone_get_temp() calls and related false lockdep positive for
    deadlock for thermal zone's mutex [1]. When fuel gauge is used as source of
    temperature then the charger manager forwards its get_temp calls to fuel
    gauge thermal zone. So actually different mutexes are used (one for
    charger manager thermal zone and second for fuel gauge thermal zone) but
    for lockdep this is one class of mutex.
    
    The recursion is removed by retrieving temperature through power
    supply's get_property().
    
    In case external thermal zone is used ('cm-thermal-zone' property is
    present in DTS) the recursion does not exist. Charger manager simply
    exports POWER_SUPPLY_PROP_TEMP_AMBIENT property (instead of
    POWER_SUPPLY_PROP_TEMP) thus no thermal zone is created for this power
    supply.
    
    [1] https://lkml.org/lkml/2014/10/6/309Signed-off-by: default avatarKrzysztof Kozlowski <k.kozlowski@samsung.com>
    Cc: <stable@vger.kernel.org>
    Fixes: 3bb3dbbd ("power_supply: Add initial Charger-Manager driver")
    Signed-off-by: default avatarSebastian Reichel <sre@kernel.org>
    bdbe8144
charger-manager.c 56.3 KB