diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index 62fd80c9e98cbb6b2944cba67398ee746870d1c3..93c907b4776fa08a8bc55aa629bef064cbae3f4b 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -328,8 +328,7 @@ struct pt_regs
 	psw_t psw;
 	unsigned long gprs[NUM_GPRS];
 	unsigned long orig_gpr2;
-	unsigned short ilc;
-	unsigned short svcnr;
+	unsigned int svc_code;
 };
 
 /*
@@ -487,6 +486,8 @@ typedef struct
 #define PTRACE_POKETEXT_AREA	      0x5004
 #define PTRACE_POKEDATA_AREA 	      0x5005
 #define PTRACE_GET_LAST_BREAK	      0x5006
+#define PTRACE_PEEK_SYSTEM_CALL       0x5007
+#define PTRACE_POKE_SYSTEM_CALL	      0x5008
 
 /*
  * PT_PROT definition is loosely based on hppa bsd definition in
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
index 5c0246b955d80e411250623c400c3387f23568b7..614267f6071353cc9527194fe251923b51b6fba9 100644
--- a/arch/s390/include/asm/syscall.h
+++ b/arch/s390/include/asm/syscall.h
@@ -13,6 +13,7 @@
 #define _ASM_SYSCALL_H	1
 
 #include <linux/sched.h>
+#include <linux/err.h>
 #include <asm/ptrace.h>
 
 /*
@@ -25,7 +26,7 @@ extern const unsigned int sys_call_table[];
 static inline long syscall_get_nr(struct task_struct *task,
 				  struct pt_regs *regs)
 {
-	return regs->svcnr ? regs->svcnr : -1;
+	return regs->svc_code ? (regs->svc_code & 0xffff) : -1;
 }
 
 static inline void syscall_rollback(struct task_struct *task,
@@ -37,7 +38,7 @@ static inline void syscall_rollback(struct task_struct *task,
 static inline long syscall_get_error(struct task_struct *task,
 				     struct pt_regs *regs)
 {
-	return (regs->gprs[2] >= -4096UL) ? -regs->gprs[2] : 0;
+	return IS_ERR_VALUE(regs->gprs[2]) ? regs->gprs[2] : 0;
 }
 
 static inline long syscall_get_return_value(struct task_struct *task,
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index f9a9a10979c9bfe59838fd9904f647d529d4da1a..0c4788eb5a6564480fef98ccd875bc0fff0b55c1 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -48,6 +48,7 @@ struct thread_info {
 	unsigned int		cpu;		/* current CPU */
 	int			preempt_count;	/* 0 => preemptable, <0 => BUG */
 	struct restart_block	restart_block;
+	unsigned int		system_call;
 	__u64			user_timer;
 	__u64			system_timer;
 	unsigned long		last_break;	/* last breaking-event-address. */
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 1140035b1cd8c68e00531c8dfc99292803ab1cb9..751318765e2e95ba1a2d5c56e683e13de0eb9925 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -45,8 +45,7 @@ int main(void)
 	DEFINE(__PT_PSW, offsetof(struct pt_regs, psw));
 	DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
 	DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
-	DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc));
-	DEFINE(__PT_SVCNR, offsetof(struct pt_regs, svcnr));
+	DEFINE(__PT_SVC_CODE, offsetof(struct pt_regs, svc_code));
 	DEFINE(__PT_SIZE, sizeof(struct pt_regs));
 	BLANK();
 	DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain));
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index a9a285b8c4ad3ccdfafcaf2b1412de4900e2b219..d7c8e54c32e7f285f874bcb50a9ae074cb4c7cb0 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -342,7 +342,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
 		return err;
 
 	restore_fp_regs(&current->thread.fp_regs);
-	regs->svcnr = 0;	/* disable syscall checks */
+	regs->svc_code = 0;	/* disable syscall checks */
 	return 0;
 }
 
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 195387ab7c983ca42496c2f8ca927a4176a05b13..afe3685d30e799b27e4018b4f28ed7a14037342e 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -43,8 +43,7 @@ SP_R13	     =	STACK_FRAME_OVERHEAD + __PT_GPRS + 52
 SP_R14	     =	STACK_FRAME_OVERHEAD + __PT_GPRS + 56
 SP_R15	     =	STACK_FRAME_OVERHEAD + __PT_GPRS + 60
 SP_ORIG_R2   =	STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
