From 8a7dc1da8fe84286faefaeb7ddfe8086df272837 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Fri, 7 Sep 2012 19:17:18 +0400 Subject: [PATCH] dump: dump zombies from another PID namespace The problem is to get a virtual pid for zombies. This code gets two list of children from current and target pidns. Then it removes alive task from the second list and dumps remaining zombies. A procfs from a target pidns is needed for dumping zombies, crtools gets it from parasite code. v2: Fix comment and get proc fd from a root task Signed-off-by: Andrey Vagin Signed-off-by: Pavel Emelyanov --- cr-dump.c | 104 ++++++++++++++++++++++++++++++++++++++++++++------- test/zdtm.sh | 4 +- 2 files changed, 92 insertions(+), 16 deletions(-) diff --git a/cr-dump.c b/cr-dump.c index c9420e9b9..7a7b795d3 100644 --- a/cr-dump.c +++ b/cr-dump.c @@ -1339,6 +1339,89 @@ static int dump_task_threads(struct parasite_ctl *parasite_ctl, return 0; } +static int fill_zombies_pids(struct pstree_item *item) +{ + struct pstree_item *child; + int i, nr; + pid_t *ch; + + if (parse_children(item->pid.virt, &ch, &nr) < 0) + return -1; + + list_for_each_entry(child, &item->children, list) { + if (child->pid.virt < 0) + continue; + for (i = 0; i < nr; i++) { + if (ch[i] == child->pid.virt) { + ch[i] = -1; + break; + } + } + } + + i = 0; + list_for_each_entry(child, &item->children, list) { + if (child->pid.virt > 0) + continue; + for (; i < nr; i++) { + if (ch[i] < 0) + continue; + child->pid.virt = ch[i]; + ch[i] = -1; + break; + } + BUG_ON(i == nr); + } + + return 0; +} + +static int dump_zombies() +{ + struct pstree_item *item; + int oldfd, ret = -1; + int pidns = opts.namespaces_flags & CLONE_NEWPID; + + if (pidns) { + oldfd = set_proc_fd(pidns_proc); + if (oldfd < 0) + return -1; + } + + for_each_pstree_item(item) { + if (item->state != TASK_DEAD) + continue; + + if (item->pid.virt < 0) { + if (!pidns) + item->pid.virt = item->pid.real; + else if (root_item == item) { + pr_err("A root task is dead\n"); + goto err; + } else if (fill_zombies_pids(item->parent)) + goto err; + } + + pr_info("Obtainting zombie stat ... "); + if (parse_pid_stat(item->pid.virt, &pps_buf) < 0) + goto err; + + item->sid = pps_buf.sid; + item->pgid = pps_buf.pgid; + + BUG_ON(!list_empty(&item->children)); + if (dump_one_zombie(item, &pps_buf) < 0) + goto err; + } + + ret = 0; +err: + if (pidns) + close_proc(); + + return ret; +} + static int dump_one_task(struct pstree_item *item) { pid_t pid = item->pid.real; @@ -1358,6 +1441,9 @@ static int dump_one_task(struct pstree_item *item) return -1; } + if (item->state == TASK_DEAD) + return 0; + dfds = xmalloc(sizeof(*dfds)); if (!dfds) goto err_free; @@ -1367,19 +1453,6 @@ static int dump_one_task(struct pstree_item *item) if (ret < 0) goto err; - if (item->state == TASK_DEAD) { - /* FIXME don't support zombie in pid name space*/ - if (root_item->pid.virt == 1) { - pr_err("Can't dump a zombie %d in PIDNS", item->pid.real); - ret = -1; - goto err; - } - item->pid.virt = item->pid.real; - - BUG_ON(!list_empty(&item->children)); - return dump_one_zombie(item, &pps_buf); - } - ret = collect_mappings(pid, &vma_area_list); if (ret) { pr_err("Collect mappings (pid: %d) failed with %d\n", pid, ret); @@ -1399,7 +1472,7 @@ static int dump_one_task(struct pstree_item *item) goto err; } - if (opts.namespaces_flags & CLONE_NEWPID && pidns_proc < 0) { + if (opts.namespaces_flags & CLONE_NEWPID && root_item == item) { pidns_proc = parasite_get_proc_fd_seized(parasite_ctl); if (pidns_proc < 0) { pr_err("Can't get proc fd (pid: %d)\n", pid); @@ -1536,6 +1609,9 @@ int cr_dump_tasks(pid_t pid, const struct cr_options *opts) goto err; } + if (dump_zombies()) + goto err; + if (dump_pstree(root_item)) goto err; diff --git a/test/zdtm.sh b/test/zdtm.sh index 027caa719..43b2694d3 100644 --- a/test/zdtm.sh +++ b/test/zdtm.sh @@ -52,14 +52,14 @@ static/fifo-rowo-pair static/fifo-ghost static/fifo static/fifo_wronly +static/zombie00 +transition/fork " # Duplicate list with ns/ prefix TEST_LIST=$TEST_LIST$(echo $TEST_LIST | tr ' ' '\n' | sed 's#^#ns/#') # These ones are not in ns TEST_LIST="$TEST_LIST -static/zombie00 -transition/fork static/file_fown static/socket-ext "