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