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

selftests/powerpc: Add transactional syscall test

Check that a syscall made during an active transaction will fail with
the correct failure code and that one made during a suspended
transaction will succeed.

Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Sam bobroff and committed by
Michael Ellerman
7fe924d9 2b03fc1d

+153 -1
+1
tools/testing/selftests/powerpc/tm/.gitignore
··· 1 1 tm-resched-dscr 2 + tm-syscall
+4 -1
tools/testing/selftests/powerpc/tm/Makefile
··· 1 - PROGS := tm-resched-dscr 1 + PROGS := tm-resched-dscr tm-syscall 2 2 3 3 all: $(PROGS) 4 4 5 5 $(PROGS): ../harness.c 6 + 7 + tm-syscall: tm-syscall-asm.S 8 + tm-syscall: CFLAGS += -mhtm 6 9 7 10 run_tests: all 8 11 @-for PROG in $(PROGS); do \
+27
tools/testing/selftests/powerpc/tm/tm-syscall-asm.S
··· 1 + #include <ppc-asm.h> 2 + #include <asm/unistd.h> 3 + 4 + .text 5 + FUNC_START(getppid_tm_active) 6 + tbegin. 7 + beq 1f 8 + li r0, __NR_getppid 9 + sc 10 + tend. 11 + blr 12 + 1: 13 + li r3, -1 14 + blr 15 + 16 + FUNC_START(getppid_tm_suspended) 17 + tbegin. 18 + beq 1f 19 + li r0, __NR_getppid 20 + tsuspend. 21 + sc 22 + tresume. 23 + tend. 24 + blr 25 + 1: 26 + li r3, -1 27 + blr
+121
tools/testing/selftests/powerpc/tm/tm-syscall.c
··· 1 + /* 2 + * Copyright 2015, Sam Bobroff, IBM Corp. 3 + * Licensed under GPLv2. 4 + * 5 + * Test the kernel's system call code to ensure that a system call 6 + * made from within an active HTM transaction is aborted with the 7 + * correct failure code. 8 + * Conversely, ensure that a system call made from within a 9 + * suspended transaction can succeed. 10 + */ 11 + 12 + #include <stdio.h> 13 + #include <unistd.h> 14 + #include <sys/syscall.h> 15 + #include <asm/tm.h> 16 + #include <asm/cputable.h> 17 + #include <linux/auxvec.h> 18 + #include <sys/time.h> 19 + #include <stdlib.h> 20 + 21 + #include "utils.h" 22 + 23 + extern int getppid_tm_active(void); 24 + extern int getppid_tm_suspended(void); 25 + 26 + unsigned retries = 0; 27 + 28 + #define TEST_DURATION 10 /* seconds */ 29 + #define TM_RETRIES 100 30 + 31 + long failure_code(void) 32 + { 33 + return __builtin_get_texasru() >> 24; 34 + } 35 + 36 + bool failure_is_persistent(void) 37 + { 38 + return (failure_code() & TM_CAUSE_PERSISTENT) == TM_CAUSE_PERSISTENT; 39 + } 40 + 41 + bool failure_is_syscall(void) 42 + { 43 + return (failure_code() & TM_CAUSE_SYSCALL) == TM_CAUSE_SYSCALL; 44 + } 45 + 46 + pid_t getppid_tm(bool suspend) 47 + { 48 + int i; 49 + pid_t pid; 50 + 51 + for (i = 0; i < TM_RETRIES; i++) { 52 + if (suspend) 53 + pid = getppid_tm_suspended(); 54 + else 55 + pid = getppid_tm_active(); 56 + 57 + if (pid >= 0) 58 + return pid; 59 + 60 + if (failure_is_persistent()) { 61 + if (failure_is_syscall()) 62 + return -1; 63 + 64 + printf("Unexpected persistent transaction failure.\n"); 65 + printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n", 66 + __builtin_get_texasr(), __builtin_get_tfiar()); 67 + exit(-1); 68 + } 69 + 70 + retries++; 71 + } 72 + 73 + printf("Exceeded limit of %d temporary transaction failures.\n", TM_RETRIES); 74 + printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n", 75 + __builtin_get_texasr(), __builtin_get_tfiar()); 76 + 77 + exit(-1); 78 + } 79 + 80 + int tm_syscall(void) 81 + { 82 + unsigned count = 0; 83 + struct timeval end, now; 84 + 85 + SKIP_IF(!((long)get_auxv_entry(AT_HWCAP2) & PPC_FEATURE2_HTM)); 86 + setbuf(stdout, NULL); 87 + 88 + printf("Testing transactional syscalls for %d seconds...\n", TEST_DURATION); 89 + 90 + gettimeofday(&end, NULL); 91 + now.tv_sec = TEST_DURATION; 92 + now.tv_usec = 0; 93 + timeradd(&end, &now, &end); 94 + 95 + for (count = 0; timercmp(&now, &end, <); count++) { 96 + /* 97 + * Test a syscall within a suspended transaction and verify 98 + * that it succeeds. 99 + */ 100 + FAIL_IF(getppid_tm(true) == -1); /* Should succeed. */ 101 + 102 + /* 103 + * Test a syscall within an active transaction and verify that 104 + * it fails with the correct failure code. 105 + */ 106 + FAIL_IF(getppid_tm(false) != -1); /* Should fail... */ 107 + FAIL_IF(!failure_is_persistent()); /* ...persistently... */ 108 + FAIL_IF(!failure_is_syscall()); /* ...with code syscall. */ 109 + gettimeofday(&now, 0); 110 + } 111 + 112 + printf("%d active and suspended transactions behaved correctly.\n", count); 113 + printf("(There were %d transaction retries.)\n", retries); 114 + 115 + return 0; 116 + } 117 + 118 + int main(void) 119 + { 120 + return test_harness(tm_syscall, "tm_syscall"); 121 + }