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

crtools: link pstree_item-s in a tree (v3)

because they describes a process TREE.

It's usefull, when we dump tasks from another pid namespace,
because a real pid is got from parasite. In previous version
we need to update pid in two places one is in a pstree_item and
one is in a children array.

A process tree will be necessery to restore sid and pgid,
because we should add fake tasks in a tree. For example if
a sesion leader is absent.

v2: fix rollback actions
v3: fix comments from Pavel Emelyanov
    * add macros for_each_pstree_item
    * and a few bugs
Signed-off-by: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent ced64e22
This diff is collapsed.
......@@ -48,7 +48,7 @@
static struct task_entries *task_entries;
static struct pstree_item *me;
static LIST_HEAD(tasks);
static struct pstree_item *root_item = NULL;
static int restore_task_with_children(void *);
static int sigreturn_restore(pid_t pid, struct list_head *vmas, int nr_vmas);
......@@ -70,6 +70,7 @@ static int shmem_remap(void *old_addr, void *new_addr, unsigned long size)
static int prepare_pstree(void)
{
int ret = 0, ps_fd;
struct pstree_item *pi, *parent = NULL;
pr_info("Reading image tree\n");
......@@ -88,37 +89,46 @@ static int prepare_pstree(void)
while (1) {
struct pstree_entry e;
struct pstree_item *pi;
ret = read_img_eof(ps_fd, &e);
if (ret <= 0)
break;
ret = -1;
pi = xmalloc(sizeof(*pi));
pi = alloc_pstree_item();
if (pi == NULL)
break;
pi->rst = xzalloc(sizeof(*pi->rst));
if (pi->rst == NULL)
if (pi->rst == NULL) {
xfree(pi);
break;
}
pi->pid = e.pid;
pi->pgid = e.pgid;
pi->sid = e.sid;
ret = -1;
pi->nr_children = e.nr_children;
pi->children = xmalloc(e.nr_children * sizeof(u32));
if (!pi->children)
if (e.ppid == 0) {
BUG_ON(root_item);
root_item = pi;
pi->parent = NULL;
INIT_LIST_HEAD(&pi->list);
} else {
for_each_pstree_item(parent)
if (parent->pid == e.ppid)
break;
ret = read_img_buf(ps_fd, pi->children,
e.nr_children * sizeof(u32));
if (ret < 0)
if (parent == NULL) {
pr_err("Can't find a parent for %d", pi->pid);
xfree(pi);
break;
}
pi->parent = parent;
list_add(&pi->list, &parent->children);
}
ret = -1;
pi->nr_threads = e.nr_threads;
pi->threads = xmalloc(e.nr_threads * sizeof(u32));
if (!pi->threads)
......@@ -129,7 +139,6 @@ static int prepare_pstree(void)
if (ret < 0)
break;
list_add_tail(&pi->list, &tasks);
task_entries->nr += e.nr_threads;
task_entries->nr_tasks++;
}
......@@ -178,7 +187,7 @@ static int prepare_shared(void)
if (collect_inotify())
return -1;
list_for_each_entry(pi, &tasks, list) {
for_each_pstree_item(pi) {
ret = prepare_shmem_pid(pi->pid);
if (ret < 0)
break;
......@@ -464,16 +473,18 @@ static int restore_one_task(int pid)
*/
#define STACK_SIZE (8 * 4096)
struct cr_clone_arg {
int pid, fd;
struct pstree_item *item;
unsigned long clone_flags;
int fd;
};
static inline int fork_with_pid(int pid, unsigned long ns_clone_flags)
static inline int fork_with_pid(struct pstree_item *item, unsigned long ns_clone_flags)
{
int ret = -1;
char buf[32];
struct cr_clone_arg ca;
void *stack;
pid_t pid = item->pid;
pr_info("Forking task with %d pid (flags 0x%lx)\n", pid, ns_clone_flags);
......@@ -485,7 +496,7 @@ static inline int fork_with_pid(int pid, unsigned long ns_clone_flags)
}
snprintf(buf, sizeof(buf), "%d", pid - 1);
ca.pid = pid;
ca.item = item;
ca.clone_flags = ns_clone_flags;
ca.fd = open(LAST_PID_PATH, O_RDWR);
if (ca.fd < 0) {
......@@ -591,15 +602,18 @@ static void restore_pgid(void)
static int restore_task_with_children(void *_arg)
{
struct cr_clone_arg *ca = _arg;
struct pstree_item *child;
pid_t pid;
int ret, i;
int ret;
sigset_t blockmask;
close_safe(&ca->fd);
me = ca->item;
pid = getpid();
if (ca->pid != pid) {
pr_err("Pid %d do not match expected %d\n", pid, ca->pid);
if (me->pid != pid) {
pr_err("Pid %d do not match expected %d\n", pid, me->pid);
exit(-1);
}
......@@ -607,15 +621,6 @@ static int restore_task_with_children(void *_arg)
if (ret < 0)
exit(1);
list_for_each_entry(me, &tasks, list)
if (me->pid == pid)
break;
if (me == list_entry(&tasks, struct pstree_item, list)) {
pr_err("Pid %d not found in pstree image\n", pid);
exit(1);
}
if (ca->clone_flags) {
ret = prepare_namespace(me->pid, ca->clone_flags);
if (ret)
......@@ -637,9 +642,9 @@ static int restore_task_with_children(void *_arg)
exit(1);
}
pr_info("Restoring %d children:\n", me->nr_children);
for (i = 0; i < me->nr_children; i++) {
ret = fork_with_pid(me->children[i], 0);
pr_info("Restoring children:\n");
list_for_each_entry(child, &me->children, list) {
ret = fork_with_pid(child, 0);
if (ret < 0)
exit(1);
}
......@@ -652,11 +657,10 @@ static int restore_task_with_children(void *_arg)
return restore_one_task(me->pid);
}
static int restore_root_task(pid_t pid, struct cr_options *opts)
static int restore_root_task(struct pstree_item *init, struct cr_options *opts)
{
int ret;
struct sigaction act, old_act;
struct pstree_item *init;
ret = sigaction(SIGCHLD, NULL, &act);
if (ret < 0) {
......@@ -672,13 +676,6 @@ static int restore_root_task(pid_t pid, struct cr_options *opts)
return -1;
}
init = list_first_entry(&tasks, struct pstree_item, list);
if (init->pid != pid) {
pr_err("Pids mismatch. Init has pid %d, requested %d\n",
init->pid, pid);
return -1;
}
/*
* FIXME -- currently we assume that all the tasks live
* in the same set of namespaces. This is done to debug
......@@ -686,7 +683,7 @@ static int restore_root_task(pid_t pid, struct cr_options *opts)
* this later.
*/
ret = fork_with_pid(init->pid, opts->namespaces_flags);
ret = fork_with_pid(init, opts->namespaces_flags);
if (ret < 0)
return -1;
......@@ -705,11 +702,12 @@ static int restore_root_task(pid_t pid, struct cr_options *opts)
out:
if (ret < 0) {
pr_err("Someone can't be restored\n");
struct pstree_item *pi;
pr_err("Someone can't be restored\n");
list_for_each_entry(pi, &tasks, list)
for_each_pstree_item(pi)
kill(pi->pid, SIGKILL);
return 1;
}
......@@ -746,7 +744,7 @@ static int restore_all_tasks(pid_t pid, struct cr_options *opts)
if (prepare_shared() < 0)
return -1;
return restore_root_task(pid, opts);
return restore_root_task(root_item, opts);
}
#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)
......
......@@ -418,8 +418,8 @@ static int show_collect_pstree(int fd_pstree, struct list_head *collect)
ret = read_img_eof(fd_pstree, &e);
if (ret <= 0)
goto out;
pr_msg("pid: %8d pgid: %8d sid %8d nr_children: %8d nr_threads: %8d\n",
e.pid, e.pgid, e.sid, e.nr_children, e.nr_threads);
pr_msg("pid: %8d ppid %8d pgid: %8d sid %8d nr_threads: %8d\n",
e.pid, e.ppid, e.pgid, e.sid, e.nr_threads);
if (collect) {
item = xzalloc(sizeof(struct pstree_item));
......@@ -437,18 +437,6 @@ static int show_collect_pstree(int fd_pstree, struct list_head *collect)
list_add_tail(&item->list, collect);
}
if (e.nr_children) {
pr_msg("\\\n");
pr_msg(" +--- children: ");
while (e.nr_children--) {
ret = read_img(fd_pstree, &pid);
if (ret < 0)
goto out;
pr_msg(" %6d", pid);
}
pr_msg("\n");
}
if (e.nr_threads) {
pr_msg(" \\\n");
pr_msg(" --- threads: ");
......@@ -640,7 +628,7 @@ err:
static int cr_show_all(struct cr_options *opts)
{
struct pstree_item *item = NULL;
struct pstree_item *item = NULL, *tmp;
LIST_HEAD(pstree_list);
int i, ret = -1, fd, pid;
......@@ -709,7 +697,11 @@ static int cr_show_all(struct cr_options *opts)
}
out:
free_pstree(&pstree_list);
list_for_each_entry_safe(item, tmp, &pstree_list, list) {
list_del(&item->list);
xfree(item->threads);
xfree(item);
}
return ret;
}
......
......@@ -3,13 +3,12 @@
#include <sys/types.h>
#include "list.h"
#include "types.h"
#include "list.h"
#include "util.h"
#include "image.h"
extern void free_pstree(struct list_head *pstree_list);
#define CR_FD_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
#define CR_FD_PERM_DUMP (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
......@@ -180,16 +179,21 @@ struct pstree_item {
struct list_head list;
pid_t pid; /* leader pid */
struct pstree_item *parent;
struct list_head children; /* array of children */
pid_t pgid;
pid_t sid;
int state; /* TASK_XXX constants */
int nr_children; /* number of children */
int nr_threads; /* number of threads */
u32 *threads; /* array of threads */
u32 *children; /* array of children */
struct rst_info *rst;
};
extern struct pstree_item *alloc_pstree_item(void);
extern struct pstree_item *pstree_item_next(struct pstree_item *item);
#define for_each_pstree_item(pi) \
for (pi = root_item; pi != NULL; pi = pstree_item_next(pi))
static inline int in_vma_area(struct vma_area *vma, unsigned long addr)
{
return addr >= (unsigned long)vma->vma.start &&
......
......@@ -141,9 +141,9 @@ struct fs_entry {
struct pstree_entry {
u32 pid;
u32 ppid;
u32 pgid;
u32 sid;
u32 nr_children;
u32 nr_threads;
} __packed;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment