Skip to contentSkip to conversation

x86 fixes

GIT PULL In review Ingo Molnar 3 participants 9 messages Jul 18, 2015 – Jul 20, 2015

Subsystems (8)
x86 MM core Scheduler s390 +4 more subsystems
lore
Share & tools
lore
#0 lore raw

Linus,

Please pull the latest x86-urgent-for-linus git tree from:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86-urgent-for-linus

# HEAD: 5aaeb5c01c5b6c0be7b7aadbf3ace9f3a4458c3d x86/fpu, sched: Introduce CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT and use it on x86

Two families of fixes:

- Fix an FPU context related boot crash on newer x86 hardware with larger

    context sizes than what most people test. To fix this without ugly kludges or 
    extensive reverts we had to touch core task allocator, to allow x86 to 
    determine the task size dynamically, at boot time.

    I've tested it on a number of x86 platforms, and I cross-built it to a handful 
    of architectures:

	                                 (warns)               (warns)
	testing     x86-64:  -git:  pass (    0),  -tip:  pass (    0)
	testing     x86-32:  -git:  pass (    0),  -tip:  pass (    0)
	testing        arm:  -git:  pass ( 1359),  -tip:  pass ( 1359)
	testing       cris:  -git:  pass ( 1031),  -tip:  pass ( 1031)
	testing       m32r:  -git:  pass ( 1135),  -tip:  pass ( 1135)
	testing       m68k:  -git:  pass ( 1471),  -tip:  pass ( 1471)
	testing       mips:  -git:  pass ( 1162),  -tip:  pass ( 1162)
	testing    mn10300:  -git:  pass ( 1058),  -tip:  pass ( 1058)
	testing     parisc:  -git:  pass ( 1846),  -tip:  pass ( 1846)
	testing      sparc:  -git:  pass ( 1185),  -tip:  pass ( 1185)

     ... so I hope the cross-arch impact 'none', as intended.

    (by Dave Hansen)

- Fix various NMI handling related bugs unearthed by the big asm code rewrite and generally make the NMI code more robust and more maintainable while at it. These changes are a bit late in the cycle, I hope they are still acceptable.

(by Andy Lutomirski)

out-of-topic modifications in x86-urgent-for-linus:
-----------------------------------------------------

  arch/Kconfig                       # 5aaeb5c01c5b: x86/fpu, sched: Introduce CO
  fs/proc/kcore.c                    # 5aaeb5c01c5b: x86/fpu, sched: Introduce CO
  kernel/fork.c                      # 0c8c0f03e3a2: x86/fpu, sched: Dynamically 

Thanks,

Ingo

------------------>
Andy Lutomirski (9):
x86/nmi: Enable nested do_nmi() handling for 64-bit kernels x86/nmi/64: Remove asm code that saves CR2
x86/nmi/64: Switch stacks on userspace NMI entry x86/nmi/64: Improve nested NMI comments
x86/nmi/64: Reorder nested NMI checks
x86/nmi/64: Use DF to avoid userspace RSP confusing nested NMI detection x86/nmi/64: Minor asm simplification
x86/nmi/64: Make the "NMI executing" variable more consistent x86/entry/64, x86/nmi/64: Add CONFIG_DEBUG_ENTRY NMI testing code

Dave Hansen (1):
x86/fpu, sched: Dynamically allocate 'struct fpu'

Ingo Molnar (1):
x86/fpu, sched: Introduce CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT and use it on x86

 arch/Kconfig                     |   4 +
 arch/x86/Kconfig                 |   1 +
 arch/x86/Kconfig.debug           |  12 ++
 arch/x86/entry/entry_64.S        | 299 ++++++++++++++++++++++++++-------------
 arch/x86/include/asm/fpu/types.h |  72 +++++-----
 arch/x86/include/asm/processor.h |  10 +-
 arch/x86/kernel/fpu/init.c       |  40 ++++++
 arch/x86/kernel/nmi.c            | 123 +++++++---------
 arch/x86/kernel/process.c        |   2 +-
 fs/proc/kcore.c                  |   4 +-
 include/linux/sched.h            |  16 ++-
 kernel/fork.c                    |   7 +-
 12 files changed, 376 insertions(+), 214 deletions(-)
arch/Kconfig +4 -0
index bec6666a3cc4..8a8ea7110de8 100644
@@ -221,6 +221,10 @@ config ARCH_TASK_STRUCT_ALLOCATOR
 config ARCH_THREAD_INFO_ALLOCATOR
 	bool
 
+# Select if arch wants to size task_struct dynamically via arch_task_struct_size:
+config ARCH_WANTS_DYNAMIC_TASK_STRUCT
+	bool
+
 config HAVE_REGS_AND_STACK_ACCESS_API
 	bool
 	help
arch/x86/Kconfig +1 -0
index 3dbb7e7909ca..b3a1a5d77d92 100644
@@ -41,6 +41,7 @@ config X86
 	select ARCH_USE_CMPXCHG_LOCKREF		if X86_64
 	select ARCH_USE_QUEUED_RWLOCKS
 	select ARCH_USE_QUEUED_SPINLOCKS
+	select ARCH_WANTS_DYNAMIC_TASK_STRUCT
 	select ARCH_WANT_FRAME_POINTERS
 	select ARCH_WANT_IPC_PARSE_VERSION	if X86_32
 	select ARCH_WANT_OPTIONAL_GPIOLIB
arch/x86/Kconfig.debug +12 -0
index a15893d17c55..d8c0d3266173 100644
@@ -297,6 +297,18 @@ config OPTIMIZE_INLINING
 
 	  If unsure, say N.
 
+config DEBUG_ENTRY
+	bool "Debug low-level entry code"
+	depends on DEBUG_KERNEL
+	---help---
+	  This option enables sanity checks in x86's low-level entry code.
+	  Some of these sanity checks may slow down kernel entries and
+	  exits or otherwise impact performance.
+
+	  This is currently used to help test NMI code.
+
+	  If unsure, say N.
+
 config DEBUG_NMI_SELFTEST
 	bool "NMI Selftest"
 	depends on DEBUG_KERNEL && X86_LOCAL_APIC
