crtools uses a parasite code for dumping processes. The parasite code is injected into a process with help PTRACE_SEIZE. Currently crtools blocks signals from a parasite code. If a process has pending signals, crtools wait while a process handles these signals. This method is not suitable for stopped tasks. A stopped task can have a few pending signals, when we will try to execute a parasite code, we will need to drop SIGSTOP, but all other signals must remain pending, because a state of processes must not be changed during checkpointing. This patch adds two ptrace commands to set/get signal-blocked mask. I think gdb can use this commands too. [akpm@linux-foundation.org: be consistent with brace layout] Signed-off-by: Andrey Vagin <avagin@openvz.org> Reviewed-by: Oleg Nesterov <oleg@redhat.com> Cc: Roland McGrath <roland@redhat.com> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Cc: Pavel Emelyanov <xemul@parallels.com> Cc: Cyrill Gorcunov <gorcunov@openvz.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Unified · Split
| @@ -61,6 +61,9 @@ struct ptrace_peeksiginfo_args { · 60 unmodified lines | ||
| 61 | 61 | __s32 nr; /* how may siginfos to take */ |
| 62 | 62 | }; |
| 63 | 63 | |
| 64 | +#define PTRACE_GETSIGMASK 0x420a | |
| 65 | +#define PTRACE_SETSIGMASK 0x420b | |
| 66 | + | |
| 64 | 67 | /* Read signals from a shared (process wide) queue */ |
| 65 | 68 | #define PTRACE_PEEKSIGINFO_SHARED (1 << 0) |
| 66 | 69 | |
| @@ -844,6 +844,47 @@ int ptrace_request(struct task_struct *child, long request, · 843 unmodified lines | ||
| 844 | 844 | ret = ptrace_setsiginfo(child, &siginfo); |
| 845 | 845 | break; |
| 846 | 846 | |
| 847 | + case PTRACE_GETSIGMASK: | |
| 848 | + if (addr != sizeof(sigset_t)) { | |
| 849 | + ret = -EINVAL; | |
| 850 | + break; | |
| 851 | + } | |
| 852 | + | |
| 853 | + if (copy_to_user(datavp, &child->blocked, sizeof(sigset_t))) | |
| 854 | + ret = -EFAULT; | |
| 855 | + else | |
| 856 | + ret = 0; | |
| 857 | + | |
| 858 | + break; | |
| 859 | + | |
| 860 | + case PTRACE_SETSIGMASK: { | |
| 861 | + sigset_t new_set; | |
| 862 | + | |
| 863 | + if (addr != sizeof(sigset_t)) { | |
| 864 | + ret = -EINVAL; | |
| 865 | + break; | |
| 866 | + } | |
| 867 | + | |
| 868 | + if (copy_from_user(&new_set, datavp, sizeof(sigset_t))) { | |
| 869 | + ret = -EFAULT; | |
| 870 | + break; | |
| 871 | + } | |
| 872 | + | |
| 873 | + sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); | |
| 874 | + | |
| 875 | + /* | |
| 876 | + * Every thread does recalc_sigpending() after resume, so | |
| 877 | + * retarget_shared_pending() and recalc_sigpending() are not | |
| 878 | + * called here. | |
| 879 | + */ | |
| 880 | + spin_lock_irq(&child->sighand->siglock); | |
| 881 | + child->blocked = new_set; | |
| 882 | + spin_unlock_irq(&child->sighand->siglock); | |
| 883 | + | |
| 884 | + ret = 0; | |
| 885 | + break; | |
| 886 | + } | |
| 887 | + | |
| 847 | 888 | case PTRACE_INTERRUPT: |
| 848 | 889 | /* |
| 849 | 890 | * Stop tracee without any side-effect on signal or job |
| @@ -948,8 +989,7 @@ int ptrace_request(struct task_struct *child, long request, · 98 unmodified lines | ||
| 948 | 989 | |
| 949 | 990 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
| 950 | 991 | case PTRACE_GETREGSET: |
| 951 | − case PTRACE_SETREGSET: | |
| 952 | − { | |
| 992 | + case PTRACE_SETREGSET: { | |
| 953 | 993 | struct iovec kiov; |
| 954 | 994 | struct iovec __user *uiov = datavp; |
| 955 | 995 | |