2011-09-23 12:00:45 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2011-12-19 21:05:02 +04:00
|
|
|
#include <stdarg.h>
|
2011-09-23 12:00:45 +04:00
|
|
|
#include <signal.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
2012-01-27 21:35:59 +04:00
|
|
|
#include <parasite.h>
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/vfs.h>
|
|
|
|
|
|
|
|
#include <sys/sendfile.h>
|
|
|
|
|
2011-11-28 16:33:54 +03:00
|
|
|
#include <linux/major.h>
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
#include "types.h"
|
|
|
|
#include "list.h"
|
2012-02-28 18:27:28 +04:00
|
|
|
#include "file-ids.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
#include "compiler.h"
|
|
|
|
#include "crtools.h"
|
|
|
|
#include "syscall.h"
|
2011-12-19 21:57:59 +04:00
|
|
|
#include "ptrace.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
#include "util.h"
|
2011-12-26 22:12:03 +04:00
|
|
|
#include "sockets.h"
|
2012-01-26 15:27:00 +04:00
|
|
|
#include "namespaces.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
#include "image.h"
|
2012-01-13 20:52:35 +04:00
|
|
|
#include "proc_parse.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
#include "parasite-syscall.h"
|
|
|
|
|
|
|
|
#ifndef CONFIG_X86_64
|
|
|
|
# error No x86-32 support yet
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static char big_buffer[PATH_MAX];
|
|
|
|
static char loc_buf[PAGE_SIZE];
|
|
|
|
|
2011-12-05 15:57:47 +04:00
|
|
|
void free_pstree(struct list_head *pstree_list)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct pstree_item *item, *p;
|
|
|
|
|
2011-10-21 11:46:19 +04:00
|
|
|
list_for_each_entry_safe(item, p, pstree_list, list) {
|
2011-09-23 12:00:45 +04:00
|
|
|
xfree(item->children);
|
2011-10-20 11:03:19 +04:00
|
|
|
xfree(item->threads);
|
2011-09-23 12:00:45 +04:00
|
|
|
xfree(item);
|
|
|
|
}
|
|
|
|
|
2011-10-21 11:46:19 +04:00
|
|
|
INIT_LIST_HEAD(pstree_list);
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2011-10-26 22:48:10 +04:00
|
|
|
void free_mappings(struct list_head *vma_area_list)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct vma_area *vma_area, *p;
|
|
|
|
|
2011-10-21 12:14:45 +04:00
|
|
|
list_for_each_entry_safe(vma_area, p, vma_area_list, list) {
|
2011-09-23 12:00:45 +04:00
|
|
|
if (vma_area->vm_file_fd > 0)
|
|
|
|
close(vma_area->vm_file_fd);
|
|
|
|
free(vma_area);
|
|
|
|
}
|
|
|
|
|
2011-10-21 12:14:45 +04:00
|
|
|
INIT_LIST_HEAD(vma_area_list);
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
static int collect_mappings(pid_t pid, struct list_head *vma_area_list)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
pr_info("\n");
|
|
|
|
pr_info("Collecting mappings (pid: %d)\n", pid);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
ret = parse_maps(pid, vma_area_list, true);
|
2012-03-02 19:28:46 +04:00
|
|
|
if (ret < 0)
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
|
2011-10-21 12:14:45 +04:00
|
|
|
pr_info_vma_list(vma_area_list);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info("----------------------------------------\n");
|
2012-03-02 19:28:46 +04:00
|
|
|
ret = 0;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-01-12 22:00:45 +04:00
|
|
|
struct fd_parms {
|
2012-01-13 21:39:14 +04:00
|
|
|
unsigned long fd_name;
|
|
|
|
unsigned long pos;
|
|
|
|
unsigned int flags;
|
2012-03-01 20:56:27 +03:00
|
|
|
unsigned int type;
|
2012-02-28 18:27:28 +04:00
|
|
|
|
|
|
|
u64 id;
|
|
|
|
pid_t pid;
|
2012-01-12 22:00:45 +04:00
|
|
|
};
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_one_reg_file(const struct fd_parms *p, int lfd,
|
|
|
|
const struct cr_fdset *cr_fdset,
|
2012-01-13 21:39:14 +04:00
|
|
|
bool do_close_lfd)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct fdinfo_entry e;
|
|
|
|
char fd_str[128];
|
|
|
|
int len;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
snprintf(fd_str, sizeof(fd_str), "/proc/self/fd/%d", lfd);
|
|
|
|
len = readlink(fd_str, big_buffer, sizeof(big_buffer) - 1);
|
|
|
|
if (len < 0) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't readlink %s", fd_str);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
big_buffer[len] = '\0';
|
|
|
|
pr_info("Dumping path for %lx fd via self %d [%s]\n",
|
2012-01-12 22:00:45 +04:00
|
|
|
p->fd_name, lfd, big_buffer);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-01-12 23:50:45 +04:00
|
|
|
if (do_close_lfd)
|
2011-09-23 12:00:45 +04:00
|
|
|
close(lfd);
|
|
|
|
|
2012-03-01 20:56:27 +03:00
|
|
|
e.type = p->type;
|
2011-09-23 12:00:45 +04:00
|
|
|
e.len = len;
|
2012-01-12 22:00:45 +04:00
|
|
|
e.flags = p->flags;
|
|
|
|
e.pos = p->pos;
|
|
|
|
e.addr = p->fd_name;
|
2012-03-01 20:56:34 +03:00
|
|
|
e.id = FD_ID_INVALID;
|
2012-02-28 18:27:28 +04:00
|
|
|
|
|
|
|
if (likely(!fd_is_special(&e))) {
|
2012-02-29 19:22:35 +04:00
|
|
|
struct fd_id_entry *entry;
|
2012-02-28 18:27:28 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure the union is still correlate with structure
|
|
|
|
* we write to disk.
|
|
|
|
*/
|
2012-02-29 19:22:35 +04:00
|
|
|
BUILD_BUG_ON(sizeof(entry->u.key) != sizeof(e.id));
|
2012-02-28 18:27:28 +04:00
|
|
|
|
2012-02-29 19:22:35 +04:00
|
|
|
entry = fd_id_entry_collect((u32)p->id, p->pid, p->fd_name);
|
|
|
|
if (!entry)
|
2012-02-28 18:27:28 +04:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
/* Now it might have completely new ID here */
|
2012-02-29 19:22:35 +04:00
|
|
|
e.id = entry->u.id;
|
2012-03-01 20:56:34 +03:00
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
cr-dump.c: fix printf format warnings
cr-dump.c: In function ‘dump_one_reg_file’:
cr-dump.c:128:2: error: format ‘%8x’ expects type ‘unsigned int’, but argument 5 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_one_pipe’:
cr-dump.c:223:2: error: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 2 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 3 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 4 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 5 has type ‘u32’
cr-dump.c:240:3: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_one_fd’:
cr-dump.c:257:3: error: format ‘%d’ expects type ‘int’, but argument 5 has type ‘long unsigned int’
cr-dump.c:262:3: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c:272:4: error: format ‘%d’ expects type ‘int’, but argument 3 has type ‘long unsigned int’
cr-dump.c:286:4: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c:295:2: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_task_files’:
cr-dump.c:340:3: error: too few arguments for format
Signed-off-by: Kir Kolyshkin <kir@openvz.org>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-01-31 15:31:24 +04:00
|
|
|
pr_info("fdinfo: type: %2x len: %2x flags: %4x pos: %8lx addr: %16lx\n",
|
2012-03-01 20:56:27 +03:00
|
|
|
p->type, len, p->flags, p->pos, p->fd_name);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-01-22 20:20:40 +04:00
|
|
|
if (write_img(cr_fdset->fds[CR_FD_FDINFO], &e))
|
|
|
|
goto err;
|
|
|
|
if (write_img_buf(cr_fdset->fds[CR_FD_FDINFO], big_buffer, e.len))
|
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_task_special_files(pid_t pid, const struct cr_fdset *cr_fdset)
|
2011-12-07 17:11:00 +04:00
|
|
|
{
|
2012-02-07 19:20:17 +04:00
|
|
|
struct fd_parms params;
|
|
|
|
int fd, ret;
|
2011-12-07 17:11:00 +04:00
|
|
|
|
2012-02-07 19:20:17 +04:00
|
|
|
/* Dump /proc/pid/cwd */
|
2012-02-28 18:27:28 +04:00
|
|
|
params = (struct fd_parms) {
|
|
|
|
.id = FD_ID_INVALID,
|
|
|
|
.pid = FD_PID_INVALID,
|
2012-03-06 15:52:00 +04:00
|
|
|
.type = FDINFO_CWD,
|
2012-02-28 18:27:28 +04:00
|
|
|
};
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
fd = open_proc(pid, "cwd");
|
2012-02-17 01:39:35 +04:00
|
|
|
if (fd < 0)
|
2011-12-07 17:11:00 +04:00
|
|
|
return -1;
|
2012-03-01 20:56:27 +03:00
|
|
|
ret = dump_one_reg_file(¶ms, fd, cr_fdset, 1);
|
2012-02-07 19:20:17 +04:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2011-12-07 17:11:00 +04:00
|
|
|
|
2012-02-07 19:20:17 +04:00
|
|
|
/* Dump /proc/pid/exe */
|
2012-02-28 18:27:28 +04:00
|
|
|
params = (struct fd_parms) {
|
|
|
|
.id = FD_ID_INVALID,
|
|
|
|
.pid = FD_PID_INVALID,
|
2012-03-06 15:52:00 +04:00
|
|
|
.type = FDINFO_EXE,
|
2012-02-28 18:27:28 +04:00
|
|
|
};
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
fd = open_proc(pid, "exe");
|
2012-02-17 01:39:35 +04:00
|
|
|
if (fd < 0)
|
2012-02-07 19:32:11 +04:00
|
|
|
return -1;
|
2012-03-01 20:56:27 +03:00
|
|
|
ret = dump_one_reg_file(¶ms, fd, cr_fdset, 1);
|
2012-02-07 19:32:11 +04:00
|
|
|
|
2012-02-07 19:20:17 +04:00
|
|
|
return ret;
|
2012-02-07 19:32:11 +04:00
|
|
|
}
|
2011-12-07 17:11:00 +04:00
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
static int dump_pipe_and_data(int lfd, struct pipe_entry *e,
|
2012-03-06 14:20:00 +04:00
|
|
|
const struct cr_fdset *cr_fdset)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
int fd_pipes;
|
|
|
|
int steal_pipe[2];
|
|
|
|
int pipe_size;
|
|
|
|
int has_bytes;
|
|
|
|
int ret = -1;
|
|
|
|
|
2012-01-12 15:17:51 +04:00
|
|
|
fd_pipes = cr_fdset->fds[CR_FD_PIPES];
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info("Dumping data from pipe %x\n", e->pipeid);
|
|
|
|
if (pipe(steal_pipe) < 0) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't create pipe for stealing data");
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
pipe_size = fcntl(lfd, F_GETPIPE_SZ);
|
|
|
|
if (pipe_size < 0) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Can't obtain piped data size\n");
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
has_bytes = tee(lfd, steal_pipe[1], pipe_size, SPLICE_F_NONBLOCK);
|
|
|
|
if (has_bytes < 0) {
|
|
|
|
if (errno != EAGAIN) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't pick pipe data");
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err_close;
|
|
|
|
} else
|
|
|
|
has_bytes = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
e->bytes = has_bytes;
|
2012-01-22 20:20:40 +04:00
|
|
|
if (write_img(fd_pipes, e))
|
|
|
|
goto err_close;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
if (has_bytes) {
|
|
|
|
ret = splice(steal_pipe[0], NULL, fd_pipes,
|
|
|
|
NULL, has_bytes, 0);
|
|
|
|
if (ret < 0) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't push pipe data");
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err_close;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
err_close:
|
|
|
|
close(steal_pipe[0]);
|
|
|
|
close(steal_pipe[1]);
|
|
|
|
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_one_pipe(const struct fd_parms *p, unsigned int id, int lfd,
|
|
|
|
const struct cr_fdset *cr_fdset)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct pipe_entry e;
|
|
|
|
int ret = -1;
|
2012-03-01 20:56:41 +03:00
|
|
|
struct statfs stfs_buf;
|
|
|
|
|
|
|
|
if (fstatfs(lfd, &stfs_buf) < 0) {
|
|
|
|
pr_perror("Can't fstatfs on %ld", p->fd_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stfs_buf.f_type != PIPEFS_MAGIC) {
|
|
|
|
pr_err("Dumping of FIFO's is not supported: %ld\n", p->fd_name);
|
|
|
|
return -1;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
cr-dump.c: fix printf format warnings
cr-dump.c: In function ‘dump_one_reg_file’:
cr-dump.c:128:2: error: format ‘%8x’ expects type ‘unsigned int’, but argument 5 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_one_pipe’:
cr-dump.c:223:2: error: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 2 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 3 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 4 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 5 has type ‘u32’
cr-dump.c:240:3: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_one_fd’:
cr-dump.c:257:3: error: format ‘%d’ expects type ‘int’, but argument 5 has type ‘long unsigned int’
cr-dump.c:262:3: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c:272:4: error: format ‘%d’ expects type ‘int’, but argument 3 has type ‘long unsigned int’
cr-dump.c:286:4: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c:295:2: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_task_files’:
cr-dump.c:340:3: error: too few arguments for format
Signed-off-by: Kir Kolyshkin <kir@openvz.org>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-01-31 15:31:24 +04:00
|
|
|
pr_info("Dumping pipe %ld/%x flags %x\n", p->fd_name, id, p->flags);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-01-12 22:00:45 +04:00
|
|
|
e.fd = p->fd_name;
|
2011-09-23 12:00:45 +04:00
|
|
|
e.pipeid = id;
|
2012-01-12 22:00:45 +04:00
|
|
|
e.flags = p->flags;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-01-12 22:00:45 +04:00
|
|
|
if (p->flags & O_WRONLY) {
|
2011-09-23 12:00:45 +04:00
|
|
|
e.bytes = 0;
|
2012-01-22 20:20:40 +04:00
|
|
|
ret = write_img(cr_fdset->fds[CR_FD_PIPES], &e);
|
2011-09-23 12:00:45 +04:00
|
|
|
} else
|
|
|
|
ret = dump_pipe_and_data(lfd, &e, cr_fdset);
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (!ret)
|
cr-dump.c: fix printf format warnings
cr-dump.c: In function ‘dump_one_reg_file’:
cr-dump.c:128:2: error: format ‘%8x’ expects type ‘unsigned int’, but argument 5 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_one_pipe’:
cr-dump.c:223:2: error: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 2 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 3 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 4 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 5 has type ‘u32’
cr-dump.c:240:3: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_one_fd’:
cr-dump.c:257:3: error: format ‘%d’ expects type ‘int’, but argument 5 has type ‘long unsigned int’
cr-dump.c:262:3: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c:272:4: error: format ‘%d’ expects type ‘int’, but argument 3 has type ‘long unsigned int’
cr-dump.c:286:4: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c:295:2: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_task_files’:
cr-dump.c:340:3: error: too few arguments for format
Signed-off-by: Kir Kolyshkin <kir@openvz.org>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-01-31 15:31:24 +04:00
|
|
|
pr_info("Dumped pipe: fd: %8x pipeid: %8x flags: %8x bytes: %8x\n",
|
2011-09-23 12:00:45 +04:00
|
|
|
e.fd, e.pipeid, e.flags, e.bytes);
|
|
|
|
else
|
cr-dump.c: fix printf format warnings
cr-dump.c: In function ‘dump_one_reg_file’:
cr-dump.c:128:2: error: format ‘%8x’ expects type ‘unsigned int’, but argument 5 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_one_pipe’:
cr-dump.c:223:2: error: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 2 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 3 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 4 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 5 has type ‘u32’
cr-dump.c:240:3: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_one_fd’:
cr-dump.c:257:3: error: format ‘%d’ expects type ‘int’, but argument 5 has type ‘long unsigned int’
cr-dump.c:262:3: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c:272:4: error: format ‘%d’ expects type ‘int’, but argument 3 has type ‘long unsigned int’
cr-dump.c:286:4: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c:295:2: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_task_files’:
cr-dump.c:340:3: error: too few arguments for format
Signed-off-by: Kir Kolyshkin <kir@openvz.org>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-01-31 15:31:24 +04:00
|
|
|
pr_err("Dumping pipe %ld/%x flags %x\n", p->fd_name, id, p->flags);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int read_fd_params(pid_t pid, const char *fd, struct fd_parms *p)
|
2012-03-01 20:56:21 +03:00
|
|
|
{
|
|
|
|
FILE *file;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
file = fopen_proc(pid, "fdinfo/%s", fd);
|
|
|
|
if (!file)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
p->fd_name = atoi(fd);
|
|
|
|
ret = fscanf(file, "pos:\t%li\nflags:\t%o\n", &p->pos, &p->flags);
|
|
|
|
fclose(file);
|
|
|
|
|
|
|
|
if (ret != 2) {
|
|
|
|
pr_err("Bad format of fdinfo file (%d items, want 2)\n", ret);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("%d fdinfo %s: pos: %16lx flags: %16o\n",
|
|
|
|
pid, fd, p->pos, p->flags);
|
|
|
|
|
|
|
|
p->pid = pid;
|
|
|
|
p->id = FD_ID_INVALID;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_one_fd(pid_t pid, int pid_fd_dir, const char *d_name,
|
|
|
|
const struct cr_fdset *cr_fdset,
|
2012-02-29 16:06:48 +03:00
|
|
|
struct sk_queue *sk_queue)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2012-03-01 20:56:48 +03:00
|
|
|
struct stat fd_stat;
|
2011-11-30 22:30:53 +04:00
|
|
|
int err = -1;
|
2012-03-01 20:56:21 +03:00
|
|
|
struct fd_parms p;
|
|
|
|
int lfd;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-03-01 20:56:21 +03:00
|
|
|
if (read_fd_params(pid, d_name, &p))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
lfd = openat(pid_fd_dir, d_name, O_RDONLY);
|
2012-01-12 21:57:14 +04:00
|
|
|
if (lfd < 0) {
|
2012-03-01 20:56:21 +03:00
|
|
|
err = try_dump_socket(pid, p.fd_name, cr_fdset, sk_queue);
|
2011-12-26 22:12:03 +04:00
|
|
|
if (err != 1)
|
|
|
|
return err;
|
|
|
|
|
2012-03-01 20:56:21 +03:00
|
|
|
pr_perror("Failed to open %d/%ld", pid_fd_dir, p.fd_name);
|
2011-09-23 12:00:45 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-03-01 20:56:48 +03:00
|
|
|
if (fstat(lfd, &fd_stat) < 0) {
|
2012-03-01 20:56:21 +03:00
|
|
|
pr_perror("Can't get stat on %ld", p.fd_name);
|
2011-11-30 22:30:53 +04:00
|
|
|
goto out_close;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-03-01 20:56:48 +03:00
|
|
|
if (S_ISCHR(fd_stat.st_mode) &&
|
|
|
|
(major(fd_stat.st_rdev) == TTY_MAJOR ||
|
|
|
|
major(fd_stat.st_rdev) == UNIX98_PTY_SLAVE_MAJOR)) {
|
2011-11-28 13:57:41 +03:00
|
|
|
/* skip only standard destriptors */
|
2012-03-01 20:56:21 +03:00
|
|
|
if (p.fd_name < 3) {
|
2011-11-30 22:30:53 +04:00
|
|
|
err = 0;
|
cr-dump.c: fix printf format warnings
cr-dump.c: In function ‘dump_one_reg_file’:
cr-dump.c:128:2: error: format ‘%8x’ expects type ‘unsigned int’, but argument 5 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_one_pipe’:
cr-dump.c:223:2: error: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 2 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 3 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 4 has type ‘u32’
cr-dump.c:237:3: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 5 has type ‘u32’
cr-dump.c:240:3: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_one_fd’:
cr-dump.c:257:3: error: format ‘%d’ expects type ‘int’, but argument 5 has type ‘long unsigned int’
cr-dump.c:262:3: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c:272:4: error: format ‘%d’ expects type ‘int’, but argument 3 has type ‘long unsigned int’
cr-dump.c:286:4: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c:295:2: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘long unsigned int’
cr-dump.c: In function ‘dump_task_files’:
cr-dump.c:340:3: error: too few arguments for format
Signed-off-by: Kir Kolyshkin <kir@openvz.org>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-01-31 15:31:24 +04:00
|
|
|
pr_info("... Skipping tty ... %d/%ld\n",
|
2012-03-01 20:56:21 +03:00
|
|
|
pid_fd_dir, p.fd_name);
|
2011-11-30 22:30:53 +04:00
|
|
|
goto out_close;
|
2011-11-28 13:57:41 +03:00
|
|
|
}
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-03-01 20:56:48 +03:00
|
|
|
if (S_ISREG(fd_stat.st_mode) ||
|
|
|
|
S_ISDIR(fd_stat.st_mode) ||
|
|
|
|
(S_ISCHR(fd_stat.st_mode) && major(fd_stat.st_rdev) == MEM_MAJOR)) {
|
2012-02-28 18:27:28 +04:00
|
|
|
|
2012-03-01 20:56:48 +03:00
|
|
|
p.id = MAKE_FD_GENID(fd_stat.st_dev, fd_stat.st_ino, p.pos);
|
2012-03-06 15:52:00 +04:00
|
|
|
p.type = FDINFO_REG;
|
2012-02-28 18:27:28 +04:00
|
|
|
|
2012-03-01 20:56:27 +03:00
|
|
|
return dump_one_reg_file(&p, lfd, cr_fdset, 1);
|
2012-02-28 18:27:28 +04:00
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-03-01 20:56:48 +03:00
|
|
|
if (S_ISFIFO(fd_stat.st_mode))
|
|
|
|
return dump_one_pipe(&p, fd_stat.st_ino, lfd, cr_fdset);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-11-28 13:57:41 +03:00
|
|
|
err:
|
2012-03-01 20:56:48 +03:00
|
|
|
pr_err("Can't dump file %ld of that type [%x]\n", p.fd_name, fd_stat.st_mode);
|
2011-11-30 22:30:53 +04:00
|
|
|
|
|
|
|
out_close:
|
2012-01-12 21:57:14 +04:00
|
|
|
close_safe(&lfd);
|
2011-11-30 22:30:53 +04:00
|
|
|
return err;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_task_files(pid_t pid, const struct cr_fdset *cr_fdset,
|
2012-02-29 16:06:48 +03:00
|
|
|
struct sk_queue *sk_queue)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct dirent *de;
|
|
|
|
unsigned long pos;
|
|
|
|
unsigned int flags;
|
|
|
|
DIR *fd_dir;
|
|
|
|
|
|
|
|
pr_info("\n");
|
|
|
|
pr_info("Dumping opened files (pid: %d)\n", pid);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
2012-02-07 19:32:11 +04:00
|
|
|
/*
|
|
|
|
* Dump special files at the beginning. We might need
|
|
|
|
* to re-read them in restorer, so better to make it
|
|
|
|
* fast.
|
|
|
|
*/
|
2012-02-17 01:39:36 +04:00
|
|
|
if (dump_task_special_files(pid, cr_fdset)) {
|
2012-02-07 19:20:17 +04:00
|
|
|
pr_err("Can't dump special files\n");
|
2012-02-07 19:32:11 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
fd_dir = opendir_proc(pid, "fd");
|
2012-02-17 01:39:35 +04:00
|
|
|
if (!fd_dir)
|
2011-09-23 12:00:45 +04:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
while ((de = readdir(fd_dir))) {
|
2012-03-01 11:35:29 +03:00
|
|
|
if (!strcmp(de->d_name, "."))
|
|
|
|
continue;
|
|
|
|
if (!strcmp(de->d_name, ".."))
|
2011-09-23 12:00:45 +04:00
|
|
|
continue;
|
2012-03-01 20:56:21 +03:00
|
|
|
if (dump_one_fd(pid, dirfd(fd_dir), de->d_name, cr_fdset,
|
2012-02-29 16:06:48 +03:00
|
|
|
sk_queue))
|
2011-09-23 12:00:45 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
|
|
|
closedir(fd_dir);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_task_mappings(pid_t pid, const struct list_head *vma_area_list,
|
|
|
|
const struct cr_fdset *cr_fdset)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct vma_area *vma_area;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
pr_info("\n");
|
|
|
|
pr_info("Dumping mappings (pid: %d)\n", pid);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
2011-10-21 12:14:45 +04:00
|
|
|
list_for_each_entry(vma_area, vma_area_list, list) {
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
struct vma_entry *vma = &vma_area->vma;
|
|
|
|
|
2011-11-15 17:12:29 +04:00
|
|
|
if (!vma_entry_is(vma, VMA_AREA_REGULAR))
|
2011-09-23 12:00:45 +04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
pr_info_vma(vma_area);
|
|
|
|
|
2012-03-03 19:35:10 +03:00
|
|
|
if (vma_entry_is(vma, VMA_ANON_SHARED)) {
|
|
|
|
struct shmem_entry e;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-03-03 19:35:10 +03:00
|
|
|
e.start = vma->start;
|
|
|
|
e.end = vma->end;
|
|
|
|
e.shmid = vma_area->shmid;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-03-03 19:35:10 +03:00
|
|
|
pr_info("shmem: s: %16lx e: %16lx shmid: %16lx\n",
|
2011-09-23 12:00:45 +04:00
|
|
|
e.start, e.end, e.shmid);
|
|
|
|
|
2012-03-03 19:35:10 +03:00
|
|
|
if (write_img(cr_fdset->fds[CR_FD_SHMEM], &e))
|
|
|
|
goto err;
|
|
|
|
} else if (vma_entry_is(vma, VMA_FILE_PRIVATE) ||
|
|
|
|
vma_entry_is(vma, VMA_FILE_SHARED)) {
|
|
|
|
struct fd_parms p = {
|
|
|
|
.fd_name = vma->start,
|
|
|
|
.id = FD_ID_INVALID,
|
|
|
|
.pid = pid,
|
|
|
|
.type = FDINFO_MAP,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (vma->prot & PROT_WRITE &&
|
|
|
|
vma_entry_is(vma, VMA_FILE_SHARED))
|
|
|
|
p.flags = O_RDWR;
|
|
|
|
else
|
|
|
|
p.flags = O_RDONLY;
|
|
|
|
|
|
|
|
ret = dump_one_reg_file(&p, vma_area->vm_file_fd, cr_fdset, 0);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_task_creds(pid_t pid, const struct parasite_dump_misc *misc,
|
|
|
|
const struct cr_fdset *fds)
|
2012-01-27 21:43:32 +04:00
|
|
|
{
|
|
|
|
int ret, i;
|
|
|
|
struct proc_status_creds cr;
|
|
|
|
struct creds_entry ce;
|
|
|
|
|
|
|
|
pr_info("\n");
|
|
|
|
pr_info("Dumping creds for %d)\n", pid);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
ret = parse_pid_status(pid, &cr);
|
2012-01-27 21:43:32 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ce.uid = cr.uids[0];
|
|
|
|
ce.gid = cr.gids[0];
|
|
|
|
ce.euid = cr.uids[1];
|
|
|
|
ce.egid = cr.gids[1];
|
|
|
|
ce.suid = cr.uids[2];
|
|
|
|
ce.sgid = cr.gids[2];
|
|
|
|
ce.fsuid = cr.uids[3];
|
|
|
|
ce.fsgid = cr.gids[3];
|
|
|
|
|
|
|
|
BUILD_BUG_ON(CR_CAP_SIZE != PROC_CAP_SIZE);
|
|
|
|
|
|
|
|
for (i = 0; i < CR_CAP_SIZE; i++) {
|
|
|
|
ce.cap_inh[i] = cr.cap_inh[i];
|
|
|
|
ce.cap_prm[i] = cr.cap_prm[i];
|
|
|
|
ce.cap_eff[i] = cr.cap_eff[i];
|
|
|
|
ce.cap_bnd[i] = cr.cap_bnd[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
ce.secbits = misc->secbits;
|
|
|
|
|
|
|
|
ret = write_img(fds->fds[CR_FD_CREDS], &ce);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
#define assign_reg(dst, src, e) dst.e = (__typeof__(dst.e))src.e
|
|
|
|
#define assign_array(dst, src, e) memcpy(&dst.e, &src.e, sizeof(dst.e))
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
static int get_task_auxv(pid_t pid, struct core_entry *core)
|
2012-01-23 15:22:00 +04:00
|
|
|
{
|
2012-02-17 01:39:36 +04:00
|
|
|
int fd = open_proc(pid, "auxv");
|
2012-01-23 15:22:00 +04:00
|
|
|
int ret, i;
|
|
|
|
|
2012-02-17 01:39:35 +04:00
|
|
|
if (fd < 0)
|
2012-01-23 15:22:00 +04:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; i < AT_VECTOR_SIZE; i++) {
|
|
|
|
ret = read(fd, &core->tc.mm_saved_auxv[i],
|
|
|
|
sizeof(core->tc.mm_saved_auxv[0]));
|
|
|
|
if (ret == 0)
|
|
|
|
break;
|
|
|
|
else if (ret != sizeof(core->tc.mm_saved_auxv[0])) {
|
|
|
|
ret = -1;
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Error readind %d's auxv[%d]",
|
2012-01-23 15:22:00 +04:00
|
|
|
pid, i);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
close_safe(&fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
static int get_task_personality(pid_t pid, u32 *personality)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
FILE *file = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
file = fopen_proc(pid, "personality");
|
2012-02-17 01:39:35 +04:00
|
|
|
if (!file)
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (!fgets(loc_buf, sizeof(loc_buf), file)) {
|
|
|
|
perror("Can't read task personality");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
*personality = atoi(loc_buf);
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (file)
|
|
|
|
fclose(file);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int get_task_regs(pid_t pid, struct core_entry *core, const struct parasite_ctl *ctl)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
user_fpregs_struct_t fpregs = {-1};
|
|
|
|
user_regs_struct_t regs = {-1};
|
2011-10-20 17:19:26 +04:00
|
|
|
int ret = -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-02-17 22:56:36 +04:00
|
|
|
if (ctl)
|
|
|
|
regs = ctl->regs_orig;
|
|
|
|
else {
|
|
|
|
if (ptrace(PTRACE_GETREGS, pid, NULL, ®s)) {
|
|
|
|
pr_err("Can't obtain GP registers for %d\n", pid);
|
|
|
|
goto err;
|
|
|
|
}
|
2012-02-15 18:36:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs)) {
|
|
|
|
pr_err("Can't obtain FPU registers for %d\n", pid);
|
|
|
|
goto err;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-12-02 16:46:00 +04:00
|
|
|
/* Did we come from a system call? */
|
2012-02-10 18:34:09 +04:00
|
|
|
if ((int)regs.orig_ax >= 0) {
|
2011-12-02 16:46:00 +04:00
|
|
|
/* Restart the system call */
|
2012-02-10 18:34:09 +04:00
|
|
|
switch ((long)(int)regs.ax) {
|
2011-12-02 16:46:00 +04:00
|
|
|
case -ERESTARTNOHAND:
|
|
|
|
case -ERESTARTSYS:
|
|
|
|
case -ERESTARTNOINTR:
|
|
|
|
regs.ax = regs.orig_ax;
|
|
|
|
regs.ip -= 2;
|
|
|
|
break;
|
|
|
|
case -ERESTART_RESTARTBLOCK:
|
|
|
|
regs.ax = __NR_restart_syscall;
|
|
|
|
regs.ip -= 2;
|
|
|
|
break;
|
|
|
|
}
|
2012-02-10 18:34:09 +04:00
|
|
|
}
|
2011-12-02 16:46:00 +04:00
|
|
|
|
2012-01-22 20:16:33 +04:00
|
|
|
assign_reg(core->arch.gpregs, regs, r15);
|
|
|
|
assign_reg(core->arch.gpregs, regs, r14);
|
|
|
|
assign_reg(core->arch.gpregs, regs, r13);
|
|
|
|
assign_reg(core->arch.gpregs, regs, r12);
|
|
|
|
assign_reg(core->arch.gpregs, regs, bp);
|
|
|
|
assign_reg(core->arch.gpregs, regs, bx);
|
|
|
|
assign_reg(core->arch.gpregs, regs, r11);
|
|
|
|
assign_reg(core->arch.gpregs, regs, r10);
|
|
|
|
assign_reg(core->arch.gpregs, regs, r9);
|
|
|
|
assign_reg(core->arch.gpregs, regs, r8);
|
|
|
|
assign_reg(core->arch.gpregs, regs, ax);
|
|
|
|
assign_reg(core->arch.gpregs, regs, cx);
|
|
|
|
assign_reg(core->arch.gpregs, regs, dx);
|
|
|
|
assign_reg(core->arch.gpregs, regs, si);
|
|
|
|
assign_reg(core->arch.gpregs, regs, di);
|
|
|
|
assign_reg(core->arch.gpregs, regs, orig_ax);
|
|
|
|
assign_reg(core->arch.gpregs, regs, ip);
|
|
|
|
assign_reg(core->arch.gpregs, regs, cs);
|
|
|
|
assign_reg(core->arch.gpregs, regs, flags);
|
|
|
|
assign_reg(core->arch.gpregs, regs, sp);
|
|
|
|
assign_reg(core->arch.gpregs, regs, ss);
|
|
|
|
assign_reg(core->arch.gpregs, regs, fs_base);
|
|
|
|
assign_reg(core->arch.gpregs, regs, gs_base);
|
|
|
|
assign_reg(core->arch.gpregs, regs, ds);
|
|
|
|
assign_reg(core->arch.gpregs, regs, es);
|
|
|
|
assign_reg(core->arch.gpregs, regs, fs);
|
|
|
|
assign_reg(core->arch.gpregs, regs, gs);
|
|
|
|
|
|
|
|
assign_reg(core->arch.fpregs, fpregs, cwd);
|
|
|
|
assign_reg(core->arch.fpregs, fpregs, swd);
|
|
|
|
assign_reg(core->arch.fpregs, fpregs, twd);
|
|
|
|
assign_reg(core->arch.fpregs, fpregs, fop);
|
|
|
|
assign_reg(core->arch.fpregs, fpregs, rip);
|
|
|
|
assign_reg(core->arch.fpregs, fpregs, rdp);
|
|
|
|
assign_reg(core->arch.fpregs, fpregs, mxcsr);
|
|
|
|
assign_reg(core->arch.fpregs, fpregs, mxcsr_mask);
|
|
|
|
|
|
|
|
assign_array(core->arch.fpregs, fpregs, st_space);
|
|
|
|
assign_array(core->arch.fpregs, fpregs, xmm_space);
|
|
|
|
assign_array(core->arch.fpregs, fpregs, padding);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-10-20 17:19:26 +04:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_task_core(struct core_entry *core, const struct cr_fdset *fdset)
|
2012-01-22 20:21:35 +04:00
|
|
|
{
|
|
|
|
int fd_core = fdset->fds[CR_FD_CORE];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
lseek(fd_core, MAGIC_OFFSET, SEEK_SET);
|
|
|
|
|
|
|
|
pr_info("Dumping header ... ");
|
|
|
|
|
|
|
|
core->header.version = HEADER_VERSION;
|
|
|
|
core->header.arch = HEADER_ARCH_X86_64;
|
|
|
|
core->header.flags = 0;
|
|
|
|
|
|
|
|
ret = write_img(fd_core, core);
|
|
|
|
|
|
|
|
free(core);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_task_core_all(pid_t pid, const struct proc_pid_stat *stat,
|
|
|
|
const struct parasite_dump_misc *misc, const struct parasite_ctl *ctl,
|
|
|
|
const struct cr_fdset *cr_fdset)
|
2011-10-20 17:19:26 +04:00
|
|
|
{
|
|
|
|
struct core_entry *core = xzalloc(sizeof(*core));
|
|
|
|
int ret = -1;
|
|
|
|
unsigned long brk;
|
|
|
|
|
|
|
|
pr_info("\n");
|
|
|
|
pr_info("Dumping core (pid: %d)\n", pid);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
|
|
|
if (!core)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
pr_info("Dumping GP/FPU registers ... ");
|
2012-02-17 22:56:36 +04:00
|
|
|
ret = get_task_regs(pid, core, ctl);
|
2011-10-20 17:19:26 +04:00
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
|
|
|
pr_info("OK\n");
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info("Obtainting personality ... ");
|
2012-02-17 01:39:36 +04:00
|
|
|
ret = get_task_personality(pid, &core->tc.personality);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
|
|
|
pr_info("OK\n");
|
|
|
|
|
2012-01-22 20:16:33 +04:00
|
|
|
strncpy((char *)core->tc.comm, stat->comm, TASK_COMM_LEN);
|
|
|
|
core->tc.flags = stat->flags;
|
|
|
|
core->tc.mm_start_code = stat->start_code;
|
|
|
|
core->tc.mm_end_code = stat->end_code;
|
|
|
|
core->tc.mm_start_data = stat->start_data;
|
|
|
|
core->tc.mm_end_data = stat->end_data;
|
|
|
|
core->tc.mm_start_stack = stat->start_stack;
|
|
|
|
core->tc.mm_start_brk = stat->start_brk;
|
2012-01-22 20:12:44 +04:00
|
|
|
|
2012-01-23 15:18:31 +04:00
|
|
|
core->tc.mm_arg_start = stat->arg_start;
|
|
|
|
core->tc.mm_arg_end = stat->arg_end;
|
|
|
|
core->tc.mm_env_start = stat->env_start;
|
|
|
|
core->tc.mm_env_end = stat->env_end;
|
|
|
|
|
2012-02-12 00:30:24 +04:00
|
|
|
core->tc.mm_brk = misc->brk;
|
|
|
|
|
2012-02-17 22:56:36 +04:00
|
|
|
BUILD_BUG_ON(sizeof(core->tc.blk_sigset) != sizeof(k_rtsigset_t));
|
|
|
|
memcpy(&core->tc.blk_sigset, &misc->blocked, sizeof(k_rtsigset_t));
|
2011-10-01 13:24:34 +04:00
|
|
|
|
2012-01-23 15:22:00 +04:00
|
|
|
pr_info("Obtainting task auvx ... ");
|
2012-02-17 01:39:36 +04:00
|
|
|
ret = get_task_auxv(pid, core);
|
2012-01-23 15:22:00 +04:00
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
|
|
|
pr_info("OK\n");
|
|
|
|
|
2012-01-22 20:24:04 +04:00
|
|
|
core->tc.task_state = TASK_ALIVE;
|
|
|
|
core->tc.exit_code = 0;
|
|
|
|
|
2012-01-22 20:21:35 +04:00
|
|
|
return dump_task_core(core, cr_fdset);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
err_free:
|
|
|
|
free(core);
|
|
|
|
err:
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int parse_threads(const struct pstree_item *item, u32 **_t, int *_n)
|
2011-10-20 11:03:19 +04:00
|
|
|
{
|
|
|
|
struct dirent *de;
|
|
|
|
DIR *dir;
|
|
|
|
u32 *t = NULL;
|
2011-12-02 18:24:50 +04:00
|
|
|
int nr = 1;
|
2011-10-20 11:03:19 +04:00
|
|
|
|
2012-03-01 19:02:03 +04:00
|
|
|
dir = opendir_proc(item->pid, "task");
|
2012-02-17 01:39:35 +04:00
|
|
|
if (!dir)
|
2011-12-02 18:24:50 +04:00
|
|
|
return -1;
|
2011-10-20 11:03:19 +04:00
|
|
|
|
|
|
|
while ((de = readdir(dir))) {
|
2011-12-04 11:48:10 +04:00
|
|
|
u32 *tmp;
|
|
|
|
|
2011-10-20 11:03:19 +04:00
|
|
|
/* We expect numbers only here */
|
|
|
|
if (de->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
|
2011-12-04 11:48:10 +04:00
|
|
|
tmp = xrealloc(t, nr * sizeof(u32));
|
|
|
|
if (!tmp) {
|
|
|
|
xfree(t);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
t = tmp;
|
2011-12-02 18:24:50 +04:00
|
|
|
t[nr - 1] = atoi(de->d_name);
|
|
|
|
nr++;
|
2011-10-20 11:03:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dir);
|
|
|
|
|
2012-03-01 19:07:15 +04:00
|
|
|
*_t = t;
|
|
|
|
*_n = nr - 1;
|
2011-12-25 17:09:37 +04:00
|
|
|
|
2011-12-02 18:24:50 +04:00
|
|
|
return 0;
|
2011-10-20 11:03:19 +04:00
|
|
|
}
|
|
|
|
|
2012-03-01 19:07:15 +04:00
|
|
|
static int get_threads(struct pstree_item *item)
|
|
|
|
{
|
|
|
|
return parse_threads(item, &item->threads, &item->nr_threads);
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int check_threads(const struct pstree_item *item)
|
2012-03-01 19:07:15 +04:00
|
|
|
{
|
|
|
|
u32 *t;
|
|
|
|
int nr, ret;
|
|
|
|
|
|
|
|
ret = parse_threads(item, &t, &nr);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = ((nr == item->nr_threads) && !memcmp(t, item->threads, nr));
|
|
|
|
xfree(t);
|
|
|
|
|
|
|
|
if (!ret) {
|
|
|
|
pr_info("Threads set has changed while suspending\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int parse_children(const struct pstree_item *item, u32 **_c, int *_n)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
FILE *file;
|
|
|
|
char *tok;
|
2011-12-02 18:26:15 +04:00
|
|
|
u32 *ch = NULL;
|
2011-12-25 18:19:16 +04:00
|
|
|
int nr = 1, i;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-12-25 18:19:16 +04:00
|
|
|
for (i = 0; i < item->nr_threads; i++) {
|
2011-12-01 17:04:49 +04:00
|
|
|
|
2012-03-01 19:05:39 +04:00
|
|
|
file = fopen_proc(item->pid, "task/%d/children", item->threads[i]);
|
2012-02-17 01:39:35 +04:00
|
|
|
if (!file)
|
2011-12-25 18:19:16 +04:00
|
|
|
goto err;
|
2011-12-01 17:04:49 +04:00
|
|
|
|
2011-12-25 18:19:16 +04:00
|
|
|
if (!(fgets(loc_buf, sizeof(loc_buf), file)))
|
|
|
|
loc_buf[0] = 0;
|
2011-12-01 17:04:49 +04:00
|
|
|
|
2011-12-25 18:19:16 +04:00
|
|
|
fclose(file);
|
|
|
|
|
|
|
|
tok = strtok(loc_buf, " \n");
|
|
|
|
while (tok) {
|
|
|
|
u32 *tmp = xrealloc(ch, nr * sizeof(u32));
|
|
|
|
if (!tmp)
|
|
|
|
goto err;
|
|
|
|
ch = tmp;
|
|
|
|
ch[nr - 1] = atoi(tok);
|
|
|
|
nr++;
|
|
|
|
tok = strtok(NULL, " \n");
|
2011-12-04 11:48:10 +04:00
|
|
|
}
|
2011-12-25 18:19:16 +04:00
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-03-01 19:07:15 +04:00
|
|
|
*_c = ch;
|
|
|
|
*_n = nr - 1;
|
2011-12-25 18:19:16 +04:00
|
|
|
|
2011-12-02 18:26:15 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
2011-12-25 18:19:16 +04:00
|
|
|
xfree(ch);
|
2011-12-02 18:26:15 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-03-01 19:07:15 +04:00
|
|
|
static int get_children(struct pstree_item *item)
|
|
|
|
{
|
|
|
|
return parse_children(item, &item->children, &item->nr_children);
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static void unseize_task_and_threads(const struct pstree_item *item, int st)
|
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
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < item->nr_threads; i++)
|
|
|
|
unseize_task(item->threads[i], st); /* item->pid will be here */
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static void pstree_switch_state(const struct list_head *list,
|
|
|
|
const struct cr_options *opts)
|
2011-12-02 18:26:15 +04:00
|
|
|
{
|
2011-12-02 18:27:51 +04:00
|
|
|
struct pstree_item *item;
|
2011-12-02 18:26:15 +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
|
|
|
list_for_each_entry(item, list, list) {
|
|
|
|
unseize_task_and_threads(item, opts->final_state);
|
|
|
|
if (opts->leader_only)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int seize_threads(const struct pstree_item *item)
|
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
|
|
|
{
|
|
|
|
int i = 0, ret;
|
|
|
|
|
|
|
|
if ((item->state == TASK_DEAD) && (item->nr_threads > 1)) {
|
|
|
|
pr_err("Zombies with threads are not supported\n");
|
2011-12-02 18:27:51 +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-09-23 12:00:45 +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
|
|
|
for (i = 0; i < item->nr_threads; i++) {
|
|
|
|
if (item->pid == item->threads[i])
|
|
|
|
continue;
|
2012-02-01 17:03:51 +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
|
|
|
pr_info("\tSeizing %d's %d thread\n", item->pid, item->threads[i]);
|
2012-03-01 19:04:31 +04:00
|
|
|
ret = seize_task(item->threads[i], item->ppid);
|
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 < 0)
|
|
|
|
goto err;
|
2012-02-01 17:03:51 +04:00
|
|
|
|
2012-03-01 19:03:09 +04:00
|
|
|
if (ret == TASK_DEAD) {
|
|
|
|
pr_err("Zombie thread not supported\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
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == TASK_STOPPED) {
|
|
|
|
pr_err("Stopped threads not supported\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2011-10-20 11:03:19 +04:00
|
|
|
|
2011-12-02 18:27:51 +04:00
|
|
|
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
|
|
|
for (i--; i >= 0; i--) {
|
|
|
|
if (item->pid == item->threads[i])
|
|
|
|
continue;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-03-01 19:09:02 +04:00
|
|
|
unseize_task(item->threads[i], TASK_ALIVE);
|
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-01-19 19:22: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
|
|
|
return -1;
|
2012-01-19 19:22:59 +04:00
|
|
|
}
|
|
|
|
|
2012-03-01 19:02:03 +04:00
|
|
|
static int collect_threads(struct pstree_item *item)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2012-03-01 19:07:15 +04:00
|
|
|
ret = get_threads(item);
|
2012-03-01 19:02:03 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = seize_threads(item);
|
2012-03-01 19:07:15 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = check_threads(item);
|
2012-03-01 19:02:03 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-01 19:04:31 +04:00
|
|
|
static struct pstree_item *collect_task(pid_t pid, pid_t ppid, struct list_head *list)
|
2012-01-19 19:22:59 +04:00
|
|
|
{
|
2012-02-17 01:39:36 +04:00
|
|
|
int ret;
|
2012-01-19 19:22:59 +04:00
|
|
|
struct pstree_item *item;
|
|
|
|
|
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
|
|
|
item = xzalloc(sizeof(*item));
|
|
|
|
if (!item)
|
|
|
|
goto err;
|
2012-01-19 19:22:59 +04:00
|
|
|
|
2012-03-01 19:04:31 +04:00
|
|
|
ret = seize_task(pid, ppid);
|
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 < 0)
|
|
|
|
goto err_free;
|
2012-01-19 19:22: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
|
|
|
pr_info("Seized task %d, state %d\n", pid, ret);
|
|
|
|
item->pid = pid;
|
2012-03-01 19:04:31 +04:00
|
|
|
item->ppid = ppid;
|
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
|
|
|
item->state = ret;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-03-01 19:02:03 +04:00
|
|
|
ret = collect_threads(item);
|
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 < 0)
|
|
|
|
goto err_close;
|
|
|
|
|
2012-03-01 19:07:15 +04:00
|
|
|
ret = get_children(item);
|
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 < 0)
|
|
|
|
goto err_close;
|
|
|
|
|
|
|
|
if ((item->state == TASK_DEAD) && (item->nr_children > 0)) {
|
|
|
|
pr_err("Zombie with children?! O_o Run, run, run!\n");
|
|
|
|
goto err_close;
|
|
|
|
}
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
close_pid_proc();
|
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
|
|
|
list_add_tail(&item->list, list);
|
|
|
|
pr_info("Collected %d in %d state\n", item->pid, item->state);
|
|
|
|
return item;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-01-12 23:50:45 +04:00
|
|
|
err_close:
|
2012-02-17 01:39:36 +04:00
|
|
|
close_pid_proc();
|
2012-03-01 19:09:02 +04:00
|
|
|
unseize_task(pid, item->state);
|
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
|
|
|
err_free:
|
|
|
|
xfree(item->children);
|
|
|
|
xfree(item->threads);
|
|
|
|
xfree(item);
|
2011-09-23 12:00:45 +04:00
|
|
|
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
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int check_subtree(const struct pstree_item *item)
|
2012-03-01 19:07:15 +04:00
|
|
|
{
|
|
|
|
u32 *ch;
|
|
|
|
int nr, ret;
|
|
|
|
|
|
|
|
ret = parse_children(item, &ch, &nr);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = ((nr == item->nr_children) && !memcmp(ch, item->children, nr));
|
|
|
|
xfree(ch);
|
|
|
|
|
|
|
|
if (!ret) {
|
|
|
|
pr_info("Children set has changed while suspending\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-03-01 19:04:31 +04:00
|
|
|
static int collect_subtree(pid_t pid, pid_t ppid, struct list_head *pstree_list,
|
|
|
|
int leader_only)
|
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
|
|
|
{
|
|
|
|
struct pstree_item *item;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
pr_info("Collecting tasks starting from %d\n", pid);
|
2012-03-01 19:04:31 +04:00
|
|
|
item = collect_task(pid, ppid, pstree_list);
|
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 (item == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (leader_only)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < item->nr_children; i++)
|
2012-03-01 19:04:31 +04:00
|
|
|
if (collect_subtree(item->children[i], item->pid, pstree_list, 0) < 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
|
|
|
return -1;
|
|
|
|
|
2012-03-01 19:07:15 +04:00
|
|
|
if (check_subtree(item))
|
|
|
|
return -1;
|
|
|
|
|
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 0;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-03-01 19:12:35 +04:00
|
|
|
static int collect_pstree(pid_t pid, struct list_head *pstree_list,
|
2012-03-06 14:20:00 +04:00
|
|
|
const struct cr_options *opts)
|
2012-03-01 19:04:31 +04:00
|
|
|
{
|
2012-03-01 19:11:29 +04:00
|
|
|
int ret, attempts = 5;
|
|
|
|
|
|
|
|
while (1) {
|
2012-03-01 19:12:35 +04:00
|
|
|
struct pstree_item *item;
|
|
|
|
|
|
|
|
ret = collect_subtree(pid, -1, pstree_list, opts->leader_only);
|
|
|
|
if (ret == 0) {
|
|
|
|
/*
|
|
|
|
* Some tasks could have been reparented to
|
|
|
|
* namespaces' reaper. Check this.
|
|
|
|
*/
|
|
|
|
if (opts->namespaces_flags & CLONE_NEWPID) {
|
|
|
|
item = list_first_entry(pstree_list,
|
|
|
|
struct pstree_item, list);
|
|
|
|
BUG_ON(item->pid != 1);
|
|
|
|
|
|
|
|
if (check_subtree(item))
|
|
|
|
goto try_again;
|
|
|
|
}
|
|
|
|
|
2012-03-01 19:11:29 +04:00
|
|
|
break;
|
2012-03-01 19:12:35 +04:00
|
|
|
}
|
2012-03-01 19:11:29 +04:00
|
|
|
|
2012-03-01 19:13:34 +04:00
|
|
|
if (list_empty(pstree_list))
|
|
|
|
/*
|
|
|
|
* No items at all -- no need in re-scanning it again
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
|
2012-03-01 19:11:29 +04:00
|
|
|
/*
|
|
|
|
* Old tasks can die and new ones can appear while we
|
|
|
|
* try to seize the swarm. It's much simpler (and reliable)
|
|
|
|
* just to restart the collection from the beginning
|
|
|
|
* rather than trying to chase them.
|
|
|
|
*/
|
2012-03-01 19:12:35 +04:00
|
|
|
try_again:
|
2012-03-01 19:11:29 +04:00
|
|
|
if (attempts == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
attempts--;
|
|
|
|
pr_info("Trying to suspend tasks again\n");
|
|
|
|
|
|
|
|
while (!list_empty(pstree_list)) {
|
|
|
|
item = list_first_entry(pstree_list,
|
|
|
|
struct pstree_item, list);
|
|
|
|
list_del(&item->list);
|
|
|
|
|
|
|
|
unseize_task_and_threads(item, TASK_ALIVE);
|
|
|
|
|
|
|
|
xfree(item->children);
|
|
|
|
xfree(item->threads);
|
|
|
|
xfree(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2012-03-01 19:04:31 +04:00
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_pstree(pid_t pid, const struct list_head *pstree_list,
|
|
|
|
const struct cr_fdset *cr_fdset)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2012-03-06 14:20:00 +04:00
|
|
|
const struct pstree_item *item;
|
2011-09-23 12:00:45 +04:00
|
|
|
struct pstree_entry e;
|
|
|
|
unsigned long i;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
pr_info("\n");
|
|
|
|
pr_info("Dumping pstree (pid: %d)\n", pid);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
2011-10-21 11:46:19 +04:00
|
|
|
list_for_each_entry(item, pstree_list, list) {
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info("Process: %d (%d children)\n",
|
|
|
|
item->pid, item->nr_children);
|
|
|
|
|
|
|
|
e.pid = item->pid;
|
|
|
|
e.nr_children = item->nr_children;
|
2011-10-20 17:19:26 +04:00
|
|
|
e.nr_threads = item->nr_threads;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-01-22 20:20:40 +04:00
|
|
|
if (write_img(cr_fdset->fds[CR_FD_PSTREE], &e))
|
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info("Children:");
|
|
|
|
for (i = 0; i < item->nr_children; i++) {
|
|
|
|
pr_info(" %d", item->children[i]);
|
2012-01-22 20:20:40 +04:00
|
|
|
if (write_img(cr_fdset->fds[CR_FD_PSTREE],
|
|
|
|
&item->children[i]))
|
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
pr_info("\n");
|
2011-10-20 17:19:26 +04:00
|
|
|
|
|
|
|
pr_info("Threads:\n");
|
|
|
|
for (i = 0; i < item->nr_threads; i++) {
|
|
|
|
pr_info(" %d", item->threads[i]);
|
2012-01-22 20:20:40 +04:00
|
|
|
if (write_img(cr_fdset->fds[CR_FD_PSTREE],
|
|
|
|
&item->threads[i]))
|
|
|
|
goto err;
|
2011-10-20 17:19:26 +04:00
|
|
|
}
|
|
|
|
pr_info("\n");
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static struct vma_area *find_vma_by_addr(const struct list_head *vma_area_list,
|
|
|
|
unsigned long addr)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct vma_area *vma_area;
|
|
|
|
|
2011-10-21 12:14:45 +04:00
|
|
|
list_for_each_entry(vma_area, vma_area_list, list) {
|
2011-09-23 12:00:45 +04:00
|
|
|
if (in_vma_area(vma_area, addr))
|
|
|
|
return vma_area;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* kernel expects a special format in core file */
|
2012-03-06 14:20:00 +04:00
|
|
|
static int finalize_core(pid_t pid, const struct list_head *vma_area_list,
|
|
|
|
const struct cr_fdset *cr_fdset)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2012-02-12 00:26:54 +04:00
|
|
|
int fd_core;
|
|
|
|
unsigned long num;
|
2011-09-23 12:00:45 +04:00
|
|
|
struct vma_area *vma_area;
|
|
|
|
struct vma_entry ve;
|
2012-02-08 14:11:54 +04:00
|
|
|
ssize_t bytes;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info("\n");
|
|
|
|
pr_info("Finalizing core (pid: %d)\n", pid);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
2012-01-12 15:17:51 +04:00
|
|
|
fd_core = cr_fdset->fds[CR_FD_CORE];
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
lseek(fd_core, GET_FILE_OFF_AFTER(struct core_entry), SEEK_SET);
|
|
|
|
|
|
|
|
num = 0;
|
|
|
|
pr_info("Appending VMAs ... ");
|
|
|
|
|
|
|
|
/* All VMAs first */
|
|
|
|
|
2011-10-21 12:14:45 +04:00
|
|
|
list_for_each_entry(vma_area, vma_area_list, list) {
|
2012-02-08 14:11:54 +04:00
|
|
|
bytes = write(fd_core, &vma_area->vma, sizeof(vma_area->vma));
|
|
|
|
if (bytes != sizeof(vma_area->vma)) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("\nUnable to write vma entry (%li written)", num);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
num++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ending marker */
|
2011-10-24 11:27:28 +04:00
|
|
|
memzero_p(&ve);
|
2012-01-22 20:20:40 +04:00
|
|
|
if (write_img(fd_core, &ve))
|
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info("OK (%li written)\n", num);
|
|
|
|
|
|
|
|
pr_info("----------------------------------------\n");
|
2012-02-12 00:26:54 +04:00
|
|
|
return 0;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-02-12 00:26:54 +04:00
|
|
|
err:
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Error catched");
|
2012-02-12 00:26:54 +04:00
|
|
|
return -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-02-21 09:25:17 +03:00
|
|
|
static int dump_task_thread(struct parasite_ctl *parasite_ctl,
|
2012-03-06 14:20:00 +04:00
|
|
|
pid_t pid, const struct cr_fdset *cr_fdset)
|
2011-10-20 17:19:26 +04:00
|
|
|
{
|
|
|
|
struct core_entry *core = xzalloc(sizeof(*core));
|
|
|
|
int ret = -1;
|
2012-02-21 09:25:17 +03:00
|
|
|
unsigned int *taddr;
|
2011-10-20 17:19:26 +04:00
|
|
|
|
|
|
|
pr_info("\n");
|
|
|
|
pr_info("Dumping core for thread (pid: %d)\n", pid);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
|
|
|
if (!core)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
pr_info("Dumping GP/FPU registers ... ");
|
2012-02-17 22:56:36 +04:00
|
|
|
ret = get_task_regs(pid, core, NULL);
|
2011-10-20 17:19:26 +04:00
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
2012-02-21 09:25:17 +03:00
|
|
|
|
|
|
|
ret = parasite_dump_tid_addr_seized(parasite_ctl, pid, &taddr);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Can't dump tid address for pid %d", pid);
|
|
|
|
goto err;
|
2012-02-15 18:36:32 +04:00
|
|
|
}
|
2012-02-21 09:25:17 +03:00
|
|
|
|
|
|
|
pr_info("%d: tid_address=%p\n", pid, taddr);
|
|
|
|
core->clear_tid_address = (u64) taddr;
|
|
|
|
|
2011-10-20 17:19:26 +04:00
|
|
|
pr_info("OK\n");
|
|
|
|
|
2012-01-22 20:24:04 +04:00
|
|
|
core->tc.task_state = TASK_ALIVE;
|
|
|
|
core->tc.exit_code = 0;
|
|
|
|
|
2012-01-22 20:21:35 +04:00
|
|
|
return dump_task_core(core, cr_fdset);
|
2011-10-20 17:19:26 +04:00
|
|
|
|
|
|
|
err_free:
|
|
|
|
free(core);
|
|
|
|
err:
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_one_zombie(const struct pstree_item *item,
|
|
|
|
const struct proc_pid_stat *pps,
|
|
|
|
struct cr_fdset *cr_fdset)
|
2012-01-22 20:28:30 +04:00
|
|
|
{
|
|
|
|
struct core_entry *core;
|
|
|
|
|
2012-02-08 20:19:39 +03:00
|
|
|
cr_fdset = cr_dump_fdset_open(item->pid, CR_FD_DESC_CORE, cr_fdset);
|
2012-01-22 20:28:30 +04:00
|
|
|
if (cr_fdset == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
core = xzalloc(sizeof(*core));
|
|
|
|
if (core == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
core->tc.task_state = TASK_DEAD;
|
|
|
|
core->tc.exit_code = pps->exit_code;
|
|
|
|
|
|
|
|
return dump_task_core(core, cr_fdset);
|
|
|
|
}
|
|
|
|
|
2012-01-22 20:12:44 +04:00
|
|
|
static struct proc_pid_stat pps_buf;
|
|
|
|
|
2012-02-21 09:25:17 +03:00
|
|
|
static int dump_task_threads(struct parasite_ctl *parasite_ctl,
|
2012-03-06 14:20:00 +04:00
|
|
|
const struct pstree_item *item)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2012-01-22 20:13:59 +04:00
|
|
|
int i;
|
|
|
|
struct cr_fdset *cr_fdset_thread = NULL;
|
|
|
|
|
|
|
|
if (item->nr_threads == 1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < item->nr_threads; i++) {
|
|
|
|
/* Leader is already dumped */
|
|
|
|
if (item->pid == item->threads[i])
|
|
|
|
continue;
|
|
|
|
|
2012-02-08 20:19:39 +03:00
|
|
|
cr_fdset_thread = cr_dump_fdset_open(item->threads[i], CR_FD_DESC_CORE, NULL);
|
2012-01-22 20:13:59 +04:00
|
|
|
if (!cr_fdset_thread)
|
|
|
|
goto err;
|
|
|
|
|
2012-02-21 09:25:17 +03:00
|
|
|
if (dump_task_thread(parasite_ctl,
|
|
|
|
item->threads[i], cr_fdset_thread))
|
2012-01-22 20:13:59 +04:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
close_cr_fdset(&cr_fdset_thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
close_cr_fdset(&cr_fdset_thread);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_one_task(const struct pstree_item *item, struct cr_fdset *cr_fdset)
|
2012-01-22 20:13:59 +04:00
|
|
|
{
|
|
|
|
pid_t pid = item->pid;
|
2011-10-21 12:14:45 +04:00
|
|
|
LIST_HEAD(vma_area_list);
|
|
|
|
struct parasite_ctl *parasite_ctl;
|
2012-01-12 23:50:45 +04:00
|
|
|
int ret = -1;
|
2012-01-27 21:35:59 +04:00
|
|
|
struct parasite_dump_misc misc;
|
2012-02-29 16:06:48 +03:00
|
|
|
struct sk_queue sk_queue = { };
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info("========================================\n");
|
|
|
|
pr_info("Dumping task (pid: %d)\n", pid);
|
|
|
|
pr_info("========================================\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
|
|
|
if (item->state == TASK_STOPPED) {
|
|
|
|
pr_err("Stopped tasks are not supported\n");
|
2012-02-17 01:39:32 +04:00
|
|
|
goto err_free;
|
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-01-22 20:12:44 +04:00
|
|
|
pr_info("Obtainting task stat ... ");
|
2012-02-17 01:39:36 +04:00
|
|
|
ret = parse_pid_stat(pid, &pps_buf);
|
2012-01-22 20:12:44 +04:00
|
|
|
if (ret < 0)
|
|
|
|
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
|
|
|
if (item->state == TASK_DEAD)
|
2012-01-22 20:28:30 +04:00
|
|
|
return dump_one_zombie(item, &pps_buf, cr_fdset);
|
2012-01-22 20:24:47 +04:00
|
|
|
|
2012-01-31 18:26:51 +04:00
|
|
|
ret = -1;
|
2012-02-08 20:19:39 +03:00
|
|
|
if (!cr_dump_fdset_open(item->pid, CR_FD_DESC_TASK, cr_fdset))
|
2012-01-22 20:15:11 +04:00
|
|
|
goto err;
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
ret = collect_mappings(pid, &vma_area_list);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Collect mappings (pid: %d) failed with %d\n", pid, ret);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-02-29 16:06:48 +03:00
|
|
|
ret = dump_task_files(pid, cr_fdset, &sk_queue);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Dump files (pid: %d) failed with %d\n", pid, ret);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
parasite_ctl = parasite_infect_seized(pid, &vma_area_list);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (!parasite_ctl) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Can't infect (pid: %d) with parasite\n", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-01-11 13:30:38 +04:00
|
|
|
ret = parasite_dump_pages_seized(parasite_ctl, &vma_area_list, cr_fdset);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Can't dump pages (pid: %d) with parasite\n", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2011-11-29 15:12:25 +03:00
|
|
|
ret = parasite_dump_sigacts_seized(parasite_ctl, cr_fdset);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Can't dump sigactions (pid: %d) with parasite\n", pid);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-01-24 16:45:19 +04:00
|
|
|
ret = parasite_dump_itimers_seized(parasite_ctl, cr_fdset);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Can't dump itimers (pid: %d)\n", pid);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-01-27 21:35:59 +04:00
|
|
|
ret = parasite_dump_misc_seized(parasite_ctl, &misc);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Can't dump misc (pid: %d)\n", pid);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-02-17 22:56:36 +04:00
|
|
|
ret = dump_task_core_all(pid, &pps_buf, &misc, parasite_ctl, cr_fdset);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Dump core (pid: %d) failed with %d\n", pid, ret);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-02-21 09:25:17 +03:00
|
|
|
ret = dump_task_threads(parasite_ctl, item);
|
2012-02-17 22:56:36 +04:00
|
|
|
if (ret) {
|
|
|
|
pr_err("Can't dump threads\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-03-03 19:36:43 +03:00
|
|
|
ret = parasite_dump_socket_info(parasite_ctl, cr_fdset, &sk_queue);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Can't dump socket info (pid: %d)\n", pid);
|
|
|
|
goto err;
|
|
|
|
}
|
2012-02-29 16:06:48 +03:00
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
ret = parasite_cure_seized(parasite_ctl);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Can't cure (pid: %d) from parasite\n", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2011-10-21 12:14:45 +04:00
|
|
|
ret = dump_task_mappings(pid, &vma_area_list, cr_fdset);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Dump mappings (pid: %d) failed with %d\n", pid, ret);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
ret = dump_task_creds(pid, &misc, cr_fdset);
|
2012-01-27 21:43:32 +04:00
|
|
|
if (ret) {
|
|
|
|
pr_err("Dump creds (pid: %d) failed with %d\n", pid, ret);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2011-10-21 12:14:45 +04:00
|
|
|
ret = finalize_core(pid, &vma_area_list, cr_fdset);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Finalizing core (pid: %d) failed with %d\n", pid, ret);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-01-22 20:13:59 +04:00
|
|
|
free_mappings(&vma_area_list);
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
err:
|
2012-02-17 01:39:36 +04:00
|
|
|
close_pid_proc();
|
2012-02-17 01:39:32 +04:00
|
|
|
err_free:
|
2011-10-21 12:14:45 +04:00
|
|
|
free_mappings(&vma_area_list);
|
2011-09-23 12:00:45 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
int cr_dump_tasks(pid_t pid, const struct cr_options *opts)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2011-10-21 11:46:19 +04:00
|
|
|
LIST_HEAD(pstree_list);
|
2011-09-23 12:00:45 +04:00
|
|
|
struct cr_fdset *cr_fdset = NULL;
|
|
|
|
struct pstree_item *item;
|
2012-02-17 01:39:35 +04:00
|
|
|
int i, ret = -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-10-06 14:07:48 +04:00
|
|
|
pr_info("========================================\n");
|
|
|
|
if (!opts->leader_only)
|
2011-09-23 12:00:45 +04:00
|
|
|
pr_info("Dumping process group (pid: %d)\n", pid);
|
2011-10-06 14:07:48 +04:00
|
|
|
else
|
|
|
|
pr_info("Dumping process (pid: %d)\n", pid);
|
|
|
|
pr_info("========================================\n");
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-03-01 19:12:35 +04:00
|
|
|
if (collect_pstree(pid, &pstree_list, opts))
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
|
2012-01-31 22:28:22 +04:00
|
|
|
if (opts->namespaces_flags) {
|
2012-03-13 18:11:00 +04:00
|
|
|
if (dump_namespaces(pid, opts->namespaces_flags) < 0)
|
2012-01-26 15:27:00 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-01-19 19:16:55 +04:00
|
|
|
/*
|
|
|
|
* Ignore collection errors by now since we may not want
|
|
|
|
* to dump the missed sockets. But later, when we will start
|
|
|
|
* dumping containers, we'll better fail here, rather than
|
|
|
|
* in the dump stage
|
|
|
|
*/
|
|
|
|
|
|
|
|
collect_sockets();
|
2011-12-26 22:12:03 +04:00
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
list_for_each_entry(item, &pstree_list, list) {
|
2012-02-08 20:19:39 +03:00
|
|
|
cr_fdset = cr_dump_fdset_open(item->pid, CR_FD_DESC_NONE, NULL);
|
2012-01-22 20:15:11 +04:00
|
|
|
if (!cr_fdset)
|
|
|
|
goto err;
|
|
|
|
|
2011-10-13 16:18:32 +04:00
|
|
|
if (item->pid == pid) {
|
2012-02-08 20:19:39 +03:00
|
|
|
if (!cr_dump_fdset_open(item->pid, CR_FD_DESC_USE(CR_FD_PSTREE), cr_fdset))
|
2011-10-13 16:18:32 +04:00
|
|
|
goto err;
|
2011-10-21 11:46:19 +04:00
|
|
|
if (dump_pstree(pid, &pstree_list, cr_fdset))
|
2011-10-13 16:18:32 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-02-29 16:06:48 +03:00
|
|
|
/*
|
|
|
|
* Prepare for socket queues in advance. They are not per-task,
|
|
|
|
* but per-someother-task which makes restore tricky. Thus save
|
|
|
|
* them in "global" image.
|
|
|
|
* That's why we open the file with tree leader's pid for any
|
|
|
|
* of it's children.
|
|
|
|
*/
|
|
|
|
if (!cr_dump_fdset_open(pid, CR_FD_DESC_USE(CR_FD_SK_QUEUES), cr_fdset))
|
|
|
|
goto err;
|
|
|
|
|
2012-01-22 20:13:59 +04:00
|
|
|
if (dump_one_task(item, cr_fdset))
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
|
2012-01-12 21:25:19 +04:00
|
|
|
close_cr_fdset(&cr_fdset);
|
2011-10-24 23:01:42 +04:00
|
|
|
|
2011-10-04 01:50:19 +04:00
|
|
|
if (opts->leader_only)
|
2011-09-23 12:00:45 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
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
|
|
|
pstree_switch_state(&pstree_list, opts);
|
2011-10-21 11:46:19 +04:00
|
|
|
free_pstree(&pstree_list);
|
2012-01-12 21:25:19 +04:00
|
|
|
close_cr_fdset(&cr_fdset);
|
2011-10-24 23:01:42 +04:00
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
return ret;
|
|
|
|
}
|