arch/x86/entry/entry_64.S +199 -100

391 lines not on this page · raw message

arch/x86/include/asm/fpu/types.h +38 -34

90 lines not on this page · raw message

arch/x86/include/asm/processor.h +7 -3
index 43e6519df0d5..944f1785ed0d 100644
@@ -390,9 +390,6 @@ struct thread_struct {
 #endif
 	unsigned long		gs;
 
-	/* Floating point and extended processor state */
-	struct fpu		fpu;
-
 	/* Save middle states of ptrace breakpoints */
 	struct perf_event	*ptrace_bps[HBP_NUM];
 	/* Debug status used for traps, single steps, etc... */
@@ -418,6 +415,13 @@ struct thread_struct {
 	unsigned long		iopl;
 	/* Max allowed port in the bitmap, in bytes: */
 	unsigned		io_bitmap_max;
+
+	/* Floating point and extended processor state */
+	struct fpu		fpu;
+	/*
+	 * WARNING: 'fpu' is dynamically-sized.  It *MUST* be at
+	 * the end.
+	 */
 };
 
 /*
arch/x86/kernel/fpu/init.c +40 -0
index 32826791e675..0b39173dd971 100644
@@ -4,6 +4,8 @@
 #include <asm/fpu/internal.h>
 #include <asm/tlbflush.h>
 
+#include <linux/sched.h>
+
 /*
  * Initialize the TS bit in CR0 according to the style of context-switches
  * we are using:
@@ -136,6 +138,43 @@ static void __init fpu__init_system_generic(void)
 unsigned int xstate_size;
 EXPORT_SYMBOL_GPL(xstate_size);
 
+/* Enforce that 'MEMBER' is the last field of 'TYPE': */
+#define CHECK_MEMBER_AT_END_OF(TYPE, MEMBER) \
+	BUILD_BUG_ON(sizeof(TYPE) != offsetofend(TYPE, MEMBER))
+
+/*
+ * We append the 'struct fpu' to the task_struct:
+ */
+static void __init fpu__init_task_struct_size(void)
+{
+	int task_size = sizeof(struct task_struct);
+
+	/*
+	 * Subtract off the static size of the register state.
+	 * It potentially has a bunch of padding.
+	 */
+	task_size -= sizeof(((struct task_struct *)0)->thread.fpu.state);
+
+	/*
+	 * Add back the dynamically-calculated register state
+	 * size.
+	 */
+	task_size += xstate_size;
+
+	/*
+	 * We dynamically size 'struct fpu', so we require that
+	 * it be at the end of 'thread_struct' and that
+	 * 'thread_struct' be at the end of 'task_struct'.  If
+	 * you hit a compile error here, check the structure to
+	 * see if something got added to the end.
+	 */
+	CHECK_MEMBER_AT_END_OF(struct fpu, state);
+	CHECK_MEMBER_AT_END_OF(struct thread_struct, fpu);
+	CHECK_MEMBER_AT_END_OF(struct task_struct, thread);
+
+	arch_task_struct_size = task_size;
+}
+
 /*
  * Set up the xstate_size based on the legacy FPU context size.
  *
@@ -287,6 +326,7 @@ void __init fpu__init_system(struct cpuinfo_x86 *c)
 	fpu__init_system_generic();
 	fpu__init_system_xstate_size_legacy();
 	fpu__init_system_xstate();
+	fpu__init_task_struct_size();
 
 	fpu__init_system_ctx_switch();
 }
arch/x86/kernel/nmi.c +52 -71

161 lines not on this page · raw message

arch/x86/kernel/process.c +1 -1
index 9cad694ed7c4..397688beed4b 100644
@@ -81,7 +81,7 @@ EXPORT_SYMBOL_GPL(idle_notifier_unregister);
  */
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
-	*dst = *src;
+	memcpy(dst, src, arch_task_struct_size);
 
 	return fpu__copy(&dst->thread.fpu, &src->thread.fpu);
 }
fs/proc/kcore.c +2 -2
index 91a4e6426321..92e6726f6e37 100644
@@ -92,7 +92,7 @@ static size_t get_kcore_size(int *nphdr, size_t *elf_buflen)
 			     roundup(sizeof(CORE_STR), 4)) +
 			roundup(sizeof(struct elf_prstatus), 4) +
 			roundup(sizeof(struct elf_prpsinfo), 4) +
-			roundup(sizeof(struct task_struct), 4);
+			roundup(arch_task_struct_size, 4);
 	*elf_buflen = PAGE_ALIGN(*elf_buflen);
 	return size + *elf_buflen;
 }
@@ -415,7 +415,7 @@ static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff)
 	/* set up the task structure */
 	notes[2].name	= CORE_STR;
 	notes[2].type	= NT_TASKSTRUCT;
-	notes[2].datasz	= sizeof(struct task_struct);
+	notes[2].datasz	= arch_task_struct_size;
 	notes[2].data	= current;
 
 	nhdr->p_filesz	+= notesize(&notes[2]);
