Message ID | 1462907128-7954-1-git-send-email-tim.gardner@canonical.com |
---|---|
State | New |
Headers | show |
On Tue, May 10, 2016 at 01:05:28PM -0600, Tim Gardner wrote: > From: Sam bobroff <sam.bobroff@au1.ibm.com> > > BugLink: http://bugs.launchpad.net/bugs/1572624 > > This patch changes the syscall handler to doom (tabort) active > transactions when a syscall is made and return very early without > performing the syscall and keeping side effects to a minimum (no CPU > accounting or system call tracing is performed). Also included is a > new HWCAP2 bit, PPC_FEATURE2_HTM_NOSC, to indicate this > behaviour to userspace. > > Currently, the system call instruction automatically suspends an > active transaction which causes side effects to persist when an active > transaction fails. > > This does change the kernel's behaviour, but in a way that was > documented as unsupported. It doesn't reduce functionality as > syscalls will still be performed after tsuspend; it just requires that > the transaction be explicitly suspended. It also provides a > consistent interface and makes the behaviour of user code > substantially the same across powerpc and platforms that do not > support suspended transactions (e.g. x86 and s390). > > Performance measurements using > http://ozlabs.org/~anton/junkcode/null_syscall.c indicate the cost of > a normal (non-aborted) system call increases by about 0.25%. > > Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com> > Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> > > This patch backport b4b56f9ecab40f3b to Ubuntu 14.04.04. > > quoted from original commit: > It is about changing the syscall handler to doom (tabort) active > transactions when a syscall is made and return very early without > performing the syscall and keeping side effects to a minimum (no CPU > accounting or system call tracing is performed). Also included is a > new HWCAP2 bit, PPC_FEATURE2_HTM_NOSC, to indicate this > behaviour to userspace. > > Without this backport patch, app running TM testing on Ubuntu 14.04 > might hang. Glibc with TLE enabled will be able to bypass this issue. > However it is not enabled on Ubunt 14.04. > > The issue to be addressed: > User is creating stack structure using C++ transactional memory > extension: > > int Pop(int) > { > int ret = 0; > __transaction_atomic > { > if(!stack_.empty()) > { > ret = stack_.top(); > stack_.pop(); > } else > ret = -1; > } > return ret; > } > > While evaluating if(!stack_.empty()), this code calls a libitm function > (GCC code), which calls malloc (glibc code) which ends up calling futex > (a syscall). > A syscall inside a transaction is forbidden by the kernel, but there is > nothing the user can do to avoid this syscall. > > This will hang the user application inside the malloc(), which would be > waiting for the futex to return. > > Ubuntu 14.04 provides glibc 2.19, which is too old to know about HTM. > And this is probably happening with other libraries as well. > > Signed-off-by: Simon Guo <simonguo@linux.vnet.ibm.com> > Signed-off-by: Tim Gardner <tim.gardner@canonical.com> > --- > > v2 - restored original author and commit log. I left in Simon's backporting > notes. > > Documentation/powerpc/transactional_memory.txt | 32 +++++++++++------------ > arch/powerpc/include/asm/cputable.h | 10 +++++--- > arch/powerpc/include/uapi/asm/cputable.h | 1 + > arch/powerpc/include/uapi/asm/tm.h | 2 +- > arch/powerpc/kernel/cputable.c | 4 ++- > arch/powerpc/kernel/entry_64.S | 35 ++++++++++++++++++++++++++ > 6 files changed, 62 insertions(+), 22 deletions(-) > > diff --git a/Documentation/powerpc/transactional_memory.txt b/Documentation/powerpc/transactional_memory.txt > index 9791e98..98b39af 100644 > --- a/Documentation/powerpc/transactional_memory.txt > +++ b/Documentation/powerpc/transactional_memory.txt > @@ -74,22 +74,23 @@ Causes of transaction aborts > Syscalls > ======== > > -Performing syscalls from within transaction is not recommended, and can lead > -to unpredictable results. > +Syscalls made from within an active transaction will not be performed and the > +transaction will be doomed by the kernel with the failure code TM_CAUSE_SYSCALL > +| TM_CAUSE_PERSISTENT. > > -Syscalls do not by design abort transactions, but beware: The kernel code will > -not be running in transactional state. The effect of syscalls will always > -remain visible, but depending on the call they may abort your transaction as a > -side-effect, read soon-to-be-aborted transactional data that should not remain > -invisible, etc. If you constantly retry a transaction that constantly aborts > -itself by calling a syscall, you'll have a livelock & make no progress. > +Syscalls made from within a suspended transaction are performed as normal and > +the transaction is not explicitly doomed by the kernel. However, what the > +kernel does to perform the syscall may result in the transaction being doomed > +by the hardware. The syscall is performed in suspended mode so any side > +effects will be persistent, independent of transaction success or failure. No > +guarantees are provided by the kernel about which syscalls will affect > +transaction success. > > -Simple syscalls (e.g. sigprocmask()) "could" be OK. Even things like write() > -from, say, printf() should be OK as long as the kernel does not access any > -memory that was accessed transactionally. > - > -Consider any syscalls that happen to work as debug-only -- not recommended for > -production use. Best to queue them up till after the transaction is over. > +Care must be taken when relying on syscalls to abort during active transactions > +if the calls are made via a library. Libraries may cache values (which may > +give the appearance of success) or perform operations that cause transaction > +failure before entering the kernel (which may produce different failure codes). > +Examples are glibc's getpid() and lazy symbol resolution. > > > Signals > @@ -176,8 +177,7 @@ kernel aborted a transaction: > TM_CAUSE_RESCHED Thread was rescheduled. > TM_CAUSE_TLBI Software TLB invalide. > TM_CAUSE_FAC_UNAV FP/VEC/VSX unavailable trap. > - TM_CAUSE_SYSCALL Currently unused; future syscalls that must abort > - transactions for consistency will use this. > + TM_CAUSE_SYSCALL Syscall from active transaction. > TM_CAUSE_SIGNAL Signal delivered. > TM_CAUSE_MISC Currently unused. > TM_CAUSE_ALIGNMENT Alignment fault. > diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h > index 22d5a7d..4ec19da 100644 > --- a/arch/powerpc/include/asm/cputable.h > +++ b/arch/powerpc/include/asm/cputable.h > @@ -236,11 +236,13 @@ extern const char *powerpc_base_platform; > > /* We only set the TM feature if the kernel was compiled with TM supprt */ > #ifdef CONFIG_PPC_TRANSACTIONAL_MEM > -#define CPU_FTR_TM_COMP CPU_FTR_TM > -#define PPC_FEATURE2_HTM_COMP PPC_FEATURE2_HTM > +#define CPU_FTR_TM_COMP CPU_FTR_TM > +#define PPC_FEATURE2_HTM_COMP PPC_FEATURE2_HTM > +#define PPC_FEATURE2_HTM_NOSC_COMP PPC_FEATURE2_HTM_NOSC > #else > -#define CPU_FTR_TM_COMP 0 > -#define PPC_FEATURE2_HTM_COMP 0 > +#define CPU_FTR_TM_COMP 0 > +#define PPC_FEATURE2_HTM_COMP 0 > +#define PPC_FEATURE2_HTM_NOSC_COMP 0 > #endif > > /* We need to mark all pages as being coherent if we're SMP or we have a > diff --git a/arch/powerpc/include/uapi/asm/cputable.h b/arch/powerpc/include/uapi/asm/cputable.h > index 67de80a..2734c00 100644 > --- a/arch/powerpc/include/uapi/asm/cputable.h > +++ b/arch/powerpc/include/uapi/asm/cputable.h > @@ -43,5 +43,6 @@ > #define PPC_FEATURE2_ISEL 0x08000000 > #define PPC_FEATURE2_TAR 0x04000000 > #define PPC_FEATURE2_VEC_CRYPTO 0x02000000 > +#define PPC_FEATURE2_HTM_NOSC 0x01000000 > > #endif /* _UAPI__ASM_POWERPC_CPUTABLE_H */ > diff --git a/arch/powerpc/include/uapi/asm/tm.h b/arch/powerpc/include/uapi/asm/tm.h > index 5d836b7..5047659 100644 > --- a/arch/powerpc/include/uapi/asm/tm.h > +++ b/arch/powerpc/include/uapi/asm/tm.h > @@ -11,7 +11,7 @@ > #define TM_CAUSE_RESCHED 0xde > #define TM_CAUSE_TLBI 0xdc > #define TM_CAUSE_FAC_UNAV 0xda > -#define TM_CAUSE_SYSCALL 0xd8 /* future use */ > +#define TM_CAUSE_SYSCALL 0xd8 > #define TM_CAUSE_MISC 0xd6 /* future use */ > #define TM_CAUSE_SIGNAL 0xd4 > #define TM_CAUSE_ALIGNMENT 0xd2 > diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c > index c18a2ea..bf3eb39 100644 > --- a/arch/powerpc/kernel/cputable.c > +++ b/arch/powerpc/kernel/cputable.c > @@ -108,7 +108,9 @@ extern void __restore_cpu_e6500(void); > PPC_FEATURE_TRUE_LE | \ > PPC_FEATURE_PSERIES_PERFMON_COMPAT) > #define COMMON_USER2_POWER8 (PPC_FEATURE2_ARCH_2_07 | \ > - PPC_FEATURE2_HTM_COMP | PPC_FEATURE2_DSCR | \ > + PPC_FEATURE2_HTM_COMP | \ > + PPC_FEATURE2_HTM_NOSC_COMP | \ > + PPC_FEATURE2_DSCR | \ > PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR | \ > PPC_FEATURE2_VEC_CRYPTO) > #define COMMON_USER_PA6T (COMMON_USER_PPC64 | PPC_FEATURE_PA6T |\ > diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S > index 1d8b58a..0dce87f 100644 > --- a/arch/powerpc/kernel/entry_64.S > +++ b/arch/powerpc/kernel/entry_64.S > @@ -34,6 +34,7 @@ > #include <asm/ftrace.h> > #include <asm/hw_irq.h> > #include <asm/context_tracking.h> > +#include <asm/tm.h> > > /* > * System calls. > @@ -51,6 +52,12 @@ exception_marker: > > .globl system_call_common > system_call_common: > +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM > +BEGIN_FTR_SECTION > + extrdi. r10, r12, 1, (63-MSR_TS_T_LG) /* transaction active? */ > + bne tabort_syscall > +END_FTR_SECTION_IFSET(CPU_FTR_TM) > +#endif > andi. r10,r12,MSR_PR > mr r10,r1 > addi r1,r1,-INT_FRAME_SIZE > @@ -311,6 +318,34 @@ syscall_exit_work: > bl do_syscall_trace_leave > b ret_from_except > > +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM > +tabort_syscall: > + /* Firstly we need to enable TM in the kernel */ > + mfmsr r10 > + li r13, 1 > + rldimi r10, r13, MSR_TM_LG, 63-MSR_TM_LG > + mtmsrd r10, 0 > + > + /* tabort, this dooms the transaction, nothing else */ > + li r13, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT) > + TABORT(R13) > + > + /* > + * Return directly to userspace. We have corrupted user register state, > + * but userspace will never see that register state. Execution will > + * resume after the tbegin of the aborted transaction with the > + * checkpointed register state. > + */ > + li r13, MSR_RI > + andc r10, r10, r13 > + mtmsrd r10, 1 > + mtspr SPRN_SRR0, r11 > + mtspr SPRN_SRR1, r12 > + > + rfid > + b . /* prevent speculative execution */ > +#endif > + > /* Save non-volatile GPRs, if not already saved. */ > _GLOBAL(save_nvgprs) > ld r11,_TRAP(r1) > -- > 1.9.1 > > > -- > kernel-team mailing list > kernel-team@lists.ubuntu.com > https://lists.ubuntu.com/mailman/listinfo/kernel-team Looks fine to me.
diff --git a/Documentation/powerpc/transactional_memory.txt b/Documentation/powerpc/transactional_memory.txt index 9791e98..98b39af 100644 --- a/Documentation/powerpc/transactional_memory.txt +++ b/Documentation/powerpc/transactional_memory.txt @@ -74,22 +74,23 @@ Causes of transaction aborts Syscalls ======== -Performing syscalls from within transaction is not recommended, and can lead -to unpredictable results. +Syscalls made from within an active transaction will not be performed and the +transaction will be doomed by the kernel with the failure code TM_CAUSE_SYSCALL +| TM_CAUSE_PERSISTENT. -Syscalls do not by design abort transactions, but beware: The kernel code will -not be running in transactional state. The effect of syscalls will always -remain visible, but depending on the call they may abort your transaction as a -side-effect, read soon-to-be-aborted transactional data that should not remain -invisible, etc. If you constantly retry a transaction that constantly aborts -itself by calling a syscall, you'll have a livelock & make no progress. +Syscalls made from within a suspended transaction are performed as normal and +the transaction is not explicitly doomed by the kernel. However, what the +kernel does to perform the syscall may result in the transaction being doomed +by the hardware. The syscall is performed in suspended mode so any side +effects will be persistent, independent of transaction success or failure. No +guarantees are provided by the kernel about which syscalls will affect +transaction success. -Simple syscalls (e.g. sigprocmask()) "could" be OK. Even things like write() -from, say, printf() should be OK as long as the kernel does not access any -memory that was accessed transactionally. - -Consider any syscalls that happen to work as debug-only -- not recommended for -production use. Best to queue them up till after the transaction is over. +Care must be taken when relying on syscalls to abort during active transactions +if the calls are made via a library. Libraries may cache values (which may +give the appearance of success) or perform operations that cause transaction +failure before entering the kernel (which may produce different failure codes). +Examples are glibc's getpid() and lazy symbol resolution. Signals @@ -176,8 +177,7 @@ kernel aborted a transaction: TM_CAUSE_RESCHED Thread was rescheduled. TM_CAUSE_TLBI Software TLB invalide. TM_CAUSE_FAC_UNAV FP/VEC/VSX unavailable trap. - TM_CAUSE_SYSCALL Currently unused; future syscalls that must abort - transactions for consistency will use this. + TM_CAUSE_SYSCALL Syscall from active transaction. TM_CAUSE_SIGNAL Signal delivered. TM_CAUSE_MISC Currently unused. TM_CAUSE_ALIGNMENT Alignment fault. diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 22d5a7d..4ec19da 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -236,11 +236,13 @@ extern const char *powerpc_base_platform; /* We only set the TM feature if the kernel was compiled with TM supprt */ #ifdef CONFIG_PPC_TRANSACTIONAL_MEM -#define CPU_FTR_TM_COMP CPU_FTR_TM -#define PPC_FEATURE2_HTM_COMP PPC_FEATURE2_HTM +#define CPU_FTR_TM_COMP CPU_FTR_TM +#define PPC_FEATURE2_HTM_COMP PPC_FEATURE2_HTM +#define PPC_FEATURE2_HTM_NOSC_COMP PPC_FEATURE2_HTM_NOSC #else -#define CPU_FTR_TM_COMP 0 -#define PPC_FEATURE2_HTM_COMP 0 +#define CPU_FTR_TM_COMP 0 +#define PPC_FEATURE2_HTM_COMP 0 +#define PPC_FEATURE2_HTM_NOSC_COMP 0 #endif /* We need to mark all pages as being coherent if we're SMP or we have a diff --git a/arch/powerpc/include/uapi/asm/cputable.h b/arch/powerpc/include/uapi/asm/cputable.h index 67de80a..2734c00 100644 --- a/arch/powerpc/include/uapi/asm/cputable.h +++ b/arch/powerpc/include/uapi/asm/cputable.h @@ -43,5 +43,6 @@ #define PPC_FEATURE2_ISEL 0x08000000 #define PPC_FEATURE2_TAR 0x04000000 #define PPC_FEATURE2_VEC_CRYPTO 0x02000000 +#define PPC_FEATURE2_HTM_NOSC 0x01000000 #endif /* _UAPI__ASM_POWERPC_CPUTABLE_H */ diff --git a/arch/powerpc/include/uapi/asm/tm.h b/arch/powerpc/include/uapi/asm/tm.h index 5d836b7..5047659 100644 --- a/arch/powerpc/include/uapi/asm/tm.h +++ b/arch/powerpc/include/uapi/asm/tm.h @@ -11,7 +11,7 @@ #define TM_CAUSE_RESCHED 0xde #define TM_CAUSE_TLBI 0xdc #define TM_CAUSE_FAC_UNAV 0xda -#define TM_CAUSE_SYSCALL 0xd8 /* future use */ +#define TM_CAUSE_SYSCALL 0xd8 #define TM_CAUSE_MISC 0xd6 /* future use */ #define TM_CAUSE_SIGNAL 0xd4 #define TM_CAUSE_ALIGNMENT 0xd2 diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index c18a2ea..bf3eb39 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -108,7 +108,9 @@ extern void __restore_cpu_e6500(void); PPC_FEATURE_TRUE_LE | \ PPC_FEATURE_PSERIES_PERFMON_COMPAT) #define COMMON_USER2_POWER8 (PPC_FEATURE2_ARCH_2_07 | \ - PPC_FEATURE2_HTM_COMP | PPC_FEATURE2_DSCR | \ + PPC_FEATURE2_HTM_COMP | \ + PPC_FEATURE2_HTM_NOSC_COMP | \ + PPC_FEATURE2_DSCR | \ PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR | \ PPC_FEATURE2_VEC_CRYPTO) #define COMMON_USER_PA6T (COMMON_USER_PPC64 | PPC_FEATURE_PA6T |\ diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 1d8b58a..0dce87f 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -34,6 +34,7 @@ #include <asm/ftrace.h> #include <asm/hw_irq.h> #include <asm/context_tracking.h> +#include <asm/tm.h> /* * System calls. @@ -51,6 +52,12 @@ exception_marker: .globl system_call_common system_call_common: +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +BEGIN_FTR_SECTION + extrdi. r10, r12, 1, (63-MSR_TS_T_LG) /* transaction active? */ + bne tabort_syscall +END_FTR_SECTION_IFSET(CPU_FTR_TM) +#endif andi. r10,r12,MSR_PR mr r10,r1 addi r1,r1,-INT_FRAME_SIZE @@ -311,6 +318,34 @@ syscall_exit_work: bl do_syscall_trace_leave b ret_from_except +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +tabort_syscall: + /* Firstly we need to enable TM in the kernel */ + mfmsr r10 + li r13, 1 + rldimi r10, r13, MSR_TM_LG, 63-MSR_TM_LG + mtmsrd r10, 0 + + /* tabort, this dooms the transaction, nothing else */ + li r13, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT) + TABORT(R13) + + /* + * Return directly to userspace. We have corrupted user register state, + * but userspace will never see that register state. Execution will + * resume after the tbegin of the aborted transaction with the + * checkpointed register state. + */ + li r13, MSR_RI + andc r10, r10, r13 + mtmsrd r10, 1 + mtspr SPRN_SRR0, r11 + mtspr SPRN_SRR1, r12 + + rfid + b . /* prevent speculative execution */ +#endif + /* Save non-volatile GPRs, if not already saved. */ _GLOBAL(save_nvgprs) ld r11,_TRAP(r1)