Skip to content

Commit 07b7c2b

Browse files
moonheeleeshuahkh
authored andcommitted
selftests: breakpoints: use suspend_stats to reliably check suspend success
The step_after_suspend_test verifies that the system successfully suspended and resumed by setting a timerfd and checking whether the timer fully expired. However, this method is unreliable due to timing races. In practice, the system may take time to enter suspend, during which the timer may expire just before or during the transition. As a result, the remaining time after resume may show non-zero nanoseconds, even if suspend/resume completed successfully. This leads to false test failures. Replace the timer-based check with a read from /sys/power/suspend_stats/success. This counter is incremented only after a full suspend/resume cycle, providing a reliable and race-free indicator. Also remove the unused file descriptor for /sys/power/state, which remained after switching to a system() call to trigger suspend [1]. [1] https://lore.kernel.org/all/20240930224025.2858767-1-yifei.l.liu@oracle.com/ Link: https://lore.kernel.org/r/20250626191626.36794-1-moonhee.lee.ca@gmail.com Fixes: c66be90 ("selftests: breakpoints: use remaining time to check if suspend succeed") Signed-off-by: Moon Hee Lee <moonhee.lee.ca@gmail.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
1 parent a089bb2 commit 07b7c2b

1 file changed

Lines changed: 31 additions & 10 deletions

File tree

tools/testing/selftests/breakpoints/step_after_suspend_test.c

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -127,22 +127,42 @@ int run_test(int cpu)
127127
return KSFT_PASS;
128128
}
129129

130+
/*
131+
* Reads the suspend success count from sysfs.
132+
* Returns the count on success or exits on failure.
133+
*/
134+
static int get_suspend_success_count_or_fail(void)
135+
{
136+
FILE *fp;
137+
int val;
138+
139+
fp = fopen("/sys/power/suspend_stats/success", "r");
140+
if (!fp)
141+
ksft_exit_fail_msg(
142+
"Failed to open suspend_stats/success: %s\n",
143+
strerror(errno));
144+
145+
if (fscanf(fp, "%d", &val) != 1) {
146+
fclose(fp);
147+
ksft_exit_fail_msg(
148+
"Failed to read suspend success count\n");
149+
}
150+
151+
fclose(fp);
152+
return val;
153+
}
154+
130155
void suspend(void)
131156
{
132-
int power_state_fd;
133157
int timerfd;
134158
int err;
159+
int count_before;
160+
int count_after;
135161
struct itimerspec spec = {};
136162

137163
if (getuid() != 0)
138164
ksft_exit_skip("Please run the test as root - Exiting.\n");
139165

140-
power_state_fd = open("/sys/power/state", O_RDWR);
141-
if (power_state_fd < 0)
142-
ksft_exit_fail_msg(
143-
"open(\"/sys/power/state\") failed %s)\n",
144-
strerror(errno));
145-
146166
timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
147167
if (timerfd < 0)
148168
ksft_exit_fail_msg("timerfd_create() failed\n");
@@ -152,14 +172,15 @@ void suspend(void)
152172
if (err < 0)
153173
ksft_exit_fail_msg("timerfd_settime() failed\n");
154174

175+
count_before = get_suspend_success_count_or_fail();
176+
155177
system("(echo mem > /sys/power/state) 2> /dev/null");
156178

157-
timerfd_gettime(timerfd, &spec);
158-
if (spec.it_value.tv_sec != 0 || spec.it_value.tv_nsec != 0)
179+
count_after = get_suspend_success_count_or_fail();
180+
if (count_after <= count_before)
159181
ksft_exit_fail_msg("Failed to enter Suspend state\n");
160182

161183
close(timerfd);
162-
close(power_state_fd);
163184
}
164185

165186
int main(int argc, char **argv)

0 commit comments

Comments
 (0)