include/linux/sched.h +14 -2
index ae21f1591615..04b5ada460b4 100644
@@ -1522,8 +1522,6 @@ struct task_struct {
 /* hung task detection */
 	unsigned long last_switch_count;
 #endif
-/* CPU-specific state of this task */
-	struct thread_struct thread;
 /* filesystem information */
 	struct fs_struct *fs;
 /* open file information */
@@ -1778,8 +1776,22 @@ struct task_struct {
 	unsigned long	task_state_change;
 #endif
 	int pagefault_disabled;
+/* CPU-specific state of this task */
+	struct thread_struct thread;
+/*
+ * WARNING: on x86, 'thread_struct' contains a variable-sized
+ * structure.  It *MUST* be at the end of 'task_struct'.
+ *
+ * Do not put anything below here!
+ */
 };
 
+#ifdef CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT
+extern int arch_task_struct_size __read_mostly;
+#else
+# define arch_task_struct_size (sizeof(struct task_struct))
+#endif
+
 /* Future-safe accessor for struct task_struct's cpus_allowed. */
 #define tsk_cpus_allowed(tsk) (&(tsk)->cpus_allowed)
 
kernel/fork.c +6 -1
index 1bfefc6f96a4..dbd9b8d7b7cc 100644
@@ -287,6 +287,11 @@ static void set_max_threads(unsigned int max_threads_suggested)
 	max_threads = clamp_t(u64, threads, MIN_THREADS, MAX_THREADS);
 }
 
