s390: move restart of execve() syscall

On s390, execve might have to be restarted for PGSTE binaries
like kvm. In the past this was done via the PIF_SYSCALL_RESTART
bit. However, with the recent changes, syscalls are now restarted
differently. Now that execve() is the only call that might get
restarted via PIF_SYSCALL_RESTART, move the loop to do_syscall().
This also has the advantage that the restart is no longer visible
to userspace.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index c7850d6..808da21 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -162,6 +162,14 @@ static inline int test_pt_regs_flag(struct pt_regs *regs, int flag)
 	return !!(regs->flags & (1UL << flag));
 }
 
+static inline int test_and_clear_pt_regs_flag(struct pt_regs *regs, int flag)
+{
+	int ret = test_pt_regs_flag(regs, flag);
+
+	clear_pt_regs_flag(regs, flag);
+	return ret;
+}
+
 /*
  * These are defined as per linux/ptrace.h, which see.
  */
diff --git a/arch/s390/kernel/syscall.c b/arch/s390/kernel/syscall.c
index ec73d2c..0322f00 100644
--- a/arch/s390/kernel/syscall.c
+++ b/arch/s390/kernel/syscall.c
@@ -134,13 +134,15 @@ static void do_syscall(struct pt_regs *regs)
 	 * work, the ptrace code sets PIF_SYSCALL_RET_SET, which is checked here
 	 * and if set, the syscall will be skipped.
 	 */
-	if (!test_pt_regs_flag(regs, PIF_SYSCALL_RET_SET)) {
-		regs->gprs[2] = -ENOSYS;
-		if (likely(nr < NR_syscalls))
-			regs->gprs[2] = current->thread.sys_call_table[nr](regs);
-	} else {
-		clear_pt_regs_flag(regs, PIF_SYSCALL_RET_SET);
-	}
+	if (unlikely(test_and_clear_pt_regs_flag(regs, PIF_SYSCALL_RET_SET)))
+		goto out;
+	regs->gprs[2] = -ENOSYS;
+	if (likely(nr >= NR_syscalls))
+		goto out;
+	do {
+		regs->gprs[2] = current->thread.sys_call_table[nr](regs);
+	} while (test_and_clear_pt_regs_flag(regs, PIF_SYSCALL_RESTART));
+out:
 	syscall_exit_to_user_mode_work(regs);
 }
 
@@ -158,13 +160,8 @@ void noinstr __do_syscall(struct pt_regs *regs, int per_trap)
 	if (per_trap)
 		set_thread_flag(TIF_PER_TRAP);
 
-	for (;;) {
-		regs->flags = 0;
-		set_pt_regs_flag(regs, PIF_SYSCALL);
-		do_syscall(regs);
-		if (!test_pt_regs_flag(regs, PIF_SYSCALL_RESTART))
-			break;
-		local_irq_enable();
-	}
+	regs->flags = 0;
+	set_pt_regs_flag(regs, PIF_SYSCALL);
+	do_syscall(regs);
 	exit_to_user_mode();
 }