mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
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: 0ab88e2394 ("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>
This commit is contained in:
parent
046e6e1a02
commit
1fb4397509
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user