]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
cpufreq: Fix hotplug-suspend race during reboot
authorTianxiang Chen <nanmu@xiaomi.com>
Wed, 8 Apr 2026 14:19:14 +0000 (22:19 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 21 May 2026 15:17:16 +0000 (17:17 +0200)
During system reboot, cpufreq_suspend() is called via the
kernel_restart() -> device_shutdown() path. Unlike the normal system
suspend path, the reboot path does not call freeze_processes(), so
userspace processes and kernel threads remain active.

This allows CPU hotplug operations to run concurrently with
cpufreq_suspend(). The original code has no synchronization with CPU
hotplug, leading to a race condition where governor_data can be freed
by the hotplug path while cpufreq_suspend() is still accessing it,
resulting in a null pointer dereference:

  Unable to handle kernel NULL pointer dereference
  Call Trace:
   do_kernel_fault+0x28/0x3c
   cpufreq_suspend+0xdc/0x160
   device_shutdown+0x18/0x200
   kernel_restart+0x40/0x80
   arm64_sys_reboot+0x1b0/0x200

Fix this by adding cpus_read_lock()/cpus_read_unlock() to
cpufreq_suspend() to block CPU hotplug operations while suspend is in
progress.

Fixes: 65650b35133f ("cpufreq: Avoid cpufreq_suspend() deadlock on system shutdown")
Signed-off-by: Tianxiang Chen <nanmu@xiaomi.com>
Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
Cc: All applicable <stable@vger.kernel.org>
[ rjw: Changelog edits ]
Link: https://patch.msgid.link/20260408141914.35281-1-nanmu@xiaomi.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/cpufreq/cpufreq.c

index 44eb1b7e7fc1bc6d683fdcb135cc532dd2c9e86e..d41067cd1f1b25315b525957e3de3d25dcd01e63 100644 (file)
@@ -1972,6 +1972,7 @@ void cpufreq_suspend(void)
        if (!cpufreq_driver)
                return;
 
+       cpus_read_lock();
        if (!has_target() && !cpufreq_driver->suspend)
                goto suspend;
 
@@ -1991,6 +1992,7 @@ void cpufreq_suspend(void)
 
 suspend:
        cpufreq_suspended = true;
+       cpus_read_unlock();
 }
 
 /**