hwmon: (adm9240) fix data race in adm9240_fan_read
authorLi Zhong <floridsleeves@gmail.com>
Sat, 24 Sep 2022 00:17:51 +0000 (17:17 -0700)
committerGuenter Roeck <linux@roeck-us.net>
Sun, 25 Sep 2022 21:22:11 +0000 (14:22 -0700)
In
adm9240_read()
  adm9240_fan_read()
    adm9240_write_fan_div(),

it assumes that the caller of adm9240_write_fan_div() must hold
data->update_lock. Otherwise, it may cause data races when data is
updated by other threads.

Signed-off-by: Li Zhong <floridsleeves@gmail.com>
Link: https://lore.kernel.org/r/20220924001751.1726369-1-floridsleeves@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
drivers/hwmon/adm9240.c

index 483cd757abd339a402ff6bd3ccf53dabd4b7eda1..40e3558d37096fc9dd879134389c2572004018ae 100644 (file)
@@ -501,17 +501,23 @@ static int adm9240_fan_read(struct device *dev, u32 attr, int channel, long *val
 
        switch (attr) {
        case hwmon_fan_input:
+               mutex_lock(&data->update_lock);
                err = regmap_read(data->regmap, ADM9240_REG_FAN(channel), &regval);
-               if (err < 0)
+               if (err < 0) {
+                       mutex_unlock(&data->update_lock);
                        return err;
+               }
                if (regval == 255 && data->fan_div[channel] < 3) {
                        /* adjust fan clock divider on overflow */
                        err = adm9240_write_fan_div(data, channel,
                                                    ++data->fan_div[channel]);
-                       if (err)
+                       if (err) {
+                               mutex_unlock(&data->update_lock);
                                return err;
+                       }
                }
                *val = FAN_FROM_REG(regval, BIT(data->fan_div[channel]));
+               mutex_unlock(&data->update_lock);
                break;
        case hwmon_fan_div:
                *val = BIT(data->fan_div[channel]);