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

selftests/powerpc: Don't rely on segfault to rerun the test

The test case tm-signal-context-force-tm expects a segfault to happen
on returning from signal handler, and then does a setcontext() to run
the test again. However, the test doesn't always segfault, causing the
test to run a single time.

This patch fixes the test by putting it within a loop and jumping, via
setcontext, just prior to the loop in case it segfaults. This way we
get the desired behavior (run the test COUNT_MAX times) regardless if
it segfaults or not. This also reduces the use of setcontext for
control flow logic, keeping it only in the segfault handler.

Also, since 'count' is changed within the signal handler, it is
declared as volatile to prevent any compiler optimization getting
confused with asynchronous changes.

Signed-off-by: Gustavo Luiz Duarte <gustavold@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200211033831.11165-3-gustavold@linux.ibm.com

authored by

Gustavo Luiz Duarte and committed by
Michael Ellerman
0f8f554e 915b7f6f

+37 -41
+37 -41
tools/testing/selftests/powerpc/tm/tm-signal-context-force-tm.c
··· 42 42 #endif 43 43 44 44 /* Setting contexts because the test will crash and we want to recover */ 45 - ucontext_t init_context, main_context; 45 + ucontext_t init_context; 46 46 47 - static int count, first_time; 47 + /* count is changed in the signal handler, so it must be volatile */ 48 + static volatile int count; 48 49 49 50 void usr_signal_handler(int signo, siginfo_t *si, void *uc) 50 51 { ··· 99 98 100 99 void seg_signal_handler(int signo, siginfo_t *si, void *uc) 101 100 { 102 - if (count == COUNT_MAX) { 103 - /* Return to tm_signal_force_msr() and exit */ 104 - setcontext(&main_context); 105 - } 106 - 107 101 count++; 108 102 109 103 /* Reexecute the test */ ··· 122 126 */ 123 127 getcontext(&init_context); 124 128 125 - /* Allocated an alternative signal stack area */ 126 - ss.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, 127 - MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 128 - ss.ss_size = SIGSTKSZ; 129 - ss.ss_flags = 0; 129 + while (count < COUNT_MAX) { 130 + /* Allocated an alternative signal stack area */ 131 + ss.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, 132 + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 133 + ss.ss_size = SIGSTKSZ; 134 + ss.ss_flags = 0; 130 135 131 - if (ss.ss_sp == (void *)-1) { 132 - perror("mmap error\n"); 133 - exit(-1); 136 + if (ss.ss_sp == (void *)-1) { 137 + perror("mmap error\n"); 138 + exit(-1); 139 + } 140 + 141 + /* Force the allocation through a page fault */ 142 + if (madvise(ss.ss_sp, SIGSTKSZ, MADV_DONTNEED)) { 143 + perror("madvise\n"); 144 + exit(-1); 145 + } 146 + 147 + /* 148 + * Setting an alternative stack to generate a page fault when 149 + * the signal is raised. 150 + */ 151 + if (sigaltstack(&ss, NULL)) { 152 + perror("sigaltstack\n"); 153 + exit(-1); 154 + } 155 + 156 + /* The signal handler will enable MSR_TS */ 157 + sigaction(SIGUSR1, &usr_sa, NULL); 158 + /* If it does not crash, it might segfault, avoid it to retest */ 159 + sigaction(SIGSEGV, &seg_sa, NULL); 160 + 161 + raise(SIGUSR1); 162 + count++; 134 163 } 135 - 136 - /* Force the allocation through a page fault */ 137 - if (madvise(ss.ss_sp, SIGSTKSZ, MADV_DONTNEED)) { 138 - perror("madvise\n"); 139 - exit(-1); 140 - } 141 - 142 - /* Setting an alternative stack to generate a page fault when 143 - * the signal is raised. 144 - */ 145 - if (sigaltstack(&ss, NULL)) { 146 - perror("sigaltstack\n"); 147 - exit(-1); 148 - } 149 - 150 - /* The signal handler will enable MSR_TS */ 151 - sigaction(SIGUSR1, &usr_sa, NULL); 152 - /* If it does not crash, it will segfault, avoid it to retest */ 153 - sigaction(SIGSEGV, &seg_sa, NULL); 154 - 155 - raise(SIGUSR1); 156 164 } 157 165 158 166 int tm_signal_context_force_tm(void) ··· 169 169 */ 170 170 SKIP_IF(!is_ppc64le()); 171 171 172 - /* Will get back here after COUNT_MAX interactions */ 173 - getcontext(&main_context); 174 - 175 - if (!first_time++) 176 - tm_trap_test(); 172 + tm_trap_test(); 177 173 178 174 return EXIT_SUCCESS; 179 175 }