Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

platform/x86: hp-wmi: add locking for concurrent hwmon access

hp_wmi_hwmon_priv.mode and .pwm are written by hp_wmi_hwmon_write() in
sysfs context and read by hp_wmi_hwmon_keep_alive_handler() in a
workqueue. A concurrent write and keep-alive expiry can observe an
inconsistent mode/pwm pair (e.g. mode=MANUAL with a stale pwm).

Add a mutex to hp_wmi_hwmon_priv protecting mode and pwm. Hold it in
hp_wmi_hwmon_write() across the field update and apply call, and in
hp_wmi_hwmon_keep_alive_handler() before calling apply.

In hp_wmi_hwmon_read(), only the pwm_enable path reads priv->mode; use
scoped_guard() there to avoid holding the lock across unrelated WMI
calls.

Fixes: c203c59fb5de ("platform/x86: hp-wmi: implement fan keep-alive")
Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Emre Cecanpunar <emreleno@gmail.com>
Link: https://patch.msgid.link/20260407142515.20683-6-emreleno@gmail.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>

authored by

Emre Cecanpunar and committed by
Ilpo Järvinen
5969c55e cb4daa45

+13 -2
+13 -2
drivers/platform/x86/hp/hp-wmi.c
··· 453 453 }; 454 454 455 455 struct hp_wmi_hwmon_priv { 456 + struct mutex lock; /* protects mode, pwm */ 456 457 u8 min_rpm; 457 458 u8 max_rpm; 458 459 int gpu_delta; ··· 2423 2422 { 2424 2423 struct hp_wmi_hwmon_priv *priv; 2425 2424 int rpm, ret; 2425 + u8 mode; 2426 2426 2427 2427 priv = dev_get_drvdata(dev); 2428 2428 switch (type) { ··· 2447 2445 *val = rpm_to_pwm(rpm / 100, priv); 2448 2446 return 0; 2449 2447 } 2450 - switch (priv->mode) { 2448 + scoped_guard(mutex, &priv->lock) 2449 + mode = priv->mode; 2450 + switch (mode) { 2451 2451 case PWM_MODE_MAX: 2452 2452 case PWM_MODE_MANUAL: 2453 2453 case PWM_MODE_AUTO: 2454 - *val = priv->mode; 2454 + *val = mode; 2455 2455 return 0; 2456 2456 default: 2457 2457 /* shouldn't happen */ ··· 2471 2467 int rpm; 2472 2468 2473 2469 priv = dev_get_drvdata(dev); 2470 + guard(mutex)(&priv->lock); 2474 2471 switch (type) { 2475 2472 case hwmon_pwm: 2476 2473 if (attr == hwmon_pwm_input) { ··· 2540 2535 2541 2536 dwork = to_delayed_work(work); 2542 2537 priv = container_of(dwork, struct hp_wmi_hwmon_priv, keep_alive_dwork); 2538 + 2539 + guard(mutex)(&priv->lock); 2543 2540 /* 2544 2541 * Re-apply the current hwmon context settings. 2545 2542 * NOTE: hp_wmi_apply_fan_settings will handle the re-scheduling. ··· 2597 2590 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 2598 2591 if (!priv) 2599 2592 return -ENOMEM; 2593 + 2594 + ret = devm_mutex_init(dev, &priv->lock); 2595 + if (ret) 2596 + return ret; 2600 2597 2601 2598 ret = hp_wmi_setup_fan_settings(priv); 2602 2599 if (ret)