summaryrefslogtreecommitdiff
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorPei Xiao <xiaopei01@kylinos.cn>2026-06-10 09:49:12 +0800
committerGuenter Roeck <linux@roeck-us.net>2026-06-10 06:14:57 -0700
commit1fb4397509bd8701d323e81ac9a97c2e24ed49eb (patch)
tree5ce7f0c0e1b09992587517e67ca54666c003d733 /drivers/hwmon
parent046e6e1a023437bf80358cecba37ea58ebe89e94 (diff)
downloadlinux-next-1fb4397509bd8701d323e81ac9a97c2e24ed49eb.tar.gz
linux-next-1fb4397509bd8701d323e81ac9a97c2e24ed49eb.zip
hwmon: (gpd-fan): fix race condition between device removal and sysfs access
Replace the manual gpd_fan_remove() callback with a devres-managed action using devm_add_action_or_reset(). The original remove hook resets the fan to AUTOMATIC mode, but the hwmon sysfs interface (registered with devm_hwmon_device_register_with_info()) remains active until after the remove callback completes. This creates a race window where a concurrent userspace sysfs access can interleave with the EC I/O sequence, potentially corrupting EC registers. Using devm_add_action_or_reset() registers the reset function as a devres action. Due to the LIFO release order of devres, the hwmon device is unregistered (sysfs removed) before the reset action executes, eliminating the race condition. Fixes: 0ab88e239439 ("hwmon: add GPD devices sensor driver") Signed-off-by: Pei Xiao <xiaopei01@kylinos.cn> Link: https://lore.kernel.org/r/4400828422cf3a88adad4db224d9efccdb1049d2.1781055639.git.xiaopei01@kylinos.cn Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/gpd-fan.c27
1 files changed, 16 insertions, 11 deletions
diff --git a/drivers/hwmon/gpd-fan.c b/drivers/hwmon/gpd-fan.c
index 1b57a5add934..d1993cd645cb 100644
--- a/drivers/hwmon/gpd-fan.c
+++ b/drivers/hwmon/gpd-fan.c
@@ -609,6 +609,16 @@ static void gpd_init_ec(struct gpd_fan_data *data)
gpd_win4_init_ec(data);
}
+static void gpd_fan_reset_hardware(void *pdata)
+{
+ struct gpd_fan_data *data = pdata;
+
+ if (data) {
+ data->pwm_enable = AUTOMATIC;
+ gpd_set_pwm_enable(data, AUTOMATIC);
+ }
+}
+
static int gpd_fan_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -617,6 +627,7 @@ static int gpd_fan_probe(struct platform_device *pdev)
struct device *hwdev;
struct gpd_fan_data *data;
const struct gpd_fan_drvdata *match;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res)
@@ -644,6 +655,11 @@ static int gpd_fan_probe(struct platform_device *pdev)
dev_set_drvdata(dev, data);
gpd_init_ec(data);
+
+ ret = devm_add_action_or_reset(dev, gpd_fan_reset_hardware, data);
+ if (ret)
+ return ret;
+
hwdev = devm_hwmon_device_register_with_info(dev,
DRIVER_NAME,
data,
@@ -655,19 +671,8 @@ static int gpd_fan_probe(struct platform_device *pdev)
return 0;
}
-static void gpd_fan_remove(struct platform_device *pdev)
-{
- struct gpd_fan_data *data = dev_get_drvdata(&pdev->dev);
-
- if (data) {
- data->pwm_enable = AUTOMATIC;
- gpd_set_pwm_enable(data, AUTOMATIC);
- }
-}
-
static struct platform_driver gpd_fan_driver = {
.probe = gpd_fan_probe,
- .remove = gpd_fan_remove,
.driver = {
.name = KBUILD_MODNAME,
},