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

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: c66be905cda2 ("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>

authored by

Moon Hee Lee and committed by
Shuah Khan
07b7c2b4 a089bb28

+31 -10
+31 -10
tools/testing/selftests/breakpoints/step_after_suspend_test.c
··· 127 127 return KSFT_PASS; 128 128 } 129 129 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 + 130 155 void suspend(void) 131 156 { 132 - int power_state_fd; 133 157 int timerfd; 134 158 int err; 159 + int count_before; 160 + int count_after; 135 161 struct itimerspec spec = {}; 136 162 137 163 if (getuid() != 0) 138 164 ksft_exit_skip("Please run the test as root - Exiting.\n"); 139 - 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 165 146 166 timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0); 147 167 if (timerfd < 0) ··· 172 152 if (err < 0) 173 153 ksft_exit_fail_msg("timerfd_settime() failed\n"); 174 154 155 + count_before = get_suspend_success_count_or_fail(); 156 + 175 157 system("(echo mem > /sys/power/state) 2> /dev/null"); 176 158 177 - timerfd_gettime(timerfd, &spec); 178 - if (spec.it_value.tv_sec != 0 || spec.it_value.tv_nsec != 0) 159 + count_after = get_suspend_success_count_or_fail(); 160 + if (count_after <= count_before) 179 161 ksft_exit_fail_msg("Failed to enter Suspend state\n"); 180 162 181 163 close(timerfd); 182 - close(power_state_fd); 183 164 } 184 165 185 166 int main(int argc, char **argv)