-SP_ILC	     =	STACK_FRAME_OVERHEAD + __PT_ILC
-SP_SVCNR     =	STACK_FRAME_OVERHEAD + __PT_SVCNR
+SP_SVC_CODE  =	STACK_FRAME_OVERHEAD + __PT_SVC_CODE
 SP_SIZE      =	STACK_FRAME_OVERHEAD + __PT_SIZE
 
 _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
@@ -229,7 +228,7 @@ sysc_saveall:
 	SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_SAVE_AREA
 	mvc	SP_PSW(8,%r15),__LC_SVC_OLD_PSW
-	mvc	SP_ILC(4,%r15),__LC_SVC_ILC
+	mvc	SP_SVC_CODE(4,%r15),__LC_SVC_ILC
 	l	%r12,__LC_THREAD_INFO	# load pointer to thread_info struct
 sysc_vtime:
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
@@ -239,12 +238,12 @@ sysc_update:
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 sysc_do_svc:
 	xr	%r7,%r7
-	icm	%r7,3,SP_SVCNR(%r15)	# load svc number and test for svc 0
+	icm	%r7,3,SP_SVC_CODE+2(%r15)# load svc number and test for svc 0
 	bnz	BASED(sysc_nr_ok)	# svc number > 0
 	# svc 0: system call number in %r1
 	cl	%r1,BASED(.Lnr_syscalls)
 	bnl	BASED(sysc_nr_ok)
-	sth	%r1,SP_SVCNR(%r15)
+	sth	%r1,SP_SVC_CODE+2(%r15)
 	lr	%r7,%r1 	  # copy svc number to %r7
 sysc_nr_ok:
 	sll	%r7,2		  # svc number *4
@@ -335,10 +334,11 @@ sysc_notify_resume:
 #
 sysc_restart:
 	ni	__TI_flags+3(%r12),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
-	l	%r7,SP_R2(%r15) 	# load new svc number
-	mvc	SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument
 	lm	%r2,%r6,SP_R2(%r15)	# load svc arguments
-	sth	%r7,SP_SVCNR(%r15)
+	xr	%r7,%r7			# svc 0 returns -ENOSYS
+	clc	SP_SVC_CODE+2(%r15),BASED(.Lnr_syscalls+2)
+	bnl	BASED(sysc_nr_ok)	# invalid svc number -> do svc 0
+	icm	%r7,3,SP_SVC_CODE+2(%r15)# load new svc number
 	b	BASED(sysc_nr_ok)	# restart svc
 
 #
@@ -346,7 +346,7 @@ sysc_restart:
 #
 sysc_singlestep:
 	ni	__TI_flags+3(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP
-	xc	SP_SVCNR(2,%r15),SP_SVCNR(%r15)		# clear svc number
+	xc	SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15)	# clear svc code
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 	l	%r1,BASED(.Lhandle_per)	# load adr. of per handler
 	la	%r14,BASED(sysc_return)	# load adr. of system return
@@ -361,7 +361,7 @@ sysc_tracesys:
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
 	la	%r3,0
 	xr	%r0,%r0
-	icm	%r0,3,SP_SVCNR(%r15)
+	icm	%r0,3,SP_SVC_CODE(%r15)
 	st	%r0,SP_R2(%r15)
 	basr	%r14,%r1
 	cl	%r2,BASED(.Lnr_syscalls)
@@ -454,7 +454,7 @@ ENTRY(pgm_check_handler)
 	bnz	BASED(pgm_per)		# got per exception -> special case
 	SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_SAVE_AREA
-	xc	SP_ILC(4,%r15),SP_ILC(%r15)
+	xc	SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15)
 	mvc	SP_PSW(8,%r15),__LC_PGM_OLD_PSW
 	l	%r12,__LC_THREAD_INFO	# load pointer to thread_info struct
 	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
@@ -531,7 +531,7 @@ pgm_svcper:
 	SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_SAVE_AREA
 	mvc	SP_PSW(8,%r15),__LC_SVC_OLD_PSW