+#ifdef CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT
+/* Initialized by the architecture: */
+int arch_task_struct_size __read_mostly;
+#endif
+
 void __init fork_init(void)
 {
 #ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR
@@ -295,7 +300,7 @@ void __init fork_init(void)
 #endif
 	/* create a slab on which task_structs can be allocated */
 	task_struct_cachep =
-		kmem_cache_create("task_struct", sizeof(struct task_struct),
+		kmem_cache_create("task_struct", arch_task_struct_size,
 			ARCH_MIN_TASKALIGN, SLAB_PANIC | SLAB_NOTRACK, NULL);
 #endif
 
#1 lore raw
Quoted 25 lines · Ingo Molnar

Linus,

Please pull the latest x86-urgent-for-linus git tree from:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86-urgent-for-linus

# HEAD: 5aaeb5c01c5b6c0be7b7aadbf3ace9f3a4458c3d x86/fpu, sched: Introduce CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT and use it on x86

Two families of fixes:

- Fix an FPU context related boot crash on newer x86 hardware with larger

    context sizes than what most people test. To fix this without ugly kludges or 
    extensive reverts we had to touch core task allocator, to allow x86 to 
    determine the task size dynamically, at boot time.

    I've tested it on a number of x86 platforms, and I cross-built it to a handful 
    of architectures:

	                                 (warns)               (warns)
	testing     x86-64:  -git:  pass (    0),  -tip:  pass (    0)
	testing     x86-32:  -git:  pass (    0),  -tip:  pass (    0)
	testing        arm:  -git:  pass ( 1359),  -tip:  pass ( 1359)
	testing       cris:  -git:  pass ( 1031),  -tip:  pass ( 1031)
	testing       m32r:  -git:  pass ( 1135),  -tip:  pass ( 1135)
	testing       m68k:  -git:  pass ( 1471),  -tip:  pass ( 1471)
Quoted 8 lines
	testing       mips:  -git:  pass ( 1162),  -tip:  pass ( 1162)
	testing    mn10300:  -git:  pass ( 1058),  -tip:  pass ( 1058)
	testing     parisc:  -git:  pass ( 1846),  -tip:  pass ( 1846)
	testing      sparc:  -git:  pass ( 1185),  -tip:  pass ( 1185)

     ... so I hope the cross-arch impact 'none', as intended.

    (by Dave Hansen)

Unfortunately not true. It breaks the build on s390 since a couple of displacements used in asm code now get too large:

arch/s390/kernel/entry.S:181: Error: operand out of range (0x00000000000018a8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:191: Error: operand out of range (0x00000000000018a8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:423: Error: operand out of range (0x0000000000001924 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:437: Error: operand out of range (0x00000000000018e8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:438: Error: operand out of range (0x00000000000018e0 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:439: Error: operand out of range (0x00000000000018f0 is not between 0x0000000000000000 and 0x0000000000000fff) make[1]: *** [arch/s390/kernel/entry.o] Error 1

Let's see how we can fix this.

#2 lore raw

PATCH 1/1 sched, s390: Fix the fallout of increasing the offset of 'thread_struct' within 'task_struct'

Quoted 30 lines · Heiko Carstens
Quoted 10 lines
    I've tested it on a number of x86 platforms, and I cross-built it to a handful 
    of architectures:

	                                 (warns)               (warns)
	testing     x86-64:  -git:  pass (    0),  -tip:  pass (    0)
	testing     x86-32:  -git:  pass (    0),  -tip:  pass (    0)
	testing        arm:  -git:  pass ( 1359),  -tip:  pass ( 1359)
	testing       cris:  -git:  pass ( 1031),  -tip:  pass ( 1031)
	testing       m32r:  -git:  pass ( 1135),  -tip:  pass ( 1135)
	testing       m68k:  -git:  pass ( 1471),  -tip:  pass ( 1471)
Quoted 8 lines
	testing       mips:  -git:  pass ( 1162),  -tip:  pass ( 1162)
	testing    mn10300:  -git:  pass ( 1058),  -tip:  pass ( 1058)
	testing     parisc:  -git:  pass ( 1846),  -tip:  pass ( 1846)
	testing      sparc:  -git:  pass ( 1185),  -tip:  pass ( 1185)

     ... so I hope the cross-arch impact 'none', as intended.

    (by Dave Hansen)

Unfortunately not true. It breaks the build on s390 since a couple of displacements used in asm code now get too large:

arch/s390/kernel/entry.S:181: Error: operand out of range (0x00000000000018a8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:191: Error: operand out of range (0x00000000000018a8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:423: Error: operand out of range (0x0000000000001924 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:437: Error: operand out of range (0x00000000000018e8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:438: Error: operand out of range (0x00000000000018e0 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:439: Error: operand out of range (0x00000000000018f0 is not between 0x0000000000000000 and 0x0000000000000fff) make[1]: *** [arch/s390/kernel/entry.o] Error 1

Quoted 1 line

Let's see how we can fix this.

There's also a traps.c build breakage reported below - and an RFC fix for it.

Thanks,

Ingo

=========================>

Quoted 10 lines · Guenter

Hi,

Commit 0c8c0f03e3a2 ("x86/fpu, sched: Dynamically allocate 'struct fpu'") causes s390 builds in mainline to fail as follows.

arch/s390/kernel/traps.c: Assembler messages:
arch/s390/kernel/traps.c:262: Error: operand out of range

	(0x00000000000023e8 is not between 0x0000000000000000 and 0x0000000000000fff)
arch/s390/kernel/traps.c:300: Error: operand out of range
	(0x00000000000023e8 is not between 0x0000000000000000 and 0x0000000000000fff)

Yeah, so I'm really out on a limb here as I know next to nothing about s390 assembly, but the build failure appears to be analogous to the arm64 one: the offset of thread_struct fields within task_struct increased due to commit 0c8c0f03e3a2 ("x86/fpu, sched: Dynamically allocate 'struct fpu'"), which increased assembly offsets beyond the limit this instruction can apparently encode.

Does the (untested!) patch below help?

It's an equivalent transformation on the C side, but it might cause GCC to generate different assembly code, because we now have a temporary variable with much smaller offsets.

The code is also a tiny bit cleaner this way, as the 'current->thread.fp_regs' pattern isn't repeated twice.

In case this works:

Thanks,

Ingo

================>

 arch/s390/kernel/traps.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
arch/s390/kernel/traps.c +4 -2
index 4d96c9f53455..db6f0eec55b5 100644
@@ -251,6 +251,7 @@ int alloc_vector_registers(struct task_struct *tsk)
 
 void vector_exception(struct pt_regs *regs)
 {
+	s390_fp_regs *fp_regs = &current->thread.fp_regs;
 	int si_code, vic;
 
 	if (!MACHINE_HAS_VX) {
@@ -259,8 +260,9 @@ void vector_exception(struct pt_regs *regs)
 	}
 
 	/* get vector interrupt code from fpc */
-	asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
-	vic = (current->thread.fp_regs.fpc & 0xf00) >> 8;
+	asm volatile("stfpc %0" : "=m" (fp_regs->fpc));
+	vic = (fp_regs->fpc & 0xf00) >> 8;
+
 	switch (vic) {
 	case 1: /* invalid vector operation */
 		si_code = FPE_FLTINV;
#3 lore raw

Re: [PATCH] sched, s390: Fix the fallout of increasing the offset of 'thread_struct' within 'task_struct'

Quoted 10 lines · On Mon, 20 Jul 2015 10:00:32 +0200 Ingo Molnar <[email protected]> wrote:
Quoted 8 lines · Heiko Carstens

arch/s390/kernel/entry.S:181: Error: operand out of range (0x00000000000018a8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:191: Error: operand out of range (0x00000000000018a8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:423: Error: operand out of range (0x0000000000001924 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:437: Error: operand out of range (0x00000000000018e8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:438: Error: operand out of range (0x00000000000018e0 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:439: Error: operand out of range (0x00000000000018f0 is not between 0x0000000000000000 and 0x0000000000000fff) make[1]: *** [arch/s390/kernel/entry.o] Error 1

Quoted 3 lines
Quoted 1 line

Let's see how we can fix this.

There's also a traps.c build breakage reported below - and an RFC fix for it.

This patch should fix it for good.
--

Quoted 1 line

From 54b3c4b85572bf5acc698cfca15d2c9cad446c44 Mon Sep 17 00:00:00 2001

From: Martin Schwidefsky <[email protected]>
Date: Mon, 20 Jul 2015 10:01:46 +0200
Subject: [PATCH] s390: adapt entry.S to the move of thread_struct

git commit 0c8c0f03e3a292e031596484275c14cf39c0ab7a "x86/fpu, sched: Dynamically allocate 'struct fpu'" moved the thread_struct to the end of the task_struct.

This causes some of the offsets used in entry.S to overflow their instruction operand field. To fix this use aghi to create a dedicated pointer for the thread_struct.

---
 arch/s390/kernel/asm-offsets.c | 15 +++++++--------
 arch/s390/kernel/entry.S       | 13 +++++++++----
 arch/s390/kernel/traps.c       |  4 ++--
 3 files changed, 18 insertions(+), 14 deletions(-)
arch/s390/kernel/asm-offsets.c +7 -8
index c7d1b9d..a2da259 100644
@@ -23,15 +23,15 @@
 
 int main(void)
 {
-	DEFINE(__THREAD_info, offsetof(struct task_struct, stack));
-	DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp));
-	DEFINE(__THREAD_mm_segment, offsetof(struct task_struct, thread.mm_segment));
-	BLANK();
+	DEFINE(__TASK_thread_info, offsetof(struct task_struct, stack));
+	DEFINE(__TASK_thread, offsetof(struct task_struct, thread));
 	DEFINE(__TASK_pid, offsetof(struct task_struct, pid));
 	BLANK();
-	DEFINE(__THREAD_per_cause, offsetof(struct task_struct, thread.per_event.cause));
-	DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address));
-	DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid));
+	DEFINE(__THREAD_ksp, offsetof(struct thread_struct, ksp));
+	DEFINE(__THREAD_per_cause, offsetof(struct thread_struct, per_event.cause));
+	DEFINE(__THREAD_per_address, offsetof(struct thread_struct, per_event.address));
+	DEFINE(__THREAD_per_paid, offsetof(struct thread_struct, per_event.paid));
+	DEFINE(__THREAD_trap_tdb, offsetof(struct thread_struct, trap_tdb));
 	BLANK();
 	DEFINE(__TI_task, offsetof(struct thread_info, task));
 	DEFINE(__TI_flags, offsetof(struct thread_info, flags));
@@ -176,7 +176,6 @@ int main(void)
 	DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data));
 	DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap));
 	DEFINE(__LC_PGM_TDB, offsetof(struct _lowcore, pgm_tdb));
-	DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));
 	DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce));
 	DEFINE(__SIE_PROG0C, offsetof(struct kvm_s390_sie_block, prog0c));
 	DEFINE(__SIE_PROG20, offsetof(struct kvm_s390_sie_block, prog20));
arch/s390/kernel/entry.S +9 -4
index 3238893..84062e7 100644
@@ -178,17 +178,21 @@ _PIF_WORK	= (_PIF_PER_TRAP)
  */
 ENTRY(__switch_to)
 	stmg	%r6,%r15,__SF_GPRS(%r15)	# store gprs of prev task
-	stg	%r15,__THREAD_ksp(%r2)		# store kernel stack of prev
-	lg	%r4,__THREAD_info(%r2)		# get thread_info of prev
-	lg	%r5,__THREAD_info(%r3)		# get thread_info of next
+	lgr	%r1,%r2
+	aghi	%r1,__TASK_thread		# thread_struct of prev task
+	lg	%r4,__TASK_thread_info(%r2)	# get thread_info of prev
+	lg	%r5,__TASK_thread_info(%r3)	# get thread_info of next
+	stg	%r15,__THREAD_ksp(%r1)		# store kernel stack of prev
+	lgr	%r1,%r3
+	aghi	%r1,__TASK_thread		# thread_struct of next task
 	lgr	%r15,%r5
 	aghi	%r15,STACK_INIT			# end of kernel stack of next
 	stg	%r3,__LC_CURRENT		# store task struct of next
 	stg	%r5,__LC_THREAD_INFO		# store thread info of next
 	stg	%r15,__LC_KERNEL_STACK		# store end of kernel stack
+	lg	%r15,__THREAD_ksp(%r1)		# load kernel stack of next
 	lctl	%c4,%c4,__TASK_pid(%r3)		# load pid to control reg. 4
 	mvc	__LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
-	lg	%r15,__THREAD_ksp(%r3)		# load kernel stack of next
 	lmg	%r6,%r15,__SF_GPRS(%r15)	# load gprs of next task
 	br	%r14
 
@@ -417,6 +421,7 @@ ENTRY(pgm_check_handler)
 	LAST_BREAK %r14
 	lg	%r15,__LC_KERNEL_STACK
 	lg	%r14,__TI_task(%r12)
+	aghi	%r14,__TASK_thread	# pointer to thread_struct
 	lghi	%r13,__LC_PGM_TDB
 	tm	__LC_PGM_ILC+2,0x02	# check for transaction abort
 	jz	2f
arch/s390/kernel/traps.c +2 -2
index 4d96c9f..7bea81d 100644
@@ -259,7 +259,7 @@ void vector_exception(struct pt_regs *regs)
 	}
 
 	/* get vector interrupt code from fpc */
-	asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
+	asm volatile("stfpc %0" : "=Q" (current->thread.fp_regs.fpc));
 	vic = (current->thread.fp_regs.fpc & 0xf00) >> 8;
 	switch (vic) {
 	case 1: /* invalid vector operation */
@@ -297,7 +297,7 @@ void data_exception(struct pt_regs *regs)
 
 	location = get_trap_ip(regs);
 
-	asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
+	asm volatile("stfpc %0" : "=Q" (current->thread.fp_regs.fpc));
 	/* Check for vector register enablement */
 	if (MACHINE_HAS_VX && !current->thread.vxrs &&
 	    (current->thread.fp_regs.fpc & FPC_DXC_MASK) == 0xfe00) {
Signature · 8 lines
2.3.8


-- 
blue skies,
   Martin.

"Reality continues to ruin my life." - Calvin.
#4 lore raw

Re: [PATCH] sched, s390: Fix the fallout of increasing the offset of 'thread_struct' within 'task_struct'

Quoted 19 lines · Martin Schwidefsky
arch/s390/kernel/entry.S +7 -3
index 3238893..84062e7 100644
@@ -178,17 +178,21 @@ _PIF_WORK	= (_PIF_PER_TRAP)
  */
 ENTRY(__switch_to)
 	stmg	%r6,%r15,__SF_GPRS(%r15)	# store gprs of prev task
-	stg	%r15,__THREAD_ksp(%r2)		# store kernel stack of prev
-	lg	%r4,__THREAD_info(%r2)		# get thread_info of prev
-	lg	%r5,__THREAD_info(%r3)		# get thread_info of next
+	lgr	%r1,%r2
+	aghi	%r1,__TASK_thread		# thread_struct of prev task
+	lg	%r4,__TASK_thread_info(%r2)	# get thread_info of prev
+	lg	%r5,__TASK_thread_info(%r3)	# get thread_info of next
+	stg	%r15,__THREAD_ksp(%r1)		# store kernel stack of prev
+	lgr	%r1,%r3
+	aghi	%r1,__TASK_thread		# thread_struct of next task
 	lgr	%r15,%r5

arch/s390/kernel/entry.S _PIF_WORK = (_PIF_PER_TRAP) · line 197

Quoted 10 lines
arch/s390/kernel/entry.S +1 -1
 	aghi	%r15,STACK_INIT			# end of kernel stack of next
 	stg	%r3,__LC_CURRENT		# store task struct of next
 	stg	%r5,__LC_THREAD_INFO		# store thread info of next
 	stg	%r15,__LC_KERNEL_STACK		# store end of kernel stack
+	lg	%r15,__THREAD_ksp(%r1)		# load kernel stack of next
 	lctl	%c4,%c4,__TASK_pid(%r3)		# load pid to control reg. 4
 	mvc	__LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
-	lg	%r15,__THREAD_ksp(%r3)		# load kernel stack of next
 	lmg	%r6,%r15,__SF_GPRS(%r15)	# load gprs of next task
 	br	%r14

Btw., I think we'd be slightly better off with the variant I sent: that way the offset arithmetics are done in C code and are ready in the relevant registers by the time they are used in __switch_to().

arch/s390/kernel/entry.S ENTRY(pgm_check_handler) · line 427

Quoted 9 lines
arch/s390/kernel/entry.S +1 -0
@@ -417,6 +421,7 @@ ENTRY(pgm_check_handler)
 	LAST_BREAK %r14
 	lg	%r15,__LC_KERNEL_STACK
 	lg	%r14,__TI_task(%r12)
+	aghi	%r14,__TASK_thread	# pointer to thread_struct
 	lghi	%r13,__LC_PGM_TDB
 	tm	__LC_PGM_ILC+2,0x02	# check for transaction abort
 	jz	2f

Don't we also need the chunk I have:

@@ -448,6 +449,7 @@ ENTRY(pgm_check_handler)
nill %r10,0x007f
sll %r10,2
je .Lsysc_return
+ ahi %r14,-__TASK_thread_struct # r14 now points to 'current'
lgf %r1,0(%r10,%r1) # load address of handler routine
lgr %r2,%r11 # pass pointer to pt_regs
basr %r14,%r1 # branch to interrupt-handler

Because the 'basr' line relies on 'r14' having task_struct, I think?

But I don't really know what I'm talking about here ...

Thanks,

Ingo

#5 lore raw

Re: [PATCH] sched, s390: Fix the fallout of increasing the offset of 'thread_struct' within 'task_struct'

Quoted 28 lines · On Mon, 20 Jul 2015 10:38:47 +0200 Ingo Molnar <[email protected]> wrote:
Quoted 25 lines · Martin Schwidefsky
arch/s390/kernel/entry.S +8 -3
index 3238893..84062e7 100644
@@ -178,17 +178,21 @@ _PIF_WORK	= (_PIF_PER_TRAP)
  */
 ENTRY(__switch_to)
 	stmg	%r6,%r15,__SF_GPRS(%r15)	# store gprs of prev task
-	stg	%r15,__THREAD_ksp(%r2)		# store kernel stack of prev
-	lg	%r4,__THREAD_info(%r2)		# get thread_info of prev
-	lg	%r5,__THREAD_info(%r3)		# get thread_info of next
+	lgr	%r1,%r2
+	aghi	%r1,__TASK_thread		# thread_struct of prev task
+	lg	%r4,__TASK_thread_info(%r2)	# get thread_info of prev
+	lg	%r5,__TASK_thread_info(%r3)	# get thread_info of next
+	stg	%r15,__THREAD_ksp(%r1)		# store kernel stack of prev
+	lgr	%r1,%r3
+	aghi	%r1,__TASK_thread		# thread_struct of next task
 	lgr	%r15,%r5
 	aghi	%r15,STACK_INIT			# end of kernel stack of next
 	stg	%r3,__LC_CURRENT		# store task struct of next
 	stg	%r5,__LC_THREAD_INFO		# store thread info of next
 	stg	%r15,__LC_KERNEL_STACK		# store end of kernel stack
+	lg	%r15,__THREAD_ksp(%r1)		# load kernel stack of next
 	lctl	%c4,%c4,__TASK_pid(%r3)		# load pid to control reg. 4
Quoted 8 lines

arch/s390/kernel/entry.S _PIF_WORK = (_PIF_PER_TRAP) · line 197

Quoted 4 lines
arch/s390/kernel/entry.S +0 -1
 	mvc	__LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
-	lg	%r15,__THREAD_ksp(%r3)		# load kernel stack of next
 	lmg	%r6,%r15,__SF_GPRS(%r15)	# load gprs of next task
 	br	%r14

Btw., I think we'd be slightly better off with the variant I sent: that way the offset arithmetics are done in C code and are ready in the relevant registers by the time they are used in __switch_to().

If we save any instruction then not many, we are trading additional parameter passing vs. four additional instructions in __switch_to. With this variant the fallout is kept at a minimum which I would prefer at this point.

Quoted 21 lines

arch/s390/kernel/entry.S ENTRY(pgm_check_handler) · line 427

Quoted 9 lines
arch/s390/kernel/entry.S +1 -0
@@ -417,6 +421,7 @@ ENTRY(pgm_check_handler)
 	LAST_BREAK %r14
 	lg	%r15,__LC_KERNEL_STACK
 	lg	%r14,__TI_task(%r12)
+	aghi	%r14,__TASK_thread	# pointer to thread_struct
 	lghi	%r13,__LC_PGM_TDB
 	tm	__LC_PGM_ILC+2,0x02	# check for transaction abort
 	jz	2f

Don't we also need the chunk I have:

(quoted diff) +1 -0
@@ -448,6 +449,7 @@ ENTRY(pgm_check_handler)
 	nill	%r10,0x007f
 	sll	%r10,2
 	je	.Lsysc_return
+	ahi     %r14,-__TASK_thread_struct # r14 now points to 'current'
 	lgf	%r1,0(%r10,%r1)		# load address of handler routine
 	lgr	%r2,%r11		# pass pointer to pt_regs
 	basr	%r14,%r1		# branch to interrupt-handler
Quoted 3 lines

Because the 'basr' line relies on 'r14' having task_struct, I think?

But I don't really know what I'm talking about here ...

The basr instruction is one of the function calling instructions and %r14 is used for the return address. Between function calls the register is basically free. So far it is used for the task_struct pointer (the code following the "lg %r14,__TI_task(%r12)"). What I noticed is that the pointer is only used to access the embedded thread_struct. To get from the task_struct to a thread_struct a single aghi is needed. The rest is moving stuff around in asm-offsets.c

Signature · 4 lines
blue skies,
   Martin.

"Reality continues to ruin my life." - Calvin.
#6 lore raw

PATCH 1/1 s390, sched: Fix thread_struct move fallout to __switch_to()

In reply to Heiko Carstens
Quoted 11 lines · Heiko Carstens

Unfortunately not true. It breaks the build on s390 since a couple of displacements used in asm code now get too large:

arch/s390/kernel/entry.S:181: Error: operand out of range (0x00000000000018a8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:191: Error: operand out of range (0x00000000000018a8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:423: Error: operand out of range (0x0000000000001924 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:437: Error: operand out of range (0x00000000000018e8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:438: Error: operand out of range (0x00000000000018e0 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:439: Error: operand out of range (0x00000000000018f0 is not between 0x0000000000000000 and 0x0000000000000fff) make[1]: *** [arch/s390/kernel/entry.o] Error 1

Quoted 1 line

Let's see how we can fix this.

Sorry about this!

So I looked at the __switch_to() assembly, and the main complication appears to be that we have two uses of 'prev':

lg %r4,__THREAD_info(%r2) # get thread_info of prev

stg %r15,__THREAD_ksp(%r2) # store kernel stack of prev

the __THREAD_info offset is best expressed relative to task_struct - the __THREAD_ksp offset is best expressed relative to thread_struct.

I.e. I think the best fix would be to extend the signature of s390's __switch_to() from (prev,next) to (prev,next,prev_thread,next_thread).

Is the C parameter mapping r2,r3,r4,r5? If yes then the patch below should do the trick. (Utterly untested.)

Note:

- I renamed __THREAD_info to __TASK_thread_info, to better separate task_struct and thread_struct offsets syntactically and visually.

- I removed __THREAD_mm_segment which is unused

I also looked at fixing pgm_check_handler(), but my s390-fu gave up completely on that one: task_struct is in 'r14', but this is a hardware entry function it appears. So to fix it we'd have to pick a temporary register, put thread_struct pointer into it, and fix up these offsets:

arch/s390/kernel/asm-offsets.c: DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address)); arch/s390/kernel/asm-offsets.c: DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid)); arch/s390/kernel/asm-offsets.c: DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));

to be thread_struct relative.

Thanks,

Ingo

==============>

 arch/s390/include/asm/switch_to.h |  7 +++++--
 arch/s390/kernel/asm-offsets.c    |  5 ++---
 arch/s390/kernel/entry.S          | 14 +++++++++-----
 3 files changed, 16 insertions(+), 10 deletions(-)
arch/s390/include/asm/switch_to.h +5 -2
index d62e7a69605f..aa854b600938 100644
@@ -10,7 +10,10 @@
 #include <linux/thread_info.h>
 #include <asm/ptrace.h>
 
-extern struct task_struct *__switch_to(void *, void *);
+extern struct task_struct *
+__switch_to(struct task_struct *prev, struct task_struct *next,
+	    struct thread_struct *prev_thread, struct thread_struct *next_thrad);
+
 extern void update_cr_regs(struct task_struct *task);
 
 static inline int test_fp_ctl(u32 fpc)
@@ -169,7 +172,7 @@ static inline void restore_access_regs(unsigned int *acrs)
 		restore_access_regs(&next->thread.acrs[0]);		\
 		restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);	\
 	}								\
-	prev = __switch_to(prev,next);					\
+	prev = __switch_to(prev, next, &prev->thread, &next->thread);	\
 } while (0)
 
 #endif /* __ASM_SWITCH_TO_H */
arch/s390/kernel/asm-offsets.c +2 -3
index c7d1b9d09011..2b422297660f 100644
@@ -23,9 +23,8 @@
 
 int main(void)
 {
-	DEFINE(__THREAD_info, offsetof(struct task_struct, stack));
-	DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp));
-	DEFINE(__THREAD_mm_segment, offsetof(struct task_struct, thread.mm_segment));
+	DEFINE(__TASK_thread_info, offsetof(struct task_struct, stack));
+	DEFINE(__THREAD_ksp, offsetof(struct thread_struct, ksp));
 	BLANK();
 	DEFINE(__TASK_pid, offsetof(struct task_struct, pid));
 	BLANK();
arch/s390/kernel/entry.S +9 -5
index 3238893c9d4f..c2fcb9e7ad25 100644
@@ -170,17 +170,21 @@ _PIF_WORK	= (_PIF_PER_TRAP)
 	.section .kprobes.text, "ax"
 
 /*
- * Scheduler resume function, called by switch_to
+ * Low level scheduler resume function, called by switch_to():
+ *
  *  gpr2 = (task_struct *) prev
  *  gpr3 = (task_struct *) next
+ *  gpr4 = (thread_struct *) prev->thread
+ *  gpr5 = (thread_struct *) next->thread
+ *
  * Returns:
  *  gpr2 = prev
  */
 ENTRY(__switch_to)
 	stmg	%r6,%r15,__SF_GPRS(%r15)	# store gprs of prev task
-	stg	%r15,__THREAD_ksp(%r2)		# store kernel stack of prev
-	lg	%r4,__THREAD_info(%r2)		# get thread_info of prev
-	lg	%r5,__THREAD_info(%r3)		# get thread_info of next
+	stg	%r15,__THREAD_ksp(%r4)		# store kernel stack of prev
+	lg	%r4,__TASK_thread_info(%r2)	# get thread_info of prev
+	lg	%r5,__TASK_thread_info(%r3)	# get thread_info of next
 	lgr	%r15,%r5
 	aghi	%r15,STACK_INIT			# end of kernel stack of next
 	stg	%r3,__LC_CURRENT		# store task struct of next
@@ -188,7 +192,7 @@ ENTRY(__switch_to)
 	stg	%r15,__LC_KERNEL_STACK		# store end of kernel stack
 	lctl	%c4,%c4,__TASK_pid(%r3)		# load pid to control reg. 4
 	mvc	__LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
-	lg	%r15,__THREAD_ksp(%r3)		# load kernel stack of next
+	lg	%r15,__THREAD_ksp(%r5)		# load kernel stack of next
 	lmg	%r6,%r15,__SF_GPRS(%r15)	# load gprs of next task
 	br	%r14
 
#7 lore raw

Re: [PATCH] s390, sched: Fix thread_struct move fallout to __switch_to()

Quoted 47 lines · On Mon, 20 Jul 2015 10:20:04 +0200 Ingo Molnar <[email protected]> wrote:
Quoted 11 lines · Heiko Carstens

Unfortunately not true. It breaks the build on s390 since a couple of displacements used in asm code now get too large:

arch/s390/kernel/entry.S:181: Error: operand out of range (0x00000000000018a8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:191: Error: operand out of range (0x00000000000018a8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:423: Error: operand out of range (0x0000000000001924 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:437: Error: operand out of range (0x00000000000018e8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:438: Error: operand out of range (0x00000000000018e0 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:439: Error: operand out of range (0x00000000000018f0 is not between 0x0000000000000000 and 0x0000000000000fff) make[1]: *** [arch/s390/kernel/entry.o] Error 1

Quoted 1 line

Let's see how we can fix this.

Sorry about this!

So I looked at the __switch_to() assembly, and the main complication appears to be that we have two uses of 'prev':

lg %r4,__THREAD_info(%r2) # get thread_info of prev

stg %r15,__THREAD_ksp(%r2) # store kernel stack of prev

the __THREAD_info offset is best expressed relative to task_struct - the __THREAD_ksp offset is best expressed relative to thread_struct.

I.e. I think the best fix would be to extend the signature of s390's __switch_to() from (prev,next) to (prev,next,prev_thread,next_thread).

Is the C parameter mapping r2,r3,r4,r5? If yes then the patch below should do the trick. (Utterly untested.)

Note:

- I renamed __THREAD_info to __TASK_thread_info, to better separate task_struct and thread_struct offsets syntactically and visually.

- I removed __THREAD_mm_segment which is unused

I also looked at fixing pgm_check_handler(), but my s390-fu gave up completely on that one: task_struct is in 'r14', but this is a hardware entry function it appears. So to fix it we'd have to pick a temporary register, put thread_struct pointer into it, and fix up these offsets:

Quoted 5 lines

arch/s390/kernel/asm-offsets.c: DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address)); arch/s390/kernel/asm-offsets.c: DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid)); arch/s390/kernel/asm-offsets.c: DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));

to be thread_struct relative.

Just use the patch I've sent. No worries :-)

Signature · 4 lines
blue skies,
   Martin.

"Reality continues to ruin my life." - Calvin.
#8 lore raw

Re: [PATCH] s390, sched: Fix thread_struct move fallout to __switch_to()

In reply to Ingo Molnar
Quoted 10 lines · Ingo Molnar

I also looked at fixing pgm_check_handler(), but my s390-fu gave up completely on that one: task_struct is in 'r14', but this is a hardware entry function it appears. So to fix it we'd have to pick a temporary register, put thread_struct pointer into it, and fix up these offsets:

arch/s390/kernel/asm-offsets.c: DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address)); arch/s390/kernel/asm-offsets.c: DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid)); arch/s390/kernel/asm-offsets.c: DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));

