2011-12-19 21:57:59 +04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/resource.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
|
|
|
#include "compiler.h"
|
2013-01-09 17:02:47 +04:00
|
|
|
#include "asm/types.h"
|
2011-12-19 21:57:59 +04:00
|
|
|
#include "util.h"
|
|
|
|
#include "ptrace.h"
|
2012-03-01 19:03:09 +04:00
|
|
|
#include "proc_parse.h"
|
2011-12-19 21:57:59 +04:00
|
|
|
|
2013-12-20 20:36:12 +04:00
|
|
|
int unseize_task(pid_t pid, int orig_st, int st)
|
2011-12-19 21:57:59 +04:00
|
|
|
{
|
2013-04-12 13:00:05 -07:00
|
|
|
pr_debug("\tUnseizing %d into %d\n", pid, st);
|
2012-04-11 15:17:26 +04:00
|
|
|
|
2012-03-01 19:09:02 +04:00
|
|
|
if (st == TASK_DEAD)
|
2012-02-01 22:06:51 +04:00
|
|
|
kill(pid, SIGKILL);
|
2013-12-20 20:36:12 +04:00
|
|
|
else if (st == TASK_STOPPED && orig_st == TASK_ALIVE)
|
2012-02-03 14:49:57 +04:00
|
|
|
kill(pid, SIGSTOP);
|
2012-03-01 19:09:02 +04:00
|
|
|
else if (st == TASK_ALIVE)
|
|
|
|
/* do nothing */ ;
|
2012-02-03 14:49:57 +04:00
|
|
|
else
|
|
|
|
pr_err("Unknown final state %d\n", st);
|
|
|
|
|
|
|
|
return ptrace(PTRACE_DETACH, pid, NULL, NULL);
|
2011-12-19 21:57:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This routine seizes task putting it into a special
|
|
|
|
* state where we can manipulate the task via ptrace
|
2013-04-12 13:00:06 -07:00
|
|
|
* interface, and finally we can detach ptrace out of
|
2011-12-19 21:57:59 +04:00
|
|
|
* of it so the task would not know if it was saddled
|
|
|
|
* up with someone else.
|
|
|
|
*/
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
|
2012-04-11 22:10:09 +04:00
|
|
|
int seize_task(pid_t pid, pid_t ppid, pid_t *pgid, pid_t *sid)
|
2011-12-19 21:57:59 +04:00
|
|
|
{
|
|
|
|
siginfo_t si;
|
|
|
|
int status;
|
2013-03-26 22:03:15 +04:00
|
|
|
int ret, ret2, ptrace_errno;
|
2012-03-01 19:04:31 +04:00
|
|
|
struct proc_pid_stat_small ps;
|
2011-12-19 21:57:59 +04:00
|
|
|
|
2012-04-25 21:33:09 +04:00
|
|
|
ret = ptrace(PTRACE_SEIZE, pid, NULL, 0);
|
2013-03-26 22:03:15 +04:00
|
|
|
ptrace_errno = errno;
|
2013-12-20 14:45:17 +04:00
|
|
|
if (ret == 0) {
|
2013-12-20 16:42:24 +04:00
|
|
|
/*
|
|
|
|
* If we SEIZE-d the task stop it before going
|
|
|
|
* and reading its stat from proc. Otherwise task
|
|
|
|
* may die _while_ we're doing it and we'll have
|
|
|
|
* inconsistent seize/state pair.
|
|
|
|
*
|
|
|
|
* If task dies after we seize it but before we
|
|
|
|
* do this interrupt, we'll notice it via proc.
|
|
|
|
*/
|
2013-12-20 14:45:17 +04:00
|
|
|
ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("SEIZE %d: can't interrupt task", pid);
|
|
|
|
ptrace(PTRACE_DETACH, pid, NULL, NULL);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
2012-04-11 22:10:09 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* It's ugly, but the ptrace API doesn't allow to distinguish
|
|
|
|
* attaching to zombie from other errors. Thus we have to parse
|
|
|
|
* the target's /proc/pid/stat. Sad, but parse whatever else
|
|
|
|
* we might nead at that early point.
|
|
|
|
*/
|
|
|
|
|
2012-03-01 19:04:31 +04:00
|
|
|
ret2 = parse_pid_stat_small(pid, &ps);
|
|
|
|
if (ret2 < 0)
|
|
|
|
return -1;
|
2012-03-01 19:03:09 +04:00
|
|
|
|
2012-04-11 22:10:09 +04:00
|
|
|
if (pgid)
|
|
|
|
*pgid = ps.pgid;
|
|
|
|
if (sid)
|
|
|
|
*sid = ps.sid;
|
|
|
|
|
2012-03-01 19:04:31 +04:00
|
|
|
if (ret < 0) {
|
2012-03-01 19:03:09 +04:00
|
|
|
if (ps.state != 'Z') {
|
2013-03-27 01:10:56 +04:00
|
|
|
if (pid == getpid())
|
2013-05-09 10:58:03 -07:00
|
|
|
pr_err("The criu itself is within dumped tree.\n");
|
2013-03-27 01:10:56 +04:00
|
|
|
else
|
2013-04-12 13:00:05 -07:00
|
|
|
pr_err("Unseizable non-zombie %d found, state %c, err %d/%d\n",
|
2013-03-27 01:10:56 +04:00
|
|
|
pid, ps.state, ret, ptrace_errno);
|
2012-03-01 19:03:09 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TASK_DEAD;
|
|
|
|
}
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
|
2012-03-01 19:04:31 +04:00
|
|
|
if ((ppid != -1) && (ps.ppid != ppid)) {
|
|
|
|
pr_err("Task pid reused while suspending (%d: %d -> %d)\n",
|
|
|
|
pid, ppid, ps.ppid);
|
|
|
|
goto err;
|
|
|
|
}
|
2013-04-23 20:55:20 +04:00
|
|
|
|
|
|
|
try_again:
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
ret = wait4(pid, &status, __WALL, NULL);
|
2012-01-19 19:21:16 +04:00
|
|
|
if (ret < 0) {
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
pr_perror("SEIZE %d: can't wait task", pid);
|
2012-01-19 19:21:16 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2011-12-19 21:57:59 +04:00
|
|
|
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
if (ret != pid) {
|
|
|
|
pr_err("SEIZE %d: wrong task attached (%d)\n", pid, ret);
|
2011-12-19 21:57:59 +04:00
|
|
|
goto err;
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
}
|
2011-12-19 21:57:59 +04:00
|
|
|
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
if (!WIFSTOPPED(status)) {
|
|
|
|
pr_err("SEIZE %d: task not stopped after seize\n", pid);
|
2011-12-19 21:57:59 +04:00
|
|
|
goto err;
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
}
|
2011-12-19 21:57:59 +04:00
|
|
|
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
ret = ptrace(PTRACE_GETSIGINFO, pid, NULL, &si);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("SEIZE %d: can't read signfo", pid);
|
|
|
|
goto err;
|
|
|
|
}
|
2011-12-19 21:57:59 +04:00
|
|
|
|
2012-04-25 21:34:05 +04:00
|
|
|
if (SI_EVENT(si.si_code) != PTRACE_EVENT_STOP) {
|
2012-03-01 20:25:39 +04:00
|
|
|
/*
|
|
|
|
* Kernel notifies us about the task being seized received some
|
|
|
|
* event other than the STOP, i.e. -- a signal. Let the task
|
|
|
|
* handle one and repeat.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (ptrace(PTRACE_CONT, pid, NULL,
|
|
|
|
(void *)(unsigned long)si.si_signo)) {
|
2013-12-12 22:15:00 +04:00
|
|
|
pr_perror("Can't continue signal handling, aborting");
|
2012-03-01 20:25:39 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto try_again;
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
}
|
2011-12-19 21:57:59 +04:00
|
|
|
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
if (si.si_signo == SIGTRAP)
|
|
|
|
return TASK_ALIVE;
|
2013-10-01 11:21:34 +04:00
|
|
|
else if (si.si_signo == SIGSTOP) {
|
|
|
|
/*
|
|
|
|
* PTRACE_SEIZE doesn't affect signal or group stop state.
|
|
|
|
* Currently ptrace reported that task is in stopped state.
|
|
|
|
* We need to start task again, and it will be trapped
|
|
|
|
* immediately, because we sent PTRACE_INTERRUPT to it.
|
|
|
|
*/
|
|
|
|
ret = ptrace(PTRACE_CONT, pid, 0, 0);
|
|
|
|
if (ret) {
|
|
|
|
pr_perror("Unable to start process");
|
2013-12-20 14:45:17 +04:00
|
|
|
goto err_stop;
|
2013-10-01 11:21:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = wait4(pid, &status, __WALL, NULL);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("SEIZE %d: can't wait task", pid);
|
2013-12-20 14:45:17 +04:00
|
|
|
goto err_stop;
|
2013-10-01 11:21:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ret != pid) {
|
|
|
|
pr_err("SEIZE %d: wrong task attached (%d)\n", pid, ret);
|
2013-12-20 14:45:17 +04:00
|
|
|
goto err_stop;
|
2013-10-01 11:21:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!WIFSTOPPED(status)) {
|
|
|
|
pr_err("SEIZE %d: task not stopped after seize\n", pid);
|
2013-12-20 14:45:17 +04:00
|
|
|
goto err_stop;
|
2013-10-01 11:21:34 +04:00
|
|
|
}
|
|
|
|
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
return TASK_STOPPED;
|
2013-12-20 14:45:17 +04:00
|
|
|
} else {
|
|
|
|
pr_err("SEIZE %d: unsupported stop signal %d\n", pid, si.si_signo);
|
|
|
|
goto err;
|
2013-10-01 11:21:34 +04:00
|
|
|
}
|
2011-12-19 21:57:59 +04:00
|
|
|
|
2013-12-20 14:45:17 +04:00
|
|
|
err_stop:
|
|
|
|
kill(pid, SIGSTOP);
|
2011-12-19 21:57:59 +04:00
|
|
|
err:
|
2013-12-20 14:45:17 +04:00
|
|
|
ptrace(PTRACE_DETACH, pid, NULL, NULL);
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
return -1;
|
2011-12-19 21:57:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes)
|
|
|
|
{
|
|
|
|
unsigned long w;
|
|
|
|
if (bytes & (sizeof(long) - 1))
|
|
|
|
return -1;
|
|
|
|
for (w = 0; w < bytes / sizeof(long); w++) {
|
|
|
|
unsigned long *d = dst, *a = addr;
|
|
|
|
d[w] = ptrace(PTRACE_PEEKDATA, pid, a + w, NULL);
|
|
|
|
if (d[w] == -1U && errno)
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes)
|
|
|
|
{
|
|
|
|
unsigned long w;
|
|
|
|
if (bytes & (sizeof(long) - 1))
|
|
|
|
return -1;
|
|
|
|
for (w = 0; w < bytes / sizeof(long); w++) {
|
|
|
|
unsigned long *s = src, *a = addr;
|
|
|
|
if (ptrace(PTRACE_POKEDATA, pid, a + w, s[w]))
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
/* don't swap big space, it might overflow the stack */
|
|
|
|
int ptrace_swap_area(pid_t pid, void *dst, void *src, long bytes)
|
|
|
|
{
|
|
|
|
void *t = alloca(bytes);
|
|
|
|
|
|
|
|
if (ptrace_peek_area(pid, t, dst, bytes))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ptrace_poke_area(pid, src, dst, bytes)) {
|
|
|
|
if (ptrace_poke_area(pid, t, dst, bytes))
|
|
|
|
return -2;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(src, t, bytes);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|