[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20260116022638.994778-1-tuhaowen@uniontech.com>
Date: Fri, 16 Jan 2026 10:26:38 +0800
From: tuhaowen <tuhaowen@...ontech.com>
To: "Rafael J . Wysocki" <rafael@...nel.org>
Cc: Pavel Machek <pavel@...nel.org>,
Len Brown <lenb@...nel.org>,
linux-pm@...r.kernel.org,
linux-kernel@...r.kernel.org,
tuhaowen@...ontech.com
Subject: [PATCH] PM: sleep: Fix race condition in suspend statistics updates
The suspend_stats structure tracks suspend/resume failure information
and is protected by suspend_stats_lock. However, while
dpm_save_failed_dev() correctly uses this lock, dpm_save_failed_step()
and dpm_save_errno() modify the same structure without any locking
protection.
This can cause races between writers (suspend/resume code updating
stats) and readers (userspace reading from /sys/power/suspend_stats/
or debugfs), leading to:
- Lost updates to counters (success, fail, step_failures)
- Corrupted circular buffer indices (last_failed_step,
last_failed_errno)
- Inconsistent data when reading statistics from sysfs/debugfs
Fix this by adding mutex_lock/unlock protection to both
dpm_save_failed_step() and dpm_save_errno(). These functions are
always called in process context, so mutex can be used safely.
Signed-off-by: tuhaowen <tuhaowen@...ontech.com>
---
kernel/power/main.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/kernel/power/main.c b/kernel/power/main.c
index bb7dd73e18fc..d8b053d85dc0 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -503,16 +503,23 @@ void dpm_save_failed_dev(const char *name)
void dpm_save_failed_step(enum suspend_stat_step step)
{
+ mutex_lock(&suspend_stats_lock);
+
suspend_stats.step_failures[step-1]++;
suspend_stats.failed_steps[suspend_stats.last_failed_step] = step;
suspend_stats.last_failed_step++;
suspend_stats.last_failed_step %= REC_FAILED_NUM;
+
+ mutex_unlock(&suspend_stats_lock);
}
void dpm_save_errno(int err)
{
+ mutex_lock(&suspend_stats_lock);
+
if (!err) {
suspend_stats.success++;
+ mutex_unlock(&suspend_stats_lock);
return;
}
@@ -521,6 +528,8 @@ void dpm_save_errno(int err)
suspend_stats.errno[suspend_stats.last_failed_errno] = err;
suspend_stats.last_failed_errno++;
suspend_stats.last_failed_errno %= REC_FAILED_NUM;
+
+ mutex_unlock(&suspend_stats_lock);
}
void pm_report_hw_sleep_time(u64 t)
--
2.20.1
Powered by blists - more mailing lists