to be thread_struct relative.

Here's a stab at that: we can move 'r14' from 'current' to 'current->thread' and back relatively cheaply I think. If I got the mnemonics right.

Thanks,

Ingo

===============================>

 arch/s390/kernel/asm-offsets.c | 9 +++++----
 arch/s390/kernel/entry.S       | 2 ++
 2 files changed, 7 insertions(+), 4 deletions(-)
arch/s390/kernel/asm-offsets.c +5 -4
index 2b422297660f..26edbc4b5078 100644
@@ -24,13 +24,14 @@
 int main(void)
 {
 	DEFINE(__TASK_thread_info, offsetof(struct task_struct, stack));
+	DEFINE(__TASK_thread_struct, offsetof(struct task_struct, thread));
 	DEFINE(__THREAD_ksp, offsetof(struct thread_struct, ksp));
 	BLANK();
 	DEFINE(__TASK_pid, offsetof(struct task_struct, pid));
 	BLANK();
-	DEFINE(__THREAD_per_cause, offsetof(struct task_struct, thread.per_event.cause));
-	DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address));
-	DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid));
+	DEFINE(__THREAD_per_cause, offsetof(struct thread_struct, per_event.cause));
+	DEFINE(__THREAD_per_address, offsetof(struct thread_struct, per_event.address));
+	DEFINE(__THREAD_per_paid, offsetof(struct thread_struct, per_event.paid));
 	BLANK();
 	DEFINE(__TI_task, offsetof(struct thread_info, task));
 	DEFINE(__TI_flags, offsetof(struct thread_info, flags));