-	mvc	SP_ILC(4,%r15),__LC_SVC_ILC
+	mvc	SP_SVC_CODE(4,%r15),__LC_SVC_ILC
 	l	%r12,__LC_THREAD_INFO	# load pointer to thread_info struct
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
@@ -550,7 +550,7 @@ pgm_svcper:
 #
 kernel_per:
 	REENABLE_IRQS
-	xc	SP_SVCNR(2,%r15),SP_SVCNR(%r15)
+	xc	SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15)
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 	l	%r1,BASED(.Lhandle_per)	# load adr. of per handler
 	basr	%r14,%r1		# branch to do_single_step
@@ -966,7 +966,7 @@ cleanup_system_call:
 	st	%r15,12(%r12)
 	CREATE_STACK_FRAME __LC_SAVE_AREA
 	mvc	SP_PSW(8,%r15),__LC_SVC_OLD_PSW
-	mvc	SP_ILC(4,%r15),__LC_SVC_ILC
+	mvc	SP_SVC_CODE(4,%r15),__LC_SVC_ILC
 	mvc	0(4,%r12),__LC_THREAD_INFO
 cleanup_vtime:
 	clc	__LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12)
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 3257f7f555515f99ed94d74b684486dd2ab16a79..7ff07d3a29c16f152f43e1b29adabeefea3c8ff7 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -43,8 +43,7 @@ SP_R13	     =	STACK_FRAME_OVERHEAD + __PT_GPRS + 104
 SP_R14	     =	STACK_FRAME_OVERHEAD + __PT_GPRS + 112
 SP_R15	     =	STACK_FRAME_OVERHEAD + __PT_GPRS + 120
 SP_ORIG_R2   =	STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
-SP_ILC	     =	STACK_FRAME_OVERHEAD + __PT_ILC
-SP_SVCNR      =	STACK_FRAME_OVERHEAD + __PT_SVCNR
+SP_SVC_CODE  =	STACK_FRAME_OVERHEAD + __PT_SVC_CODE
 SP_SIZE      =	STACK_FRAME_OVERHEAD + __PT_SIZE
 
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
@@ -250,7 +249,7 @@ sysc_saveall:
 	SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_SAVE_AREA
 	mvc	SP_PSW(16,%r15),__LC_SVC_OLD_PSW
-	mvc	SP_ILC(4,%r15),__LC_SVC_ILC
+	mvc	SP_SVC_CODE(4,%r15),__LC_SVC_ILC
 	lg	%r12,__LC_THREAD_INFO	# load pointer to thread_info struct
 sysc_vtime:
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
@@ -260,14 +259,14 @@ sysc_update:
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 	LAST_BREAK
 sysc_do_svc:
-	llgh	%r7,SP_SVCNR(%r15)
+	llgh	%r7,SP_SVC_CODE+2(%r15)
 	slag	%r7,%r7,2	# shift and test for svc 0
 	jnz	sysc_nr_ok
 	# svc 0: system call number in %r1
 	llgfr	%r1,%r1		# clear high word in r1
 	cghi	%r1,NR_syscalls
 	jnl	sysc_nr_ok
-	sth	%r1,SP_SVCNR(%r15)
+	sth	%r1,SP_SVC_CODE+2(%r15)
 	slag	%r7,%r1,2	# shift and test for svc 0
 sysc_nr_ok:
 	larl	%r10,sys_call_table
@@ -358,11 +357,12 @@ sysc_notify_resume:
 #
 sysc_restart:
 	ni	__TI_flags+7(%r12),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
-	lg	%r7,SP_R2(%r15)		# load new svc number
-	mvc	SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument
 	lmg	%r2,%r6,SP_R2(%r15)	# load svc arguments
-	sth	%r7,SP_SVCNR(%r15)
-	slag	%r7,%r7,2
+	lghi	%r7,0			# svc 0 returns -ENOSYS
+	lh	%r1,SP_SVC_CODE+2(%r15)	# load new svc number
+	cghi	%r1,NR_syscalls
+	jnl	sysc_nr_ok		# invalid svc number -> do svc 0
+	slag	%r7,%r1,2
 	j	sysc_nr_ok		# restart svc
 
 #
@@ -370,7 +370,7 @@ sysc_restart:
 #
 sysc_singlestep:
 	ni	__TI_flags+7(%r12),255-_TIF_PER_TRAP	# clear TIF_PER_TRAP
