Commit f9f69026 authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

parasite: allow to wait more than one process on the exit from syscall

All processes must be started by PTRACE_SYSCALL. The function calls wait
in a loop and if a process on the exit from the required syscall, it
is stopped, otherwise it will be reexecuted by PTRACE_SYSCALL.

The function doesn't know, which processes should be trapped, so
you should care, that wait() will not catch someone else.
Signed-off-by: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 833b1f95
......@@ -114,5 +114,5 @@ extern bool arch_can_dump_task(pid_t pid);
extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
struct vm_area_list *vma_area_list);
extern int parasite_stop_on_syscall(pid_t pid, int sys_nr);
extern int parasite_stop_on_syscall(int tasks, int sys_nr);
#endif /* __CR_PARASITE_SYSCALL_H__ */
......@@ -759,20 +759,28 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
if (ret)
return -1;
if (parasite_stop_on_syscall(pid, __NR_rt_sigreturn))
if (parasite_stop_on_syscall(1, __NR_rt_sigreturn))
return -1;
return 0;
}
int parasite_stop_on_syscall(pid_t pid, const int sys_nr)
/*
* Trap tasks on the exit from the specified syscall
*
* tasks - number of processes, which should be trapped
* sys_nr - the required syscall number
*/
int parasite_stop_on_syscall(int tasks, const int sys_nr)
{
user_regs_struct_t regs;
int status, ret;
pid_t pid;
/* Stop all threads on the enter point in sys_rt_sigreturn */
while (1) {
if (wait4(pid, &status, __WALL, NULL) < 0) {
while (tasks) {
pid = wait4(-1, &status, __WALL, NULL);
if (pid == -1) {
pr_perror("wait4 failed");
return -1;
}
......@@ -795,8 +803,30 @@ int parasite_stop_on_syscall(pid_t pid, const int sys_nr)
pr_debug("%d is going to execute the syscall %lx\n", pid, REG_SYSCALL_NR(regs));
if (REG_SYSCALL_NR(regs) == sys_nr) {
/*
* The process is going to execute the required syscall,
* the next stop will be on the exit from this syscall
*/
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
if (ret) {
pr_perror("ptrace");
return -1;
}
pid = wait4(pid, &status, __WALL, NULL);
if (pid == -1) {
pr_perror("wait4 failed");
return -1;
}
if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) {
pr_err("Task is in unexpected state: %x\n", status);
return -1;
}
pr_debug("%d was stopped\n", pid);
break;
tasks--;
continue;
}
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
......@@ -806,23 +836,6 @@ int parasite_stop_on_syscall(pid_t pid, const int sys_nr)
}
}
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
if (ret) {
pr_perror("ptrace");
return -1;
}
if (wait4(pid, &status, __WALL, NULL) != pid) {
pr_perror("wait4 failed");
return -1;
}
pr_debug("Trap %d\n", pid);
if (!WIFSTOPPED(status)) {
pr_err("%d\n", status);
return -1;
}
return 0;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment