2011-09-23 12:00:45 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
2011-10-13 19:43:52 +04:00
|
|
|
#include <getopt.h>
|
|
|
|
#include <string.h>
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include "types.h"
|
|
|
|
|
|
|
|
#include "compiler.h"
|
|
|
|
#include "crtools.h"
|
|
|
|
#include "util.h"
|
2011-12-19 18:52:50 +04:00
|
|
|
#include "log.h"
|
2011-12-26 22:12:03 +04:00
|
|
|
#include "sockets.h"
|
2012-01-31 22:28:22 +04:00
|
|
|
#include "syscall.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-10-04 01:50:19 +04:00
|
|
|
static struct cr_options opts;
|
2011-09-23 12:00:45 +04:00
|
|
|
struct page_entry zero_page_entry;
|
2011-12-16 18:02:02 +04:00
|
|
|
char image_dir[PATH_MAX];
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-10-13 13:33:32 +04:00
|
|
|
/*
|
|
|
|
* The cr fd set is the set of files where the information
|
|
|
|
* about dumped processes is stored. Each file carries some
|
|
|
|
* small portion of info about the whole picture, see below
|
|
|
|
* for more details.
|
|
|
|
*/
|
|
|
|
|
2011-11-15 18:35:55 +04:00
|
|
|
struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {
|
2011-10-13 13:33:32 +04:00
|
|
|
|
|
|
|
/* info about file descriptiors */
|
2011-09-23 12:00:45 +04:00
|
|
|
[CR_FD_FDINFO] = {
|
2011-11-15 18:35:55 +04:00
|
|
|
.fmt = FMT_FNAME_FDINFO,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = FDINFO_MAGIC,
|
|
|
|
},
|
2011-10-13 13:33:32 +04:00
|
|
|
|
|
|
|
/* private memory pages data */
|
2011-09-23 12:00:45 +04:00
|
|
|
[CR_FD_PAGES] = {
|
2011-11-15 18:35:55 +04:00
|
|
|
.fmt = FMT_FNAME_PAGES,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = PAGES_MAGIC,
|
|
|
|
},
|
2011-10-13 13:33:32 +04:00
|
|
|
|
|
|
|
/* shared memory pages data */
|
2011-09-23 12:00:45 +04:00
|
|
|
[CR_FD_PAGES_SHMEM] = {
|
2011-11-15 18:35:55 +04:00
|
|
|
.fmt = FMT_FNAME_PAGES_SHMEM,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = PAGES_MAGIC,
|
|
|
|
},
|
2011-10-13 13:33:32 +04:00
|
|
|
|
2011-11-15 18:35:55 +04:00
|
|
|
/* core data, such as regs and vmas and such */
|
2011-09-23 12:00:45 +04:00
|
|
|
[CR_FD_CORE] = {
|
2011-11-15 18:35:55 +04:00
|
|
|
.fmt = FMT_FNAME_CORE,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = CORE_MAGIC,
|
|
|
|
},
|
2011-10-13 13:33:32 +04:00
|
|
|
|
|
|
|
/* info about pipes - fds, pipe id and pipe data */
|
2011-09-23 12:00:45 +04:00
|
|
|
[CR_FD_PIPES] = {
|
2011-11-15 18:35:55 +04:00
|
|
|
.fmt = FMT_FNAME_PIPES,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = PIPES_MAGIC,
|
|
|
|
},
|
2011-10-13 13:33:32 +04:00
|
|
|
|
|
|
|
/* info about process linkage */
|
2011-09-23 12:00:45 +04:00
|
|
|
[CR_FD_PSTREE] = {
|
2011-11-15 18:35:55 +04:00
|
|
|
.fmt = FMT_FNAME_PSTREE,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = PSTREE_MAGIC,
|
|
|
|
},
|
2011-10-13 13:33:32 +04:00
|
|
|
|
|
|
|
/* info about which memory areas are shared */
|
2011-09-23 12:00:45 +04:00
|
|
|
[CR_FD_SHMEM] = {
|
2011-11-15 18:35:55 +04:00
|
|
|
.fmt = FMT_FNAME_SHMEM,
|
2011-09-23 12:00:45 +04:00
|
|
|
.magic = SHMEM_MAGIC,
|
|
|
|
},
|
2011-11-29 15:12:25 +03:00
|
|
|
|
2011-11-30 23:33:28 +04:00
|
|
|
/* info about signal handlers */
|
2011-11-29 15:12:25 +03:00
|
|
|
[CR_FD_SIGACT] = {
|
|
|
|
.fmt = FMT_FNAME_SIGACTS,
|
|
|
|
.magic = SIGACT_MAGIC,
|
|
|
|
},
|
2011-12-26 22:12:03 +04:00
|
|
|
|
|
|
|
/* info about unix sockets */
|
|
|
|
[CR_FD_UNIXSK] = {
|
|
|
|
.fmt = FMT_FNAME_UNIXSK,
|
|
|
|
.magic = UNIXSK_MAGIC,
|
|
|
|
},
|
2012-01-17 21:30:00 +04:00
|
|
|
|
|
|
|
/* info about inet sockets */
|
|
|
|
[CR_FD_INETSK] = {
|
|
|
|
.fmt = FMT_FNAME_INETSK,
|
|
|
|
.magic = INETSK_MAGIC,
|
|
|
|
},
|
|
|
|
|
2012-01-24 16:45:19 +04:00
|
|
|
/* interval timers (itimers) */
|
|
|
|
[CR_FD_ITIMERS] = {
|
|
|
|
.fmt = FMT_FNAME_ITIMERS,
|
|
|
|
.magic = ITIMERS_MAGIC,
|
|
|
|
},
|
2012-01-26 15:28:00 +04:00
|
|
|
|
2012-01-27 21:43:32 +04:00
|
|
|
/* creds */
|
|
|
|
[CR_FD_CREDS] = {
|
|
|
|
.fmt = FMT_FNAME_CREDS,
|
|
|
|
.magic = CREDS_MAGIC,
|
|
|
|
},
|
|
|
|
|
2012-01-26 15:28:00 +04:00
|
|
|
/* UTS namespace */
|
|
|
|
[CR_FD_UTSNS] = {
|
|
|
|
.fmt = FMT_FNAME_UTSNS,
|
|
|
|
.magic = UTSNS_MAGIC,
|
|
|
|
},
|
2012-01-31 22:28:55 +04:00
|
|
|
|
2012-02-08 12:13:38 +03:00
|
|
|
/* IPC namespace variables */
|
|
|
|
[CR_FD_IPCNS_VAR] = {
|
|
|
|
.fmt = FMT_FNAME_IPCNS_VAR,
|
|
|
|
.magic = IPCNS_VAR_MAGIC,
|
2012-01-31 22:28:55 +04:00
|
|
|
},
|
2011-09-23 12:00:45 +04:00
|
|
|
};
|
|
|
|
|
2012-01-12 15:18:32 +04:00
|
|
|
static struct cr_fdset *alloc_cr_fdset(void)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct cr_fdset *cr_fdset;
|
|
|
|
unsigned int i;
|
|
|
|
|
2012-01-12 15:17:51 +04:00
|
|
|
cr_fdset = xmalloc(sizeof(*cr_fdset));
|
|
|
|
if (cr_fdset)
|
|
|
|
for (i = 0; i < CR_FD_MAX; i++)
|
|
|
|
cr_fdset->fds[i] = -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
return cr_fdset;
|
|
|
|
}
|
|
|
|
|
2012-01-31 18:26:51 +04:00
|
|
|
void __close_cr_fdset(struct cr_fdset *cr_fdset)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (!cr_fdset)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < CR_FD_MAX; i++) {
|
|
|
|
if (cr_fdset->fds[i] == -1)
|
|
|
|
continue;
|
|
|
|
pr_debug("Closed %d/%d\n", i, cr_fdset->fds[i]);
|
|
|
|
close_safe(&cr_fdset->fds[i]);
|
|
|
|
cr_fdset->fds[i] = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void close_cr_fdset(struct cr_fdset **cr_fdset)
|
|
|
|
{
|
|
|
|
if (!cr_fdset || !*cr_fdset)
|
|
|
|
return;
|
|
|
|
|
|
|
|
__close_cr_fdset(*cr_fdset);
|
|
|
|
|
|
|
|
xfree(*cr_fdset);
|
|
|
|
*cr_fdset = NULL;
|
|
|
|
}
|
|
|
|
|
2012-02-08 20:19:39 +03:00
|
|
|
static struct cr_fdset *cr_fdset_open(int pid, unsigned long use_mask,
|
|
|
|
unsigned long flags, struct cr_fdset *cr_fdset)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2012-01-31 18:26:51 +04:00
|
|
|
struct cr_fdset *fdset;
|
2011-09-23 12:00:45 +04:00
|
|
|
unsigned int i;
|
|
|
|
int ret = -1;
|
2012-01-12 15:17:51 +04:00
|
|
|
char path[PATH_MAX];
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-01-31 18:26:51 +04:00
|
|
|
/*
|
|
|
|
* We either reuse existing fdset or create new one.
|
|
|
|
*/
|
|
|
|
if (!cr_fdset) {
|
|
|
|
fdset = alloc_cr_fdset();
|
|
|
|
if (!fdset)
|
2012-01-22 20:15:11 +04:00
|
|
|
goto err;
|
2012-01-31 18:26:51 +04:00
|
|
|
} else
|
|
|
|
fdset = cr_fdset;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
for (i = 0; i < CR_FD_MAX; i++) {
|
|
|
|
if (!(use_mask & CR_FD_DESC_USE(i)))
|
|
|
|
continue;
|
2012-01-31 18:26:51 +04:00
|
|
|
|
|
|
|
if (fdset->fds[i] != -1)
|
2012-01-22 20:15:11 +04:00
|
|
|
continue;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-01-12 15:17:51 +04:00
|
|
|
ret = get_image_path(path, sizeof(path),
|
|
|
|
fdset_template[i].fmt, pid);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
|
2012-02-08 20:19:39 +03:00
|
|
|
if (flags & O_EXCL) {
|
|
|
|
ret = unlink(path);
|
|
|
|
if (ret && errno != ENOENT) {
|
|
|
|
pr_perror("Unable to unlink %s", path);
|
|
|
|
goto err;
|
|
|
|
}
|
2012-01-30 21:18:37 +04:00
|
|
|
}
|
2012-01-12 15:17:51 +04:00
|
|
|
|
2012-02-08 20:19:39 +03:00
|
|
|
ret = open(path, flags, CR_FD_PERM);
|
2012-01-12 15:17:51 +04:00
|
|
|
if (ret < 0) {
|
2012-02-08 20:19:39 +03:00
|
|
|
if (!(flags & O_CREAT))
|
|
|
|
/* caller should check himself */
|
|
|
|
continue;
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Unable to open %s", path);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2012-01-31 18:26:51 +04:00
|
|
|
fdset->fds[i] = ret;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-01-12 15:17:51 +04:00
|
|
|
pr_debug("Opened %s with %d\n", path, ret);
|
2012-02-08 20:19:39 +03:00
|
|
|
if (flags == O_RDONLY) {
|
|
|
|
u32 magic;
|
|
|
|
|
|
|
|
if (read_img(ret, &magic) < 0)
|
|
|
|
goto err;
|
|
|
|
if (magic != fdset_template[i].magic) {
|
|
|
|
pr_err("Magic doesn't match for %s\n", path);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (write_img(ret, &fdset_template[i].magic))
|
|
|
|
goto err;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
2012-01-31 18:26:51 +04:00
|
|
|
|
|
|
|
return fdset;
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
err:
|
2012-01-31 18:26:51 +04:00
|
|
|
if (fdset != cr_fdset)
|
|
|
|
__close_cr_fdset(fdset);
|
|
|
|
else
|
|
|
|
close_cr_fdset(&fdset);
|
|
|
|
return NULL;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-02-08 20:19:39 +03:00
|
|
|
struct cr_fdset *cr_dump_fdset_open(int pid, unsigned long use_mask,
|
|
|
|
struct cr_fdset *cr_fdset)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2012-02-08 20:19:39 +03:00
|
|
|
return cr_fdset_open(pid, use_mask, O_RDWR | O_CREAT | O_EXCL,
|
|
|
|
cr_fdset);
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-02-08 20:19:39 +03:00
|
|
|
struct cr_fdset *cr_show_fdset_open(int pid, unsigned long use_mask)
|
|
|
|
{
|
|
|
|
return cr_fdset_open(pid, use_mask, O_RDONLY, NULL);
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-01-31 22:28:22 +04:00
|
|
|
static int parse_ns_string(const char *ptr, unsigned int *flags)
|
|
|
|
{
|
|
|
|
const char *end = ptr + strlen(ptr);
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (ptr[3] != ',' && ptr[3] != '\0')
|
|
|
|
goto bad_ns;
|
|
|
|
if (!strncmp(ptr, "uts", 3))
|
|
|
|
opts.namespaces_flags |= CLONE_NEWUTS;
|
2012-01-31 22:28:55 +04:00
|
|
|
else if (!strncmp(ptr, "ipc", 3))
|
|
|
|
opts.namespaces_flags |= CLONE_NEWIPC;
|
2012-01-31 22:28:22 +04:00
|
|
|
else
|
|
|
|
goto bad_ns;
|
|
|
|
ptr += 4;
|
|
|
|
} while (ptr < end);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bad_ns:
|
|
|
|
pr_err("Unknown namespace '%s'\n", ptr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2011-12-28 20:39:00 +04:00
|
|
|
pid_t pid = 0;
|
2011-09-23 12:00:45 +04:00
|
|
|
int ret = -1;
|
2011-10-13 19:43:52 +04:00
|
|
|
int opt, idx;
|
|
|
|
int action = -1;
|
2011-12-08 18:39:00 +04:00
|
|
|
int log_inited = 0;
|
2011-10-13 19:43:52 +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
|
|
|
static const char short_opts[] = "dsf:p:t:hcD:o:n:";
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE);
|
|
|
|
|
|
|
|
if (argc < 3)
|
|
|
|
goto usage;
|
|
|
|
|
2012-01-18 18:53:49 +03:00
|
|
|
action = argv[1][0];
|
|
|
|
|
2011-10-23 00:55:26 +04:00
|
|
|
memzero_p(&zero_page_entry);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-11-22 22:09:28 +04:00
|
|
|
/* Default options */
|
2011-12-09 12:37:08 +04:00
|
|
|
opts.final_state = CR_TASK_KILL;
|
2011-11-22 22:09:28 +04:00
|
|
|
|
2012-01-18 18:53:49 +03:00
|
|
|
for (opt = getopt_long(argc - 1, argv + 1, short_opts, NULL, &idx); opt != -1;
|
|
|
|
opt = getopt_long(argc - 1, argv + 1, short_opts, NULL, &idx)) {
|
2011-10-13 19:43:52 +04:00
|
|
|
switch (opt) {
|
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
|
|
|
case 's':
|
|
|
|
opts.final_state = CR_TASK_STOP;
|
|
|
|
break;
|
2011-10-13 19:43:52 +04:00
|
|
|
case 'p':
|
|
|
|
pid = atoi(optarg);
|
|
|
|
opts.leader_only = true;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
pid = atoi(optarg);
|
|
|
|
opts.leader_only = false;
|
|
|
|
break;
|
2011-12-05 15:57:47 +04:00
|
|
|
case 'c':
|
|
|
|
opts.show_pages_content = true;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
opts.show_dump_file = optarg;
|
|
|
|
break;
|
2012-01-18 23:24:37 +04:00
|
|
|
case 'd':
|
|
|
|
opts.restore_detach = true;
|
|
|
|
break;
|
2011-12-07 13:48:00 +04:00
|
|
|
case 'D':
|
|
|
|
if (chdir(optarg)) {
|
2012-02-01 02:08:04 +04:00
|
|
|
pr_perror("Can't change directory to %s",
|
|
|
|
optarg);
|
2011-12-19 16:51:26 +04:00
|
|
|
return -1;
|
2011-12-07 13:48:00 +04:00
|
|
|
}
|
|
|
|
break;
|
2011-12-08 18:39:00 +04:00
|
|
|
case 'o':
|
2011-12-19 18:52:50 +04:00
|
|
|
if (init_log(optarg))
|
2011-12-19 16:51:26 +04:00
|
|
|
return -1;
|
2011-12-08 18:39:00 +04:00
|
|
|
log_inited = 1;
|
|
|
|
break;
|
2012-01-26 15:27:00 +04:00
|
|
|
case 'n':
|
2012-01-31 22:28:22 +04:00
|
|
|
if (parse_ns_string(optarg, &opts.namespaces_flags))
|
|
|
|
return -1;
|
2012-01-26 15:27:00 +04:00
|
|
|
break;
|
2011-10-13 19:43:52 +04:00
|
|
|
case 'h':
|
|
|
|
default:
|
|
|
|
goto usage;
|
|
|
|
}
|
2011-10-04 01:50:19 +04:00
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-12-13 15:03:33 +04:00
|
|
|
if (!log_inited) {
|
2011-12-19 18:52:50 +04:00
|
|
|
ret = init_log(NULL);
|
2011-12-13 15:03:33 +04:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
2011-12-08 18:39:00 +04:00
|
|
|
|
2011-12-13 15:07:06 +04:00
|
|
|
if (!getcwd(image_dir, sizeof(image_dir))) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("can't get currect directory");
|
2011-12-13 15:03:33 +04:00
|
|
|
return -1;
|
2011-12-07 13:48:00 +04:00
|
|
|
}
|
|
|
|
|
2011-12-28 20:39:00 +04:00
|
|
|
if (!pid && (action != 's' || !opts.show_dump_file))
|
|
|
|
goto opt_pid_missing;
|
2011-12-20 19:26:37 +04:00
|
|
|
|
2012-01-18 18:53:49 +03:00
|
|
|
if (strcmp(argv[1], "dump") &&
|
|
|
|
strcmp(argv[1], "restore") &&
|
|
|
|
strcmp(argv[1], "show")) {
|
|
|
|
pr_err("Unknown command");
|
|
|
|
goto usage;
|
|
|
|
}
|
|
|
|
|
2011-10-13 19:43:52 +04:00
|
|
|
switch (action) {
|
|
|
|
case 'd':
|
2011-10-04 01:50:19 +04:00
|
|
|
ret = cr_dump_tasks(pid, &opts);
|
2011-10-13 19:43:52 +04:00
|
|
|
break;
|
|
|
|
case 'r':
|
2011-10-04 01:50:19 +04:00
|
|
|
ret = cr_restore_tasks(pid, &opts);
|
2011-10-13 19:43:52 +04:00
|
|
|
break;
|
|
|
|
case 's':
|
2011-10-04 01:50:19 +04:00
|
|
|
ret = cr_show(pid, &opts);
|
2011-10-13 19:43:52 +04:00
|
|
|
break;
|
|
|
|
default:
|
2011-09-23 12:00:45 +04:00
|
|
|
goto usage;
|
2011-10-13 19:43:52 +04:00
|
|
|
break;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
usage:
|
|
|
|
printk("\nUsage:\n");
|
2012-01-31 22:28:40 +04:00
|
|
|
printk(" %s dump [-c] -p|-t pid [-n ns]\n", argv[0]);
|
|
|
|
printk(" %s restore -p|-t pid [-n ns]\n", argv[0]);
|
2012-01-18 18:53:49 +03:00
|
|
|
printk(" %s show [-c] (-p|-t pid)|(-f file)\n", argv[0]);
|
|
|
|
|
|
|
|
printk("\nCommands:\n");
|
|
|
|
printk(" dump checkpoint a process identified by pid\n");
|
|
|
|
printk(" restore restore a process identified by pid\n");
|
|
|
|
printk(" show show dump contents of a process identified by pid\n");
|
2011-12-18 12:06:08 +04:00
|
|
|
printk("\nGeneral parameters:\n");
|
|
|
|
printk(" -p checkpoint/restore only a single process identified by pid\n");
|
|
|
|
printk(" -t checkpoint/restore the whole process tree identified by pid\n");
|
|
|
|
printk(" -f show contents of a checkpoint file\n");
|
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
|
|
|
printk(" -c show contents of pages dumped in hexdump format\n");
|
2012-01-18 23:24:37 +04:00
|
|
|
printk(" -d detach after restore\n");
|
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
|
|
|
printk(" -s leave tasks in stopped state after checkpoint instead of killing them\n");
|
2012-01-31 22:28:40 +04:00
|
|
|
printk(" -n checkpoint/restore namespaces - values must be separated by comma\n");
|
2012-01-31 22:29:22 +04:00
|
|
|
printk(" supported: uts, ipc\n");
|
2011-12-18 12:06:08 +04:00
|
|
|
|
|
|
|
printk("\nAdditional common parameters:\n");
|
|
|
|
printk(" -D dir save checkpoint files in specified directory\n");
|
2011-12-05 15:57:47 +04:00
|
|
|
printk("\n");
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
return -1;
|
2011-12-20 19:47:06 +04:00
|
|
|
|
|
|
|
opt_pid_missing:
|
2012-02-01 02:08:04 +04:00
|
|
|
printk("No pid specified (-t or -p option missing)\n");
|
2011-12-20 19:47:06 +04:00
|
|
|
return -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|