-	xc	SP_SVCNR(2,%r15),SP_SVCNR(%r15)		# clear svc number
+	xc	SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15)	# clear svc code
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 	larl	%r14,sysc_return	# load adr. of system return
 	jg	do_per_trap
@@ -382,7 +382,7 @@ sysc_singlestep:
 sysc_tracesys:
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
 	la	%r3,0
-	llgh	%r0,SP_SVCNR(%r15)
+	llgh	%r0,SP_SVC_CODE+2(%r15)
 	stg	%r0,SP_R2(%r15)
 	brasl	%r14,do_syscall_trace_enter
 	lghi	%r0,NR_syscalls
@@ -470,7 +470,7 @@ ENTRY(pgm_check_handler)
 	jnz	pgm_per 		 # got per exception -> special case
 	SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_SAVE_AREA
-	xc	SP_ILC(4,%r15),SP_ILC(%r15)
+	xc	SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15)
 	mvc	SP_PSW(16,%r15),__LC_PGM_OLD_PSW
 	lg	%r12,__LC_THREAD_INFO	# load pointer to thread_info struct
 	HANDLE_SIE_INTERCEPT
@@ -551,7 +551,7 @@ pgm_svcper:
 	SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_SAVE_AREA
 	mvc	SP_PSW(16,%r15),__LC_SVC_OLD_PSW
-	mvc	SP_ILC(4,%r15),__LC_SVC_ILC
+	mvc	SP_SVC_CODE(4,%r15),__LC_SVC_ILC
 	lg	%r12,__LC_THREAD_INFO	# load pointer to thread_info struct
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
@@ -571,7 +571,7 @@ pgm_svcper:
 #
 kernel_per:
 	REENABLE_IRQS
-	xc	SP_SVCNR(2,%r15),SP_SVCNR(%r15)	# clear svc number
+	xc	SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15)	# clear svc number
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 	brasl	%r14,do_per_trap
 	j	pgm_exit
@@ -973,7 +973,7 @@ cleanup_system_call:
 	stg	%r11,0(%r12)
 	CREATE_STACK_FRAME __LC_SAVE_AREA
 	mvc	SP_PSW(16,%r15),__LC_SVC_OLD_PSW
-	mvc	SP_ILC(4,%r15),__LC_SVC_ILC
+	mvc	SP_SVC_CODE(4,%r15),__LC_SVC_ILC
 	mvc	8(8,%r12),__LC_THREAD_INFO
 cleanup_vtime:
 	clc	__LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24)
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index ae0e14b8880ca8a8176ea866bc2ac6b622a4e057..bae1cc49fe96c8bfaa586a5e2d5cbdd8d72ac3c3 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -42,6 +42,7 @@ enum s390_regset {
 	REGSET_GENERAL,
 	REGSET_FP,
 	REGSET_LAST_BREAK,
+	REGSET_SYSTEM_CALL,
 	REGSET_GENERAL_EXTENDED,
 };
 
@@ -303,6 +304,13 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
 			   high order bit but older gdb's rely on it */
 			data |= PSW_ADDR_AMODE;
 #endif
