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

selftests: breakpoint: add step_after_suspend_test

Commit e56d82a11617 ("arm64: cpu hotplug: ensure we mask out
CPU_TASKS_FROZEN in notifiers") fixed a long-standing ARM64 bug that
broke single-stepping after a suspend/resume cycle. Add a kernel
selftest to make sure this doesn't regress or affect other platforms.

Signed-off-by: Greg Hackmann <ghackmann@google.com>
Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>

authored by

Greg Hackmann and committed by
Shuah Khan
bfd092b8 9d22f6e1

+221 -1
+3 -1
tools/testing/selftests/breakpoints/Makefile
··· 6 6 TEST_PROGS := breakpoint_test 7 7 endif 8 8 9 + TEST_PROGS += step_after_suspend_test 10 + 9 11 all: $(TEST_PROGS) 10 12 11 13 include ../lib.mk 12 14 13 15 clean: 14 - rm -fr breakpoint_test 16 + rm -fr breakpoint_test step_after_suspend_test
+218
tools/testing/selftests/breakpoints/step_after_suspend_test.c
··· 1 + /* 2 + * Copyright (C) 2016 Google, Inc. 3 + * 4 + * This software is licensed under the terms of the GNU General Public 5 + * License version 2, as published by the Free Software Foundation, and 6 + * may be copied, distributed, and modified under those terms. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + * 13 + */ 14 + 15 + #define _GNU_SOURCE 16 + 17 + #include <errno.h> 18 + #include <fcntl.h> 19 + #include <sched.h> 20 + #include <signal.h> 21 + #include <stdbool.h> 22 + #include <stdio.h> 23 + #include <string.h> 24 + #include <unistd.h> 25 + #include <sys/ptrace.h> 26 + #include <sys/stat.h> 27 + #include <sys/timerfd.h> 28 + #include <sys/types.h> 29 + #include <sys/wait.h> 30 + 31 + #include "../kselftest.h" 32 + 33 + void child(int cpu) 34 + { 35 + cpu_set_t set; 36 + 37 + CPU_ZERO(&set); 38 + CPU_SET(cpu, &set); 39 + if (sched_setaffinity(0, sizeof(set), &set) != 0) { 40 + perror("sched_setaffinity() failed"); 41 + _exit(1); 42 + } 43 + 44 + if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) { 45 + perror("ptrace(PTRACE_TRACEME) failed"); 46 + _exit(1); 47 + } 48 + 49 + if (raise(SIGSTOP) != 0) { 50 + perror("raise(SIGSTOP) failed"); 51 + _exit(1); 52 + } 53 + 54 + _exit(0); 55 + } 56 + 57 + bool run_test(int cpu) 58 + { 59 + int status; 60 + pid_t pid = fork(); 61 + pid_t wpid; 62 + 63 + if (pid < 0) { 64 + perror("fork() failed"); 65 + return false; 66 + } 67 + if (pid == 0) 68 + child(cpu); 69 + 70 + wpid = waitpid(pid, &status, __WALL); 71 + if (wpid != pid) { 72 + perror("waitpid() failed"); 73 + return false; 74 + } 75 + if (!WIFSTOPPED(status)) { 76 + printf("child did not stop\n"); 77 + return false; 78 + } 79 + if (WSTOPSIG(status) != SIGSTOP) { 80 + printf("child did not stop with SIGSTOP\n"); 81 + return false; 82 + } 83 + 84 + if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) { 85 + if (errno == EIO) { 86 + printf("ptrace(PTRACE_SINGLESTEP) not supported on this architecture\n"); 87 + ksft_exit_skip(); 88 + } 89 + perror("ptrace(PTRACE_SINGLESTEP) failed"); 90 + return false; 91 + } 92 + 93 + wpid = waitpid(pid, &status, __WALL); 94 + if (wpid != pid) { 95 + perror("waitpid() failed"); 96 + return false; 97 + } 98 + if (WIFEXITED(status)) { 99 + printf("child did not single-step\n"); 100 + return false; 101 + } 102 + if (!WIFSTOPPED(status)) { 103 + printf("child did not stop\n"); 104 + return false; 105 + } 106 + if (WSTOPSIG(status) != SIGTRAP) { 107 + printf("child did not stop with SIGTRAP\n"); 108 + return false; 109 + } 110 + 111 + if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { 112 + perror("ptrace(PTRACE_CONT) failed"); 113 + return false; 114 + } 115 + 116 + wpid = waitpid(pid, &status, __WALL); 117 + if (wpid != pid) { 118 + perror("waitpid() failed"); 119 + return false; 120 + } 121 + if (!WIFEXITED(status)) { 122 + printf("child did not exit after PTRACE_CONT\n"); 123 + return false; 124 + } 125 + 126 + return true; 127 + } 128 + 129 + void suspend(void) 130 + { 131 + int power_state_fd; 132 + struct sigevent event = {}; 133 + int timerfd; 134 + int err; 135 + struct itimerspec spec = {}; 136 + 137 + power_state_fd = open("/sys/power/state", O_RDWR); 138 + if (power_state_fd < 0) { 139 + perror("open(\"/sys/power/state\") failed (is this test running as root?)"); 140 + ksft_exit_fail(); 141 + } 142 + 143 + timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0); 144 + if (timerfd < 0) { 145 + perror("timerfd_create() failed"); 146 + ksft_exit_fail(); 147 + } 148 + 149 + spec.it_value.tv_sec = 5; 150 + err = timerfd_settime(timerfd, 0, &spec, NULL); 151 + if (err < 0) { 152 + perror("timerfd_settime() failed"); 153 + ksft_exit_fail(); 154 + } 155 + 156 + if (write(power_state_fd, "mem", strlen("mem")) != strlen("mem")) { 157 + perror("entering suspend failed"); 158 + ksft_exit_fail(); 159 + } 160 + 161 + close(timerfd); 162 + close(power_state_fd); 163 + } 164 + 165 + int main(int argc, char **argv) 166 + { 167 + int opt; 168 + bool do_suspend = true; 169 + bool succeeded = true; 170 + cpu_set_t available_cpus; 171 + int err; 172 + int cpu; 173 + 174 + while ((opt = getopt(argc, argv, "n")) != -1) { 175 + switch (opt) { 176 + case 'n': 177 + do_suspend = false; 178 + break; 179 + default: 180 + printf("Usage: %s [-n]\n", argv[0]); 181 + printf(" -n: do not trigger a suspend/resume cycle before the test\n"); 182 + return -1; 183 + } 184 + } 185 + 186 + if (do_suspend) 187 + suspend(); 188 + 189 + err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus); 190 + if (err < 0) { 191 + perror("sched_getaffinity() failed"); 192 + ksft_exit_fail(); 193 + } 194 + 195 + for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 196 + bool test_success; 197 + 198 + if (!CPU_ISSET(cpu, &available_cpus)) 199 + continue; 200 + 201 + test_success = run_test(cpu); 202 + printf("CPU %d: ", cpu); 203 + if (test_success) { 204 + printf("[OK]\n"); 205 + ksft_inc_pass_cnt(); 206 + } else { 207 + printf("[FAILED]\n"); 208 + ksft_inc_fail_cnt(); 209 + succeeded = false; 210 + } 211 + } 212 + 213 + ksft_print_cnts(); 214 + if (succeeded) 215 + ksft_exit_pass(); 216 + else 217 + ksft_exit_fail(); 218 + }