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

[POWERPC] Make syscall restart code more common

This patch moves the code in signal_32.c and signal_64.c for handling
syscall restart into a common signal.c file and converge around a single
implementation that is based on the 32 bits one, using trap, ccr
and r3 rather than the special "result" field for deciding what to do.

The "result" field is now pretty much deprecated. We still set it for
the sake of whatever might rely on it in userland but we no longer use
it's content.

This, along with a previous patch that enables ptracers to write to
"trap" and "orig_r3" should allow gdb to properly handle syscall
restarting.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Benjamin Herrenschmidt and committed by
Paul Mackerras
22e38f29 791cc501

+94 -77
+2 -1
arch/powerpc/kernel/Makefile
··· 12 12 13 13 obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ 14 14 irq.o align.o signal_32.o pmc.o vdso.o \ 15 - init_task.o process.o systbl.o idle.o 15 + init_task.o process.o systbl.o idle.o \ 16 + signal.o 16 17 obj-y += vdso32/ 17 18 obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ 18 19 signal_64.o ptrace32.o \
+65
arch/powerpc/kernel/signal.c
··· 1 + /* 2 + * Common signal handling code for both 32 and 64 bits 3 + * 4 + * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration 5 + * Extracted from signal_32.c and signal_64.c 6 + * 7 + * This file is subject to the terms and conditions of the GNU General 8 + * Public License. See the file README.legal in the main directory of 9 + * this archive for more details. 10 + */ 11 + 12 + #include <linux/ptrace.h> 13 + #include <linux/signal.h> 14 + #include <asm/unistd.h> 15 + 16 + void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, 17 + int has_handler) 18 + { 19 + unsigned long ret = regs->gpr[3]; 20 + int restart = 1; 21 + 22 + /* syscall ? */ 23 + if (TRAP(regs) != 0x0C00) 24 + return; 25 + 26 + /* error signalled ? */ 27 + if (!(regs->ccr & 0x10000000)) 28 + return; 29 + 30 + switch (ret) { 31 + case ERESTART_RESTARTBLOCK: 32 + case ERESTARTNOHAND: 33 + /* ERESTARTNOHAND means that the syscall should only be 34 + * restarted if there was no handler for the signal, and since 35 + * we only get here if there is a handler, we dont restart. 36 + */ 37 + restart = !has_handler; 38 + break; 39 + case ERESTARTSYS: 40 + /* ERESTARTSYS means to restart the syscall if there is no 41 + * handler or the handler was registered with SA_RESTART 42 + */ 43 + restart = !has_handler || (ka->sa.sa_flags & SA_RESTART) != 0; 44 + break; 45 + case ERESTARTNOINTR: 46 + /* ERESTARTNOINTR means that the syscall should be 47 + * called again after the signal handler returns. 48 + */ 49 + break; 50 + default: 51 + return; 52 + } 53 + if (restart) { 54 + if (ret == ERESTART_RESTARTBLOCK) 55 + regs->gpr[0] = __NR_restart_syscall; 56 + else 57 + regs->gpr[3] = regs->orig_gpr3; 58 + regs->nip -= 4; 59 + regs->result = 0; 60 + } else { 61 + regs->result = -EINTR; 62 + regs->gpr[3] = EINTR; 63 + regs->ccr |= 0x10000000; 64 + } 65 + }
+16
arch/powerpc/kernel/signal.h
··· 1 + /* 2 + * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration 3 + * Extracted from signal_32.c and signal_64.c 4 + * 5 + * This file is subject to the terms and conditions of the GNU General 6 + * Public License. See the file README.legal in the main directory of 7 + * this archive for more details. 8 + */ 9 + 10 + #ifndef _POWERPC_ARCH_SIGNAL_H 11 + #define _POWERPC_ARCH_SIGNAL_H 12 + 13 + extern void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, 14 + int has_handler); 15 + 16 + #endif /* _POWERPC_ARCH_SIGNAL_H */
+4 -24
arch/powerpc/kernel/signal_32.c
··· 51 51 #include <asm/pgtable.h> 52 52 #endif 53 53 54 + #include "signal.h" 55 + 54 56 #undef DEBUG_SIG 55 57 56 58 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) ··· 1158 1156 #ifdef CONFIG_PPC32 1159 1157 no_signal: 1160 1158 #endif 1161 - if (TRAP(regs) == 0x0C00 /* System Call! */ 1162 - && regs->ccr & 0x10000000 /* error signalled */ 1163 - && ((ret = regs->gpr[3]) == ERESTARTSYS 1164 - || ret == ERESTARTNOHAND || ret == ERESTARTNOINTR 1165 - || ret == ERESTART_RESTARTBLOCK)) { 1166 - 1167 - if (signr > 0 1168 - && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK 1169 - || (ret == ERESTARTSYS 1170 - && !(ka.sa.sa_flags & SA_RESTART)))) { 1171 - /* make the system call return an EINTR error */ 1172 - regs->result = -EINTR; 1173 - regs->gpr[3] = EINTR; 1174 - /* note that the cr0.SO bit is already set */ 1175 - } else { 1176 - regs->nip -= 4; /* Back up & retry system call */ 1177 - regs->result = 0; 1178 - regs->trap = 0; 1179 - if (ret == ERESTART_RESTARTBLOCK) 1180 - regs->gpr[0] = __NR_restart_syscall; 1181 - else 1182 - regs->gpr[3] = regs->orig_gpr3; 1183 - } 1184 - } 1159 + /* Is there any syscall restart business here ? */ 1160 + check_syscall_restart(regs, &ka, signr > 0); 1185 1161 1186 1162 if (signr == 0) { 1187 1163 /* No signal to deliver -- put the saved sigmask back */
+7 -52
arch/powerpc/kernel/signal_64.c
··· 34 34 #include <asm/syscalls.h> 35 35 #include <asm/vdso.h> 36 36 37 + #include "signal.h" 38 + 37 39 #define DEBUG_SIG 0 38 40 39 41 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) ··· 465 463 return ret; 466 464 } 467 465 468 - static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) 469 - { 470 - switch ((int)regs->result) { 471 - case -ERESTART_RESTARTBLOCK: 472 - case -ERESTARTNOHAND: 473 - /* ERESTARTNOHAND means that the syscall should only be 474 - * restarted if there was no handler for the signal, and since 475 - * we only get here if there is a handler, we dont restart. 476 - */ 477 - regs->result = -EINTR; 478 - regs->gpr[3] = EINTR; 479 - regs->ccr |= 0x10000000; 480 - break; 481 - case -ERESTARTSYS: 482 - /* ERESTARTSYS means to restart the syscall if there is no 483 - * handler or the handler was registered with SA_RESTART 484 - */ 485 - if (!(ka->sa.sa_flags & SA_RESTART)) { 486 - regs->result = -EINTR; 487 - regs->gpr[3] = EINTR; 488 - regs->ccr |= 0x10000000; 489 - break; 490 - } 491 - /* fallthrough */ 492 - case -ERESTARTNOINTR: 493 - /* ERESTARTNOINTR means that the syscall should be 494 - * called again after the signal handler returns. 495 - */ 496 - regs->gpr[3] = regs->orig_gpr3; 497 - regs->nip -= 4; 498 - regs->result = 0; 499 - break; 500 - } 501 - } 502 - 503 466 /* 504 467 * Note that 'init' is a special process: it doesn't get signals it doesn't 505 468 * want to handle. Thus you cannot kill init even with a SIGKILL even by ··· 489 522 oldset = &current->blocked; 490 523 491 524 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 525 + 526 + /* Is there any syscall restart business here ? */ 527 + check_syscall_restart(regs, &ka, signr > 0); 528 + 492 529 if (signr > 0) { 493 530 int ret; 494 - 495 - /* Whee! Actually deliver the signal. */ 496 - if (TRAP(regs) == 0x0C00) 497 - syscall_restart(regs, &ka); 498 531 499 532 /* 500 533 * Reenable the DABR before delivering the signal to ··· 504 537 if (current->thread.dabr) 505 538 set_dabr(current->thread.dabr); 506 539 540 + /* Whee! Actually deliver the signal. */ 507 541 ret = handle_signal(signr, &ka, &info, oldset, regs); 508 542 509 543 /* If a signal was successfully delivered, the saved sigmask is in ··· 515 547 return ret; 516 548 } 517 549 518 - if (TRAP(regs) == 0x0C00) { /* System Call! */ 519 - if ((int)regs->result == -ERESTARTNOHAND || 520 - (int)regs->result == -ERESTARTSYS || 521 - (int)regs->result == -ERESTARTNOINTR) { 522 - regs->gpr[3] = regs->orig_gpr3; 523 - regs->nip -= 4; /* Back up & retry system call */ 524 - regs->result = 0; 525 - } else if ((int)regs->result == -ERESTART_RESTARTBLOCK) { 526 - regs->gpr[0] = __NR_restart_syscall; 527 - regs->nip -= 4; 528 - regs->result = 0; 529 - } 530 - } 531 550 /* No signal to deliver -- put the saved sigmask back */ 532 551 if (test_thread_flag(TIF_RESTORE_SIGMASK)) { 533 552 clear_thread_flag(TIF_RESTORE_SIGMASK);