+		if (addr == (addr_t) &dummy->regs.psw.addr)
+			/*
+			 * The debugger changed the instruction address,
+			 * reset system call restart, see signal.c:do_signal
+			 */
+			task_thread_info(child)->system_call = 0;
+
 		*(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data;
 
 	} else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) {
@@ -610,6 +618,11 @@ static int __poke_user_compat(struct task_struct *child,
 			/* Build a 64 bit psw address from 31 bit address. */
 			task_pt_regs(child)->psw.addr =
 				(__u64) tmp & PSW32_ADDR_INSN;
+			/*
+			 * The debugger changed the instruction address,
+			 * reset system call restart, see signal.c:do_signal
+			 */
+			task_thread_info(child)->system_call = 0;
 		} else {
 			/* gpr 0-15 */
 			*(__u32*)((addr_t) &task_pt_regs(child)->psw
@@ -737,7 +750,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
 		 * debugger stored an invalid system call number. Skip
 		 * the system call and the system call restart handling.
 		 */
-		regs->svcnr = 0;
+		regs->svc_code = 0;
 		ret = -1;
 	}
 
@@ -899,6 +912,26 @@ static int s390_last_break_get(struct task_struct *target,
 
 #endif
 
+static int s390_system_call_get(struct task_struct *target,
+				const struct user_regset *regset,
+				unsigned int pos, unsigned int count,
+				void *kbuf, void __user *ubuf)
+{
+	unsigned int *data = &task_thread_info(target)->system_call;
+	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				   data, 0, sizeof(unsigned int));
+}
+
+static int s390_system_call_set(struct task_struct *target,
+				const struct user_regset *regset,
+				unsigned int pos, unsigned int count,
+				const void *kbuf, const void __user *ubuf)
+{
+	unsigned int *data = &task_thread_info(target)->system_call;
+	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				  data, 0, sizeof(unsigned int));
+}
+
 static const struct user_regset s390_regsets[] = {
 	[REGSET_GENERAL] = {
 		.core_note_type = NT_PRSTATUS,
@@ -925,6 +958,14 @@ static const struct user_regset s390_regsets[] = {
 		.get = s390_last_break_get,
 	},
 #endif
+	[REGSET_SYSTEM_CALL] = {
+		.core_note_type = NT_S390_SYSTEM_CALL,
+		.n = 1,
+		.size = sizeof(unsigned int),
+		.align = sizeof(unsigned int),
+		.get = s390_system_call_get,
+		.set = s390_system_call_set,
+	},
 };
 
 static const struct user_regset_view user_s390_view = {
@@ -1104,6 +1145,14 @@ static const struct user_regset s390_compat_regsets[] = {
 		.align = sizeof(long),
 		.get = s390_compat_last_break_get,
 	},
+	[REGSET_SYSTEM_CALL] = {
+		.core_note_type = NT_S390_SYSTEM_CALL,
+		.n = 1,
+		.size = sizeof(compat_uint_t),
+		.align = sizeof(compat_uint_t),
+		.get = s390_system_call_get,
+		.set = s390_system_call_set,
+	},
 	[REGSET_GENERAL_EXTENDED] = {
 		.core_note_type = NT_S390_HIGH_GPRS,
 		.n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t),
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 9a40e1cc5ec3f5e2b5ce15268b35862d22aff28e..e751cab80e04b881f52697f645de3016ff8d5687 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -30,6 +30,7 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
+#include <asm/compat.h>
 #include "entry.h"
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -156,7 +157,7 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
 	current->thread.fp_regs.fpc &= FPC_VALID_MASK;
 
 	restore_fp_regs(&current->thread.fp_regs);
-	regs->svcnr = 0;	/* disable syscall checks */
+	regs->svc_code = 0;	/* disable syscall checks */
 	return 0;
 }
 
@@ -401,7 +402,6 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
  */
 void do_signal(struct pt_regs *regs)
 {
-	unsigned long retval = 0, continue_addr = 0, restart_addr = 0;
 	siginfo_t info;
 	int signr;
 	struct k_sigaction ka;
@@ -421,54 +421,43 @@ void do_signal(struct pt_regs *regs)
 	else
 		oldset = &current->blocked;
 
-	/* Are we from a system call? */
-	if (regs->svcnr) {
-		continue_addr = regs->psw.addr;
-		restart_addr = continue_addr - regs->ilc;
-		retval = regs->gprs[2];
-
-		/* Prepare for system call restart.  We do this here so that a
-		   debugger will see the already changed PSW. */
-		switch (retval) {
-		case -ERESTARTNOHAND:
-		case -ERESTARTSYS:
-		case -ERESTARTNOINTR:
-			regs->gprs[2] = regs->orig_gpr2;
-			regs->psw.addr = restart_addr;
-			break;
-		case -ERESTART_RESTARTBLOCK:
-			regs->gprs[2] = -EINTR;
-		}
-		regs->svcnr = 0;	/* Don't deal with this again. */
-	}
-
-	/* Get signal to deliver.  When running under ptrace, at this point
-	   the debugger may change all our registers ... */
+	/*
+	 * Get signal to deliver. When running under ptrace, at this point
+	 * the debugger may change all our registers, including the system
+	 * call information.
+	 */
+	current_thread_info()->system_call = regs->svc_code;
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-
-	/* Depending on the signal settings we may need to revert the
-	   decision to restart the system call. */
-	if (signr > 0 && regs->psw.addr == restart_addr) {
-		if (retval == -ERESTARTNOHAND
-		    || (retval == -ERESTARTSYS
-			 && !(current->sighand->action[signr-1].sa.sa_flags
-			      & SA_RESTART))) {
-			regs->gprs[2] = -EINTR;
-			regs->psw.addr = continue_addr;
-		}
-	}
+	regs->svc_code = current_thread_info()->system_call;
 
 	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
-		int ret;
-#ifdef CONFIG_COMPAT
-		if (is_compat_task()) {
-			ret = handle_signal32(signr, &ka, &info, oldset, regs);
-	        }
-		else
-#endif
-			ret = handle_signal(signr, &ka, &info, oldset, regs);
-		if (!ret) {
+		if (regs->svc_code > 0) {
+			/* Check for system call restarting. */
+			switch (regs->gprs[2]) {
+			case -ERESTART_RESTARTBLOCK:
+			case -ERESTARTNOHAND:
+				regs->gprs[2] = -EINTR;
+				break;
+			case -ERESTARTSYS:
+				if (!(ka.sa.sa_flags & SA_RESTART)) {
+					regs->gprs[2] = -EINTR;
+					break;
+				}
+			/* fallthrough */
+			case -ERESTARTNOINTR:
+				regs->gprs[2] = regs->orig_gpr2;
+				regs->psw.addr = regs->psw.addr -
+					(regs->svc_code >> 16);
+				break;
+			}
+			/* No longer in a system call */
+			regs->svc_code = 0;
+		}
+
+		if ((is_compat_task() ?
+		     handle_signal32(signr, &ka, &info, oldset, regs) :
+		     handle_signal(signr, &ka, &info, oldset, regs)) == 0) {
 			/*
 			 * A signal was successfully delivered; the saved
 			 * sigmask will have been stored in the signal frame,
@@ -482,11 +471,28 @@ void do_signal(struct pt_regs *regs)
 			 * Let tracing know that we've done the handler setup.
 			 */
 			tracehook_signal_handler(signr, &info, &ka, regs,
-					test_thread_flag(TIF_SINGLE_STEP));
+					 test_thread_flag(TIF_SINGLE_STEP));
 		}
 		return;
 	}
 
+	/* No handlers present - check for system call restart */
+	if (regs->svc_code > 0) {
+		switch (regs->gprs[2]) {
+		case -ERESTART_RESTARTBLOCK:
+			/* Restart with sys_restart_syscall */
+			regs->svc_code = __NR_restart_syscall;
+		/* fallthrough */
+		case -ERESTARTNOHAND:
+		case -ERESTARTSYS:
+		case -ERESTARTNOINTR:
+			/* Restart system call with magic TIF bit. */
+			regs->gprs[2] = regs->orig_gpr2;
+			set_thread_flag(TIF_RESTART_SVC);
+			break;
+		}
+	}
+
 	/*
 	 * If there's no signal to deliver, we just put the saved sigmask back.
 	 */
@@ -494,13 +500,6 @@ void do_signal(struct pt_regs *regs)
 		clear_thread_flag(TIF_RESTORE_SIGMASK);
 		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
 	}
-
-	/* Restart a different system call. */
-	if (retval == -ERESTART_RESTARTBLOCK
-	    && regs->psw.addr == continue_addr) {
-		regs->gprs[2] = __NR_restart_syscall;
-		set_thread_flag(TIF_RESTART_SVC);
-	}
 }
 
 void do_notify_resume(struct pt_regs *regs)
diff --git a/include/linux/elf.h b/include/linux/elf.h
index 110821cb6ea5fb5c8789da31f26af10ee61fc68d..31f0508d7da7a3274e207cc3389edb824ed77fd3 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -395,6 +395,7 @@ typedef struct elf64_shdr {
 #define NT_S390_CTRS	0x304		/* s390 control registers */
 #define NT_S390_PREFIX	0x305		/* s390 prefix register */
 #define NT_S390_LAST_BREAK	0x306	/* s390 breaking event address */
+#define NT_S390_SYSTEM_CALL	0x307	/* s390 system call restart data */
 #define NT_ARM_VFP	0x400		/* ARM VFP/NEON registers */