From: Pei Xiao Date: Wed, 10 Jun 2026 01:49:12 +0000 (+0800) Subject: hwmon: (gpd-fan): fix race condition between device removal and sysfs access X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1fb4397509bd8701d323e81ac9a97c2e24ed49eb;p=thirdparty%2Flinux.git 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 Link: https://lore.kernel.org/r/4400828422cf3a88adad4db224d9efccdb1049d2.1781055639.git.xiaopei01@kylinos.cn Signed-off-by: Guenter Roeck --- diff --git a/drivers/hwmon/gpd-fan.c b/drivers/hwmon/gpd-fan.c index 1b57a5add934f..d1993cd645cbc 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, },