@@ -175,7 +176,7 @@ int main(void)
 	DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data));
 	DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap));
 	DEFINE(__LC_PGM_TDB, offsetof(struct _lowcore, pgm_tdb));
-	DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));
+	DEFINE(__THREAD_trap_tdb, offsetof(struct thread_struct, trap_tdb));
 	DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce));
 	DEFINE(__SIE_PROG0C, offsetof(struct kvm_s390_sie_block, prog0c));
 	DEFINE(__SIE_PROG20, offsetof(struct kvm_s390_sie_block, prog20));
arch/s390/kernel/entry.S +2 -0
index c2fcb9e7ad25..9806b2f94985 100644
@@ -421,6 +421,7 @@ ENTRY(pgm_check_handler)
 	LAST_BREAK %r14
 	lg	%r15,__LC_KERNEL_STACK
 	lg	%r14,__TI_task(%r12)
+	ahi     %r14,__TASK_thread_struct # r14 now points to 'current->thread'
 	lghi	%r13,__LC_PGM_TDB
 	tm	__LC_PGM_ILC+2,0x02	# check for transaction abort
 	jz	2f
@@ -448,6 +449,7 @@ ENTRY(pgm_check_handler)
 	nill	%r10,0x007f
 	sll	%r10,2
 	je	.Lsysc_return
+	ahi     %r14,-__TASK_thread_struct # r14 now points to 'current'
 	lgf	%r1,0(%r10,%r1)		# load address of handler routine
 	lgr	%r2,%r11		# pass pointer to pt_regs
 	basr	%r14,%r1		# branch to interrupt-handler