2012-07-18 07:23:05 +04:00
|
|
|
#include <sys/time.h>
|
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>
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/vfs.h>
|
|
|
|
|
|
|
|
#include <sys/sendfile.h>
|
2012-05-29 20:11:00 +04:00
|
|
|
#include <sys/mman.h>
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-10-17 00:23:25 +04:00
|
|
|
#include <sched.h>
|
|
|
|
#include <sys/resource.h>
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
#include "protobuf.h"
|
|
|
|
#include "protobuf/fdinfo.pb-c.h"
|
|
|
|
#include "protobuf/fs.pb-c.h"
|
|
|
|
#include "protobuf/mm.pb-c.h"
|
|
|
|
#include "protobuf/creds.pb-c.h"
|
|
|
|
#include "protobuf/core.pb-c.h"
|
2013-01-17 16:09:32 +08:00
|
|
|
#include "protobuf/file-lock.pb-c.h"
|
2013-01-10 20:08:38 +04:00
|
|
|
#include "protobuf/rlimit.pb-c.h"
|
2012-10-11 15:59:43 +04:00
|
|
|
|
2013-01-09 17:02:47 +04:00
|
|
|
#include "asm/types.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
#include "list.h"
|
2012-02-28 18:27:28 +04:00
|
|
|
#include "file-ids.h"
|
2012-04-09 18:02:00 +04:00
|
|
|
#include "kcmp-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"
|
2012-03-28 17:36:00 +04:00
|
|
|
#include "parasite.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
#include "parasite-syscall.h"
|
2012-03-29 16:40:10 +04:00
|
|
|
#include "files.h"
|
2012-06-20 20:00:30 +04:00
|
|
|
#include "files-reg.h"
|
2012-05-03 18:07:01 +04:00
|
|
|
#include "shmem.h"
|
2012-04-28 17:38:46 +04:00
|
|
|
#include "sk-inet.h"
|
2012-06-26 14:51:00 +04:00
|
|
|
#include "pstree.h"
|
2012-08-01 07:00:48 +04:00
|
|
|
#include "mount.h"
|
2012-09-12 20:00:54 +04:00
|
|
|
#include "tty.h"
|
2012-09-17 20:05:55 +04:00
|
|
|
#include "net.h"
|
2012-11-02 16:00:18 +03:00
|
|
|
#include "sk-packet.h"
|
2012-12-21 17:35:36 +04:00
|
|
|
#include "cpu.h"
|
2012-12-21 17:35:39 +04:00
|
|
|
#include "elf.h"
|
2013-01-17 16:09:32 +08:00
|
|
|
#include "file-lock.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2013-01-09 17:27:49 +04:00
|
|
|
#include "asm/dump.h"
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
static char loc_buf[PAGE_SIZE];
|
2012-09-07 19:16:36 +04:00
|
|
|
static int pidns_proc = -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2013-03-01 20:12:02 +04:00
|
|
|
bool privately_dump_vma(struct vma_area *vma)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The special areas are not dumped.
|
|
|
|
*/
|
|
|
|
if (!(vma->vma.status & VMA_AREA_REGULAR))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* No dumps for file-shared mappings */
|
|
|
|
if (vma->vma.status & VMA_FILE_SHARED)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* No dumps for SYSV IPC mappings */
|
|
|
|
if (vma->vma.status & VMA_AREA_SYSVIPC)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vma_area_is(vma, VMA_ANON_SHARED))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!vma_area_is(vma, VMA_ANON_PRIVATE) &&
|
|
|
|
!vma_area_is(vma, VMA_FILE_PRIVATE)) {
|
|
|
|
pr_warn("Unexpected VMA area found\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vma->vma.end > TASK_SIZE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-01 20:11:51 +04:00
|
|
|
void free_mappings(struct vm_area_list *vma_area_list)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct vma_area *vma_area, *p;
|
|
|
|
|
2013-03-01 20:11:51 +04:00
|
|
|
list_for_each_entry_safe(vma_area, p, &vma_area_list->h, 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);
|
|
|
|
}
|
|
|
|
|
2013-03-01 20:11:51 +04:00
|
|
|
INIT_LIST_HEAD(&vma_area_list->h);
|
|
|
|
vma_area_list->nr = 0;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2013-03-01 20:11:51 +04:00
|
|
|
int collect_mappings(pid_t pid, struct vm_area_list *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-05-10 21:07:00 +04:00
|
|
|
ret = parse_smaps(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;
|
|
|
|
|
2013-03-01 20:12:33 +04:00
|
|
|
pr_info("Collected, longest ares %lu bytes\n", vma_area_list->longest);
|
2013-03-01 20:11:51 +04:00
|
|
|
pr_info_vma_list(&vma_area_list->h);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-10-17 00:23:25 +04:00
|
|
|
static int dump_sched_info(int pid, ThreadCoreEntry *tc)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct sched_param sp;
|
|
|
|
|
|
|
|
BUILD_BUG_ON(SCHED_OTHER != 0); /* default in proto message */
|
|
|
|
|
|
|
|
ret = sched_getscheduler(pid);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("Can't get sched policy for %d", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("%d has %d sched policy\n", pid, ret);
|
|
|
|
tc->has_sched_policy = true;
|
|
|
|
tc->sched_policy = ret;
|
|
|
|
|
|
|
|
if ((ret == SCHED_RR) || (ret == SCHED_FIFO)) {
|
|
|
|
ret = sched_getparam(pid, &sp);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("Can't get sched param for %d", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("\tdumping %d prio for %d\n", sp.sched_priority, pid);
|
|
|
|
tc->has_sched_prio = true;
|
|
|
|
tc->sched_prio = sp.sched_priority;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The nice is ignored for RT sched policies, but is stored
|
|
|
|
* in kernel. Thus we have to take it with us in the image.
|
|
|
|
*/
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
ret = getpriority(PRIO_PROCESS, pid);
|
|
|
|
if (errno) {
|
|
|
|
pr_perror("Can't get nice for %d", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("\tdumping %d nice for %d\n", ret, pid);
|
|
|
|
tc->has_sched_nice = true;
|
|
|
|
tc->sched_nice = ret;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-03-26 17:47:38 +04:00
|
|
|
struct cr_fdset *glob_fdset;
|
2012-03-25 20:24:53 +04:00
|
|
|
|
2012-08-21 19:59:07 +04:00
|
|
|
static int collect_fds(pid_t pid, struct parasite_drain_fd *dfds)
|
2012-03-28 17:36:00 +04:00
|
|
|
{
|
|
|
|
struct dirent *de;
|
|
|
|
DIR *fd_dir;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
pr_info("\n");
|
|
|
|
pr_info("Collecting fds (pid: %d)\n", pid);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
|
|
|
fd_dir = opendir_proc(pid, "fd");
|
|
|
|
if (!fd_dir)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
while ((de = readdir(fd_dir))) {
|
2012-11-29 21:12:51 +03:00
|
|
|
if (dir_dots(de))
|
2012-03-28 17:36:00 +04:00
|
|
|
continue;
|
|
|
|
|
2012-08-21 19:59:07 +04:00
|
|
|
if (n > PARASITE_MAX_FDS - 1)
|
2012-03-28 17:36:00 +04:00
|
|
|
return -ENOMEM;
|
2012-08-21 19:59:07 +04:00
|
|
|
|
|
|
|
dfds->fds[n++] = atoi(de->d_name);
|
2012-03-28 17:36:00 +04:00
|
|
|
}
|
|
|
|
|
2012-08-21 19:59:07 +04:00
|
|
|
dfds->nr_fds = n;
|
2012-03-28 17:36:00 +04:00
|
|
|
pr_info("Found %d file descriptors\n", n);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
|
|
|
closedir(fd_dir);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-18 20:54:00 +04:00
|
|
|
static int dump_task_exe_link(pid_t pid, MmEntry *mm)
|
2011-12-07 17:11:00 +04:00
|
|
|
{
|
2012-07-19 09:39:00 +04:00
|
|
|
struct fd_parms params = FD_PARMS_INIT;
|
2012-02-07 19:20:17 +04:00
|
|
|
int fd, ret;
|
2011-12-07 17:11:00 +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-04-09 15:52:00 +04:00
|
|
|
|
|
|
|
if (fstat(fd, ¶ms.stat) < 0) {
|
|
|
|
pr_perror("Can't fstat exe link");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
mm->exe_file_id = fd_id_generate_special();
|
|
|
|
|
|
|
|
ret = dump_one_reg_file(fd, mm->exe_file_id, ¶ms);
|
2012-03-29 16:40:50 +04:00
|
|
|
close(fd);
|
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
|
|
|
|
2013-01-10 12:48:31 +03:00
|
|
|
static int dump_task_fs(pid_t pid, struct parasite_dump_misc *misc, struct cr_fdset *fdset)
|
2012-04-09 13:41:05 +04:00
|
|
|
{
|
2012-07-19 09:39:00 +04:00
|
|
|
struct fd_parms p = FD_PARMS_INIT;
|
2012-07-17 07:28:38 +04:00
|
|
|
FsEntry fe = FS_ENTRY__INIT;
|
2012-04-09 13:41:05 +04:00
|
|
|
int fd, ret;
|
|
|
|
|
2013-01-10 12:48:31 +03:00
|
|
|
fe.has_umask = true;
|
|
|
|
fe.umask = misc->umask;
|
|
|
|
|
2012-04-09 13:41:05 +04:00
|
|
|
fd = open_proc(pid, "cwd");
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (fstat(fd, &p.stat) < 0) {
|
|
|
|
pr_perror("Can't stat cwd");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fe.cwd_id = fd_id_generate_special();
|
|
|
|
|
|
|
|
ret = dump_one_reg_file(fd, fe.cwd_id, &p);
|
2012-04-09 13:52:42 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
fd = open_proc(pid, "root");
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (fstat(fd, &p.stat) < 0) {
|
|
|
|
pr_perror("Can't stat root");
|
|
|
|
return -1;
|
2012-04-09 13:41:05 +04:00
|
|
|
}
|
|
|
|
|
2012-04-09 13:52:42 +04:00
|
|
|
fe.root_id = fd_id_generate_special();
|
|
|
|
|
|
|
|
ret = dump_one_reg_file(fd, fe.root_id, &p);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2012-04-09 13:41:05 +04:00
|
|
|
close(fd);
|
2012-04-09 13:52:42 +04:00
|
|
|
|
2012-04-24 15:20:24 +04:00
|
|
|
pr_info("Dumping task cwd id %#x root id %#x\n",
|
2012-04-09 13:52:42 +04:00
|
|
|
fe.cwd_id, fe.root_id);
|
|
|
|
|
2012-08-07 02:26:50 +04:00
|
|
|
return pb_write_one(fdset_fd(fdset, CR_FD_FS), &fe, PB_FS);
|
2012-04-09 13:41:05 +04:00
|
|
|
}
|
|
|
|
|
2013-01-10 20:08:38 +04:00
|
|
|
static inline u_int64_t encode_rlim(unsigned long val)
|
|
|
|
{
|
|
|
|
return val == RLIM_INFINITY ? -1 : val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dump_task_rlims(int pid, struct cr_fdset *fds)
|
|
|
|
{
|
|
|
|
int res, fd;
|
|
|
|
|
|
|
|
fd = fdset_fd(fds, CR_FD_RLIMIT);
|
|
|
|
|
|
|
|
for (res = 0; res < RLIM_NLIMITS; res++) {
|
|
|
|
struct rlimit lim;
|
|
|
|
RlimitEntry re = RLIMIT_ENTRY__INIT;
|
|
|
|
|
|
|
|
if (prlimit(pid, res, NULL, &lim)) {
|
|
|
|
pr_perror("Can't get rlimit %d", res);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
re.cur = encode_rlim(lim.rlim_cur);
|
|
|
|
re.max = encode_rlim(lim.rlim_max);
|
|
|
|
|
|
|
|
if (pb_write_one(fd, &re, PB_RLIMIT))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-19 12:43:36 +04:00
|
|
|
static int dump_filemap(pid_t pid, VmaEntry *vma, int file_fd,
|
2012-03-21 11:33:54 +04:00
|
|
|
const struct cr_fdset *fdset)
|
|
|
|
{
|
2012-07-19 09:39:00 +04:00
|
|
|
struct fd_parms p = FD_PARMS_INIT;
|
2012-03-21 11:33:54 +04:00
|
|
|
|
2012-04-09 12:57:38 +04:00
|
|
|
if (fstat(file_fd, &p.stat) < 0) {
|
|
|
|
pr_perror("Can't stat file for vma");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-03-21 11:33:54 +04:00
|
|
|
if ((vma->prot & PROT_WRITE) && vma_entry_is(vma, VMA_FILE_SHARED))
|
|
|
|
p.flags = O_RDWR;
|
|
|
|
else
|
|
|
|
p.flags = O_RDONLY;
|
2012-04-09 12:57:38 +04:00
|
|
|
vma->shmid = fd_id_generate_special();
|
2012-03-21 11:33:54 +04:00
|
|
|
|
2012-04-09 12:57:38 +04:00
|
|
|
return dump_one_reg_file(file_fd, vma->shmid, &p);
|
2012-03-21 11:33:54 +04:00
|
|
|
}
|
|
|
|
|
2013-03-01 20:11:51 +04:00
|
|
|
static int dump_task_mappings(pid_t pid, const struct vm_area_list *vma_area_list,
|
2012-03-06 14:20:00 +04:00
|
|
|
const struct cr_fdset *cr_fdset)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct vma_area *vma_area;
|
2012-03-26 17:43:29 +04:00
|
|
|
int ret = -1, fd;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info("\n");
|
|
|
|
pr_info("Dumping mappings (pid: %d)\n", pid);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
2012-03-26 17:43:29 +04:00
|
|
|
fd = fdset_fd(cr_fdset, CR_FD_VMAS);
|
|
|
|
|
2013-03-01 20:11:51 +04:00
|
|
|
list_for_each_entry(vma_area, &vma_area_list->h, list) {
|
2012-07-19 12:43:36 +04:00
|
|
|
VmaEntry *vma = &vma_area->vma;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info_vma(vma_area);
|
|
|
|
|
2012-04-09 12:57:38 +04:00
|
|
|
if (!vma_entry_is(vma, VMA_AREA_REGULAR) ||
|
|
|
|
vma_entry_is(vma, VMA_AREA_SYSVIPC))
|
|
|
|
ret = 0;
|
|
|
|
else if (vma_entry_is(vma, VMA_ANON_SHARED))
|
2012-03-21 11:33:54 +04:00
|
|
|
ret = add_shmem_area(pid, vma);
|
|
|
|
else if (vma_entry_is(vma, VMA_FILE_PRIVATE) ||
|
|
|
|
vma_entry_is(vma, VMA_FILE_SHARED))
|
|
|
|
ret = dump_filemap(pid, vma, vma_area->vm_file_fd, cr_fdset);
|
2012-11-02 16:00:18 +03:00
|
|
|
else if (vma_entry_is(vma, VMA_AREA_SOCKET))
|
|
|
|
ret = dump_socket_map(vma_area);
|
2012-03-21 14:22:00 +04:00
|
|
|
else
|
|
|
|
ret = 0;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-04-09 12:57:38 +04:00
|
|
|
if (!ret)
|
2012-08-07 02:26:50 +04:00
|
|
|
ret = pb_write_one(fd, vma, PB_VMAS);
|
2012-03-21 11:33:54 +04:00
|
|
|
if (ret)
|
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
static int dump_task_creds(struct parasite_ctl *ctl, const struct cr_fdset *fds)
|
2012-01-27 21:43:32 +04:00
|
|
|
{
|
2012-07-19 12:35:25 +04:00
|
|
|
int ret;
|
2012-01-27 21:43:32 +04:00
|
|
|
struct proc_status_creds cr;
|
2012-07-19 12:35:25 +04:00
|
|
|
CredsEntry ce = CREDS_ENTRY__INIT;
|
2012-01-27 21:43:32 +04:00
|
|
|
|
|
|
|
pr_info("\n");
|
2012-10-11 15:59:43 +04:00
|
|
|
pr_info("Dumping creds for %d)\n", ctl->pid);
|
2012-01-27 21:43:32 +04:00
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
ret = parse_pid_status(ctl->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);
|
|
|
|
|
2012-07-19 12:35:25 +04:00
|
|
|
ce.n_cap_inh = CR_CAP_SIZE;
|
|
|
|
ce.cap_inh = cr.cap_inh;
|
|
|
|
ce.n_cap_prm = CR_CAP_SIZE;
|
|
|
|
ce.cap_prm = cr.cap_prm;
|
|
|
|
ce.n_cap_eff = CR_CAP_SIZE;
|
|
|
|
ce.cap_eff = cr.cap_eff;
|
|
|
|
ce.n_cap_bnd = CR_CAP_SIZE;
|
|
|
|
ce.cap_bnd = cr.cap_bnd;
|
2012-01-27 21:43:32 +04:00
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
if (parasite_dump_creds(ctl, &ce) < 0)
|
|
|
|
return -1;
|
2012-01-27 21:43:32 +04:00
|
|
|
|
2012-08-07 02:26:50 +04:00
|
|
|
return pb_write_one(fdset_fd(fds, CR_FD_CREDS), &ce, PB_CREDS);
|
2012-01-27 21:43:32 +04:00
|
|
|
}
|
|
|
|
|
2012-10-29 19:54:12 +04:00
|
|
|
static int get_task_auxv(pid_t pid, MmEntry *mm, size_t *size)
|
2012-01-23 15:22:00 +04:00
|
|
|
{
|
2012-04-09 14:51:37 +04:00
|
|
|
int fd, ret, i;
|
|
|
|
|
|
|
|
pr_info("Obtainting task auvx ... ");
|
2012-01-23 15:22:00 +04:00
|
|
|
|
2012-04-09 14:51:37 +04:00
|
|
|
fd = open_proc(pid, "auxv");
|
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++) {
|
2012-04-09 14:51:37 +04:00
|
|
|
ret = read(fd, &mm->mm_saved_auxv[i],
|
2013-01-09 17:40:33 +04:00
|
|
|
sizeof(auxv_t));
|
2012-01-23 15:22:00 +04:00
|
|
|
if (ret == 0)
|
|
|
|
break;
|
2013-01-09 17:40:33 +04:00
|
|
|
else if (ret != sizeof(auxv_t)) {
|
2012-01-23 15:22:00 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-29 19:54:12 +04:00
|
|
|
*size = i;
|
2012-01-23 15:22:00 +04:00
|
|
|
ret = 0;
|
|
|
|
err:
|
|
|
|
close_safe(&fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-04-09 14:51:37 +04:00
|
|
|
static int dump_task_mm(pid_t pid, const struct proc_pid_stat *stat,
|
|
|
|
const struct parasite_dump_misc *misc, const struct cr_fdset *fdset)
|
|
|
|
{
|
2012-07-18 20:54:00 +04:00
|
|
|
MmEntry mme = MM_ENTRY__INIT;
|
|
|
|
int ret = -1;
|
2012-04-09 14:51:37 +04:00
|
|
|
|
|
|
|
mme.mm_start_code = stat->start_code;
|
|
|
|
mme.mm_end_code = stat->end_code;
|
|
|
|
mme.mm_start_data = stat->start_data;
|
|
|
|
mme.mm_end_data = stat->end_data;
|
|
|
|
mme.mm_start_stack = stat->start_stack;
|
|
|
|
mme.mm_start_brk = stat->start_brk;
|
|
|
|
|
|
|
|
mme.mm_arg_start = stat->arg_start;
|
|
|
|
mme.mm_arg_end = stat->arg_end;
|
|
|
|
mme.mm_env_start = stat->env_start;
|
|
|
|
mme.mm_env_end = stat->env_end;
|
|
|
|
|
|
|
|
mme.mm_brk = misc->brk;
|
|
|
|
|
2012-07-18 20:54:00 +04:00
|
|
|
mme.n_mm_saved_auxv = AT_VECTOR_SIZE;
|
|
|
|
mme.mm_saved_auxv = xmalloc(pb_repeated_size(&mme, mm_saved_auxv));
|
|
|
|
if (!mme.mm_saved_auxv)
|
|
|
|
goto out;
|
|
|
|
|
2012-10-29 19:54:12 +04:00
|
|
|
if (get_task_auxv(pid, &mme, &mme.n_mm_saved_auxv))
|
2012-07-18 20:54:00 +04:00
|
|
|
goto out;
|
2012-04-12 15:22:06 +04:00
|
|
|
pr_info("OK\n");
|
2012-04-09 14:51:37 +04:00
|
|
|
|
2012-04-09 15:52:00 +04:00
|
|
|
if (dump_task_exe_link(pid, &mme))
|
2012-07-18 20:54:00 +04:00
|
|
|
goto out;
|
2012-04-09 15:52:00 +04:00
|
|
|
|
2012-08-07 02:26:50 +04:00
|
|
|
ret = pb_write_one(fdset_fd(fdset, CR_FD_MM), &mme, PB_MM);
|
2012-07-18 20:54:00 +04:00
|
|
|
xfree(mme.mm_saved_auxv);
|
|
|
|
out:
|
|
|
|
return ret;
|
2012-04-09 14:51:37 +04:00
|
|
|
}
|
|
|
|
|
2012-08-10 20:28:59 +04:00
|
|
|
static int get_task_futex_robust_list(pid_t pid, ThreadCoreEntry *info)
|
|
|
|
{
|
|
|
|
struct robust_list_head *head = NULL;
|
|
|
|
size_t len = 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = sys_get_robust_list(pid, &head, &len);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Failed obtaining futex robust list on %d\n", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-01-18 11:08:38 +04:00
|
|
|
info->futex_rla = encode_pointer(head);
|
2012-08-10 20:28:59 +04:00
|
|
|
info->futex_rla_len = (u32)len;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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-04-10 15:39:21 +04:00
|
|
|
pr_info("Obtainting personality ... ");
|
|
|
|
|
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)) {
|
2012-08-11 21:57:42 +04:00
|
|
|
pr_perror("Can't read task personality");
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
*personality = atoi(loc_buf);
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (file)
|
|
|
|
fclose(file);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-04-09 18:02:00 +04:00
|
|
|
static DECLARE_KCMP_TREE(vm_tree, KCMP_VM);
|
|
|
|
static DECLARE_KCMP_TREE(fs_tree, KCMP_FS);
|
|
|
|
static DECLARE_KCMP_TREE(files_tree, KCMP_FILES);
|
|
|
|
static DECLARE_KCMP_TREE(sighand_tree, KCMP_SIGHAND);
|
|
|
|
|
2013-01-11 18:16:22 +04:00
|
|
|
static int dump_task_kobj_ids(struct pstree_item *item)
|
2012-04-09 18:02:00 +04:00
|
|
|
{
|
|
|
|
int new;
|
|
|
|
struct kid_elem elem;
|
2013-01-11 18:16:22 +04:00
|
|
|
int pid = item->pid.real;
|
|
|
|
TaskKobjIdsEntry *ids = item->ids;
|
2012-04-09 18:02:00 +04:00
|
|
|
|
|
|
|
elem.pid = pid;
|
|
|
|
elem.idx = 0; /* really 0 for all */
|
|
|
|
elem.genid = 0; /* FIXME optimize */
|
|
|
|
|
|
|
|
new = 0;
|
2013-01-11 18:16:21 +04:00
|
|
|
ids->vm_id = kid_generate_gen(&vm_tree, &elem, &new);
|
|
|
|
if (!ids->vm_id || !new) {
|
2012-04-09 18:02:00 +04:00
|
|
|
pr_err("Can't make VM id for %d\n", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
new = 0;
|
2013-01-11 18:16:21 +04:00
|
|
|
ids->fs_id = kid_generate_gen(&fs_tree, &elem, &new);
|
|
|
|
if (!ids->fs_id || !new) {
|
2012-04-09 18:02:00 +04:00
|
|
|
pr_err("Can't make FS id for %d\n", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
new = 0;
|
2013-01-11 18:16:21 +04:00
|
|
|
ids->files_id = kid_generate_gen(&files_tree, &elem, &new);
|
2013-01-12 00:44:26 +04:00
|
|
|
if (!ids->files_id || (!new && !shared_fdtable(item))) {
|
2012-04-09 18:02:00 +04:00
|
|
|
pr_err("Can't make FILES id for %d\n", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
new = 0;
|
2013-01-11 18:16:21 +04:00
|
|
|
ids->sighand_id = kid_generate_gen(&sighand_tree, &elem, &new);
|
|
|
|
if (!ids->sighand_id || !new) {
|
2012-04-09 18:02:00 +04:00
|
|
|
pr_err("Can't make IO id for %d\n", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-19 13:23:01 +04:00
|
|
|
static CoreEntry *core_entry_alloc(int alloc_thread_info,
|
2013-01-11 18:16:21 +04:00
|
|
|
int alloc_tc)
|
2012-07-19 13:23:01 +04:00
|
|
|
{
|
|
|
|
CoreEntry *core;
|
|
|
|
TaskCoreEntry *tc;
|
|
|
|
|
|
|
|
core = xmalloc(sizeof(*core));
|
|
|
|
if (!core)
|
|
|
|
return NULL;
|
|
|
|
core_entry__init(core);
|
|
|
|
|
2013-01-14 11:25:50 +04:00
|
|
|
core->mtype = CORE_ENTRY__MARCH;
|
2012-07-19 13:23:01 +04:00
|
|
|
|
|
|
|
if (alloc_thread_info) {
|
2013-01-09 17:27:53 +04:00
|
|
|
if (arch_alloc_thread_info(core))
|
2012-07-19 13:23:01 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (alloc_tc) {
|
|
|
|
tc = xzalloc(sizeof(*tc) + TASK_COMM_LEN);
|
|
|
|
if (!tc)
|
|
|
|
goto err;
|
|
|
|
task_core_entry__init(tc);
|
|
|
|
tc->comm = (void *)tc + sizeof(*tc);
|
|
|
|
core->tc = tc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return core;
|
|
|
|
err:
|
|
|
|
core_entry_free(core);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-01-18 13:18:35 +04:00
|
|
|
int get_task_ids(struct pstree_item *item)
|
2013-01-11 18:16:21 +04:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2013-01-11 18:16:22 +04:00
|
|
|
item->ids = xmalloc(sizeof(*item->ids));
|
|
|
|
if (!item->ids)
|
2013-01-18 13:18:35 +04:00
|
|
|
goto err;
|
|
|
|
|
2013-01-11 18:16:22 +04:00
|
|
|
task_kobj_ids_entry__init(item->ids);
|
2013-01-11 18:16:21 +04:00
|
|
|
|
2013-01-17 17:48:19 +04:00
|
|
|
if (item->state != TASK_DEAD) {
|
|
|
|
ret = dump_task_kobj_ids(item);
|
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
2013-01-11 18:16:21 +04:00
|
|
|
|
2013-01-17 17:48:19 +04:00
|
|
|
ret = dump_task_ns_ids(item);
|
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
|
|
|
}
|
2013-01-18 13:18:33 +04:00
|
|
|
|
2013-01-18 13:18:35 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_free:
|
|
|
|
xfree(item->ids);
|
|
|
|
item->ids = NULL;
|
|
|
|
err:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dump_task_ids(struct pstree_item *item, const struct cr_fdset *cr_fdset)
|
|
|
|
{
|
2013-01-17 17:48:19 +04:00
|
|
|
return pb_write_one(fdset_fd(cr_fdset, CR_FD_IDS), item->ids, PB_IDS);
|
2013-01-11 18:16:21 +04:00
|
|
|
}
|
|
|
|
|
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,
|
2012-09-07 18:21:04 +04:00
|
|
|
const struct cr_fdset *cr_fdset,
|
2013-03-01 20:11:51 +04:00
|
|
|
struct vm_area_list *vma_area_list)
|
2011-10-20 17:19:26 +04:00
|
|
|
{
|
2012-07-19 13:23:01 +04:00
|
|
|
int fd_core = fdset_fd(cr_fdset, CR_FD_CORE);
|
|
|
|
CoreEntry *core;
|
2012-04-10 15:41:16 +04:00
|
|
|
int ret = -1;
|
2011-10-20 17:19:26 +04:00
|
|
|
|
2013-01-11 18:16:21 +04:00
|
|
|
core = core_entry_alloc(1, 1);
|
2012-07-19 13:23:01 +04:00
|
|
|
if (!core)
|
|
|
|
return -1;
|
|
|
|
|
2011-10-20 17:19:26 +04:00
|
|
|
pr_info("\n");
|
|
|
|
pr_info("Dumping core (pid: %d)\n", pid);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
2012-04-10 15:41:16 +04:00
|
|
|
ret = dump_task_mm(pid, stat, misc, cr_fdset);
|
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
|
|
|
|
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;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2013-03-01 20:11:51 +04:00
|
|
|
mark_stack_vma(CORE_THREAD_ARCH_INFO(core)->gpregs->sp, &vma_area_list->h);
|
2012-09-07 18:21:04 +04:00
|
|
|
|
2012-08-10 20:28:59 +04:00
|
|
|
ret = get_task_futex_robust_list(pid, core->thread_core);
|
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
|
|
|
|
2012-07-19 13:23:01 +04:00
|
|
|
ret = get_task_personality(pid, &core->tc->personality);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
|
|
|
|
2012-07-19 13:23:01 +04:00
|
|
|
strncpy((char *)core->tc->comm, stat->comm, TASK_COMM_LEN);
|
|
|
|
core->tc->flags = stat->flags;
|
|
|
|
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-07-19 13:23:01 +04:00
|
|
|
core->tc->task_state = TASK_ALIVE;
|
|
|
|
core->tc->exit_code = 0;
|
2012-01-22 20:24:04 +04:00
|
|
|
|
2012-10-17 00:23:25 +04:00
|
|
|
ret = dump_sched_info(pid, core->thread_core);
|
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
|
|
|
|
2013-01-09 18:48:00 +04:00
|
|
|
core_put_tls(core, misc->tls);
|
|
|
|
|
2012-08-07 02:26:50 +04:00
|
|
|
ret = pb_write_one(fd_core, core, PB_CORE);
|
2012-12-20 16:08:12 +04:00
|
|
|
if (ret < 0)
|
2012-04-12 15:22:06 +04:00
|
|
|
goto err_free;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
err_free:
|
2012-07-19 13:23:01 +04:00
|
|
|
core_entry_free(core);
|
2011-09-23 12:00:45 +04:00
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-06-19 15:53:00 +04:00
|
|
|
static int parse_threads(const struct pstree_item *item, struct pid **_t, int *_n)
|
2011-10-20 11:03:19 +04:00
|
|
|
{
|
|
|
|
struct dirent *de;
|
|
|
|
DIR *dir;
|
2012-06-19 15:53:00 +04:00
|
|
|
struct pid *t = NULL;
|
2011-12-02 18:24:50 +04:00
|
|
|
int nr = 1;
|
2011-10-20 11:03:19 +04:00
|
|
|
|
2012-06-22 00:38:00 +04:00
|
|
|
dir = opendir_proc(item->pid.real, "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))) {
|
2012-06-19 15:53:00 +04:00
|
|
|
struct pid *tmp;
|
2011-12-04 11:48:10 +04:00
|
|
|
|
2011-10-20 11:03:19 +04:00
|
|
|
/* We expect numbers only here */
|
|
|
|
if (de->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
|
2012-06-19 15:53:00 +04:00
|
|
|
tmp = xrealloc(t, nr * sizeof(struct pid));
|
2011-12-04 11:48:10 +04:00
|
|
|
if (!tmp) {
|
|
|
|
xfree(t);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
t = tmp;
|
2012-06-22 00:38:00 +04:00
|
|
|
t[nr - 1].real = atoi(de->d_name);
|
|
|
|
t[nr - 1].virt = -1;
|
2011-12-02 18:24:50 +04:00
|
|
|
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
|
|
|
{
|
2012-06-19 15:53:00 +04:00
|
|
|
struct pid *t;
|
2012-03-01 19:07:15 +04:00
|
|
|
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-09-07 19:16:35 +04:00
|
|
|
static int parse_children(pid_t pid, pid_t **_c, int *_n)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
FILE *file;
|
|
|
|
char *tok;
|
2012-09-07 19:16:35 +04:00
|
|
|
pid_t *ch = NULL;
|
2012-09-07 19:16:31 +04:00
|
|
|
int nr = 1;
|
|
|
|
DIR *dir;
|
|
|
|
struct dirent *de;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-09-07 19:16:31 +04:00
|
|
|
dir = opendir_proc(pid, "task");
|
|
|
|
if (dir == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while ((de = readdir(dir))) {
|
2012-11-29 21:12:51 +03:00
|
|
|
if (dir_dots(de))
|
2012-09-07 19:16:31 +04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
file = fopen_proc(pid, "task/%s/children", de->d_name);
|
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) {
|
2012-09-07 19:16:35 +04:00
|
|
|
pid_t *tmp = xrealloc(ch, nr * sizeof(pid_t));
|
2011-12-25 18:19:16 +04:00
|
|
|
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
|
|
|
|
2012-09-07 19:16:31 +04:00
|
|
|
closedir(dir);
|
2011-12-02 18:26:15 +04:00
|
|
|
return 0;
|
|
|
|
err:
|
2012-09-07 19:16:31 +04:00
|
|
|
closedir(dir);
|
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)
|
|
|
|
{
|
2012-09-07 19:16:35 +04:00
|
|
|
pid_t *ch;
|
2012-05-31 14:50:00 +04:00
|
|
|
int ret, i, nr_children;
|
|
|
|
struct pstree_item *c;
|
|
|
|
|
2012-09-07 19:16:31 +04:00
|
|
|
ret = parse_children(item->pid.real, &ch, &nr_children);
|
2012-05-31 14:50:00 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
for (i = 0; i < nr_children; i++) {
|
|
|
|
c = alloc_pstree_item();
|
|
|
|
if (c == NULL) {
|
|
|
|
ret = -1;
|
|
|
|
goto free;
|
|
|
|
}
|
2012-06-22 00:38:00 +04:00
|
|
|
c->pid.real = ch[i];
|
2012-05-31 14:50:00 +04:00
|
|
|
c->parent = item;
|
2012-10-08 18:59:26 +04:00
|
|
|
list_add_tail(&c->sibling, &item->children);
|
2012-05-31 14:50:00 +04:00
|
|
|
}
|
|
|
|
free:
|
|
|
|
xfree(ch);
|
|
|
|
return ret;
|
2012-03-01 19:07:15 +04:00
|
|
|
}
|
|
|
|
|
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++)
|
2012-06-22 00:38:00 +04:00
|
|
|
unseize_task(item->threads[i].real, st); /* item->pid will be here */
|
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-05-31 14:50:00 +04:00
|
|
|
static void pstree_switch_state(struct pstree_item *root_item, int st)
|
|
|
|
{
|
|
|
|
struct pstree_item *item = root_item;
|
2011-12-02 18:26:15 +04:00
|
|
|
|
2012-04-11 15:17:26 +04:00
|
|
|
pr_info("Unfreezing tasks into %d\n", st);
|
2012-05-31 14:50:00 +04:00
|
|
|
for_each_pstree_item(item)
|
2012-04-11 15:17:26 +04:00
|
|
|
unseize_task_and_threads(item, 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
|
|
|
}
|
|
|
|
|
2012-04-11 22:07:47 +04:00
|
|
|
static pid_t item_ppid(const struct pstree_item *item)
|
|
|
|
{
|
|
|
|
item = item->parent;
|
2012-06-22 00:38:00 +04:00
|
|
|
return item ? item->pid.real : -1;
|
2012-04-11 22:07:47 +04:00
|
|
|
}
|
|
|
|
|
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++) {
|
2012-06-22 00:38:00 +04:00
|
|
|
pid_t pid = item->threads[i].real;
|
|
|
|
if (item->pid.real == pid)
|
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
|
|
|
continue;
|
2012-02-01 17:03:51 +04:00
|
|
|
|
2012-06-19 15:53:00 +04:00
|
|
|
pr_info("\tSeizing %d's %d thread\n",
|
2012-06-22 00:38:00 +04:00
|
|
|
item->pid.real, pid);
|
2012-06-19 15:53:00 +04:00
|
|
|
ret = seize_task(pid, item_ppid(item), NULL, NULL);
|
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--) {
|
2012-06-22 00:38:00 +04:00
|
|
|
if (item->pid.real == item->threads[i].real)
|
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
|
|
|
continue;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-06-22 00:38:00 +04:00
|
|
|
unseize_task(item->threads[i].real, 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-05-31 14:50:00 +04:00
|
|
|
static int collect_task(struct pstree_item *item)
|
2012-01-19 19:22:59 +04:00
|
|
|
{
|
2012-02-17 01:39:36 +04:00
|
|
|
int ret;
|
2012-06-22 00:38:00 +04:00
|
|
|
pid_t pid = item->pid.real;
|
2012-04-11 22:07:47 +04:00
|
|
|
|
2012-04-11 22:10:09 +04:00
|
|
|
ret = seize_task(pid, item_ppid(item), &item->pgid, &item->sid);
|
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)
|
2012-05-31 14:50:00 +04:00
|
|
|
goto err;
|
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->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;
|
|
|
|
|
2012-05-31 14:50:00 +04:00
|
|
|
if ((item->state == TASK_DEAD) && !list_empty(&item->children)) {
|
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_err("Zombie with children?! O_o Run, run, run!\n");
|
|
|
|
goto err_close;
|
|
|
|
}
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
close_pid_proc();
|
2012-06-19 15:53:00 +04:00
|
|
|
|
2012-06-22 00:38:00 +04:00
|
|
|
pr_info("Collected %d in %d state\n", item->pid.real, item->state);
|
2012-05-31 14:50:00 +04:00
|
|
|
return 0;
|
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);
|
2011-09-23 12:00:45 +04:00
|
|
|
err:
|
2012-05-31 14:50:00 +04:00
|
|
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2012-09-07 19:16:35 +04:00
|
|
|
pid_t *ch;
|
2012-05-31 14:50:00 +04:00
|
|
|
int nr, ret, i;
|
|
|
|
struct pstree_item *child;
|
2012-03-01 19:07:15 +04:00
|
|
|
|
2012-09-07 19:16:31 +04:00
|
|
|
ret = parse_children(item->pid.real, &ch, &nr);
|
2012-03-01 19:07:15 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2012-05-31 14:50:00 +04:00
|
|
|
i = 0;
|
2012-10-08 18:59:26 +04:00
|
|
|
list_for_each_entry(child, &item->children, sibling) {
|
2012-06-22 00:38:00 +04:00
|
|
|
if (child->pid.real != ch[i])
|
2012-05-31 14:50:00 +04:00
|
|
|
break;
|
|
|
|
i++;
|
|
|
|
if (i > nr)
|
|
|
|
break;
|
|
|
|
}
|
2012-03-01 19:07:15 +04:00
|
|
|
xfree(ch);
|
|
|
|
|
2012-05-31 14:50:00 +04:00
|
|
|
if (i != nr) {
|
2012-03-01 19:07:15 +04:00
|
|
|
pr_info("Children set has changed while suspending\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-19 17:55:34 +04:00
|
|
|
static int collect_subtree(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
|
|
|
{
|
2012-05-31 14:50:00 +04:00
|
|
|
struct pstree_item *child;
|
2012-06-22 00:38:00 +04:00
|
|
|
pid_t pid = item->pid.real;
|
2012-05-31 14:50:00 +04:00
|
|
|
int ret;
|
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("Collecting tasks starting from %d\n", pid);
|
2012-05-31 14:50:00 +04:00
|
|
|
ret = collect_task(item);
|
|
|
|
if (ret)
|
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-10-08 18:59:26 +04:00
|
|
|
list_for_each_entry(child, &item->children, sibling) {
|
2012-07-19 17:55:34 +04:00
|
|
|
ret = collect_subtree(child);
|
2012-05-31 14:50:00 +04:00
|
|
|
if (ret < 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-05-31 14:50:00 +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
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2013-01-17 17:48:19 +04:00
|
|
|
static int collect_pstree_ids(void)
|
|
|
|
{
|
|
|
|
struct pstree_item *item;
|
|
|
|
|
|
|
|
for_each_pstree_item(item)
|
|
|
|
if (get_task_ids(item))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-31 14:50:00 +04:00
|
|
|
static int collect_pstree(pid_t pid, 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-05-31 14:50:00 +04:00
|
|
|
root_item = alloc_pstree_item();
|
|
|
|
if (root_item == NULL)
|
|
|
|
return -1;
|
2012-03-01 19:12:35 +04:00
|
|
|
|
2012-06-22 00:38:00 +04:00
|
|
|
root_item->pid.real = pid;
|
2012-05-31 14:50:00 +04:00
|
|
|
|
2012-07-19 17:55:34 +04:00
|
|
|
ret = collect_subtree(root_item);
|
2012-03-01 19:12:35 +04:00
|
|
|
if (ret == 0) {
|
|
|
|
/*
|
|
|
|
* Some tasks could have been reparented to
|
|
|
|
* namespaces' reaper. Check this.
|
|
|
|
*/
|
2013-01-17 18:14:55 +04:00
|
|
|
if (check_subtree(root_item))
|
|
|
|
goto try_again;
|
2012-03-01 19:12:35 +04:00
|
|
|
|
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
|
|
|
|
|
|
|
/*
|
|
|
|
* 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");
|
|
|
|
|
2012-05-31 14:50:00 +04:00
|
|
|
pstree_switch_state(root_item, TASK_ALIVE);
|
|
|
|
free_pstree(root_item);
|
2012-03-01 19:11:29 +04:00
|
|
|
}
|
|
|
|
|
2013-01-17 17:48:19 +04:00
|
|
|
return collect_pstree_ids();
|
2012-03-01 19:04:31 +04:00
|
|
|
}
|
|
|
|
|
2013-01-17 16:09:32 +08:00
|
|
|
static int collect_file_locks(const struct cr_options *opts)
|
|
|
|
{
|
|
|
|
if (parse_file_locks())
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (opts->handle_file_locks)
|
|
|
|
/*
|
2013-01-17 16:09:33 +08:00
|
|
|
* If the handle file locks option(-l) is set,
|
2013-01-17 16:09:32 +08:00
|
|
|
* collect work is over.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the handle file locks option is not set, we need to do
|
|
|
|
* the check, any file locks hold by tasks in our pstree is
|
|
|
|
* not allowed.
|
|
|
|
*
|
|
|
|
* It's hard to do it carefully, there might be some other
|
|
|
|
* issues like tasks beyond pstree would use flocks hold by
|
|
|
|
* dumping tasks, but we can't know it in dumping time.
|
|
|
|
* We need to make sure these flocks only used by dumping tasks.
|
|
|
|
* We might have to do the check that this option would only
|
|
|
|
* be used by container dumping.
|
|
|
|
*/
|
|
|
|
if (!list_empty(&file_lock_list)) {
|
|
|
|
pr_perror("Some file locks are hold by dumping tasks!"
|
|
|
|
"You can try -l to dump them.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-06-19 15:53:00 +04:00
|
|
|
static int dump_task_thread(struct parasite_ctl *parasite_ctl, struct pid *tid)
|
2011-10-20 17:19:26 +04:00
|
|
|
{
|
2012-07-19 13:23:01 +04:00
|
|
|
CoreEntry *core;
|
2012-03-26 17:36:44 +04:00
|
|
|
int ret = -1, fd_core;
|
2012-06-22 00:38:00 +04:00
|
|
|
pid_t pid = tid->real;
|
2011-10-20 17:19:26 +04:00
|
|
|
|
|
|
|
pr_info("\n");
|
|
|
|
pr_info("Dumping core for thread (pid: %d)\n", pid);
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
2013-01-11 18:16:21 +04:00
|
|
|
core = core_entry_alloc(1, 0);
|
2011-10-20 17:19:26 +04:00
|
|
|
if (!core)
|
|
|
|
goto err;
|
|
|
|
|
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
|
|
|
|
2012-08-10 20:28:59 +04:00
|
|
|
ret = get_task_futex_robust_list(pid, core->thread_core);
|
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
|
|
|
|
2013-01-09 18:32:56 +03:00
|
|
|
ret = parasite_dump_thread_seized(parasite_ctl, tid, core);
|
2012-02-21 09:25:17 +03:00
|
|
|
if (ret) {
|
2012-11-12 17:42:59 +04:00
|
|
|
pr_err("Can't dump thread for pid %d\n", pid);
|
2012-03-26 17:36:44 +04:00
|
|
|
goto err_free;
|
2012-02-15 18:36:32 +04:00
|
|
|
}
|
2012-02-21 09:25:17 +03:00
|
|
|
|
2013-01-09 18:32:56 +03:00
|
|
|
core->thread_core->has_blk_sigset = true;
|
2012-02-21 09:25:17 +03:00
|
|
|
|
2012-10-17 00:23:25 +04:00
|
|
|
ret = dump_sched_info(pid, core->thread_core);
|
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
|
|
|
|
2012-06-22 00:38:00 +04:00
|
|
|
fd_core = open_image(CR_FD_CORE, O_DUMP, tid->virt);
|
2012-03-26 17:36:44 +04:00
|
|
|
if (fd_core < 0)
|
|
|
|
goto err_free;
|
|
|
|
|
2012-08-07 02:26:50 +04:00
|
|
|
ret = pb_write_one(fd_core, core, PB_CORE);
|
2011-10-20 17:19:26 +04:00
|
|
|
|
2012-03-26 17:36:44 +04:00
|
|
|
close(fd_core);
|
2011-10-20 17:19:26 +04:00
|
|
|
err_free:
|
2012-07-19 13:23:01 +04:00
|
|
|
core_entry_free(core);
|
2011-10-20 17:19:26 +04:00
|
|
|
err:
|
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-06 14:20:00 +04:00
|
|
|
static int dump_one_zombie(const struct pstree_item *item,
|
2012-03-26 17:36:44 +04:00
|
|
|
const struct proc_pid_stat *pps)
|
2012-01-22 20:28:30 +04:00
|
|
|
{
|
2012-07-19 13:23:01 +04:00
|
|
|
CoreEntry *core;
|
2012-03-26 17:36:44 +04:00
|
|
|
int ret = -1, fd_core;
|
2012-01-22 20:28:30 +04:00
|
|
|
|
2013-01-11 18:16:21 +04:00
|
|
|
core = core_entry_alloc(0, 1);
|
2012-01-22 20:28:30 +04:00
|
|
|
if (core == NULL)
|
2012-03-26 17:36:44 +04:00
|
|
|
goto err;
|
2012-01-22 20:28:30 +04:00
|
|
|
|
2012-07-19 13:23:01 +04:00
|
|
|
core->tc->task_state = TASK_DEAD;
|
|
|
|
core->tc->exit_code = pps->exit_code;
|
2012-01-22 20:28:30 +04:00
|
|
|
|
2012-09-07 18:19:17 +04:00
|
|
|
fd_core = open_image(CR_FD_CORE, O_DUMP, item->pid.virt);
|
2012-03-26 17:36:44 +04:00
|
|
|
if (fd_core < 0)
|
|
|
|
goto err_free;
|
|
|
|
|
2012-08-07 02:26:50 +04:00
|
|
|
ret = pb_write_one(fd_core, core, PB_CORE);
|
2012-03-26 17:36:44 +04:00
|
|
|
close(fd_core);
|
|
|
|
err_free:
|
2012-07-19 13:23:01 +04:00
|
|
|
core_entry_free(core);
|
2012-03-26 17:36:44 +04:00
|
|
|
err:
|
|
|
|
return ret;
|
2012-01-22 20:28:30 +04:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
for (i = 0; i < item->nr_threads; i++) {
|
|
|
|
/* Leader is already dumped */
|
2012-06-22 00:38:00 +04:00
|
|
|
if (item->pid.real == item->threads[i].real) {
|
|
|
|
item->threads[i].virt = item->pid.virt;
|
2012-01-22 20:13:59 +04:00
|
|
|
continue;
|
2012-06-19 15:53:00 +04:00
|
|
|
}
|
2012-01-22 20:13:59 +04:00
|
|
|
|
2012-06-19 15:53:00 +04:00
|
|
|
if (dump_task_thread(parasite_ctl, &item->threads[i]))
|
2012-03-26 17:36:44 +04:00
|
|
|
return -1;
|
2012-01-22 20:13:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-07 19:17:18 +04:00
|
|
|
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;
|
|
|
|
|
2012-10-08 18:59:26 +04:00
|
|
|
list_for_each_entry(child, &item->children, sibling) {
|
2012-09-07 19:17:18 +04:00
|
|
|
if (child->pid.virt < 0)
|
|
|
|
continue;
|
|
|
|
for (i = 0; i < nr; i++) {
|
|
|
|
if (ch[i] == child->pid.virt) {
|
|
|
|
ch[i] = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
2012-10-08 18:59:26 +04:00
|
|
|
list_for_each_entry(child, &item->children, sibling) {
|
2012-09-07 19:17:18 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-01-18 23:34:30 +04:00
|
|
|
static int dump_zombies(void)
|
2012-09-07 19:17:18 +04:00
|
|
|
{
|
|
|
|
struct pstree_item *item;
|
|
|
|
int oldfd, ret = -1;
|
2013-01-17 18:14:55 +04:00
|
|
|
int pidns = current_ns_mask & CLONE_NEWPID;
|
2012-09-07 19:17:18 +04:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-08-02 16:25:52 +04:00
|
|
|
static int dump_one_task(struct pstree_item *item)
|
2012-01-22 20:13:59 +04:00
|
|
|
{
|
2012-06-22 00:38:00 +04:00
|
|
|
pid_t pid = item->pid.real;
|
2013-03-01 20:11:51 +04:00
|
|
|
struct vm_area_list vmas;
|
2011-10-21 12:14:45 +04:00
|
|
|
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-03-26 22:58:22 +04:00
|
|
|
struct cr_fdset *cr_fdset = NULL;
|
2012-08-21 19:59:07 +04:00
|
|
|
struct parasite_drain_fd *dfds;
|
2012-03-28 17:36:00 +04:00
|
|
|
|
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-09-07 17:48:55 +04:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2012-09-07 19:17:18 +04:00
|
|
|
if (item->state == TASK_DEAD)
|
|
|
|
return 0;
|
|
|
|
|
2012-09-07 17:48:55 +04:00
|
|
|
dfds = xmalloc(sizeof(*dfds));
|
|
|
|
if (!dfds)
|
|
|
|
goto err_free;
|
|
|
|
|
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;
|
|
|
|
|
2013-03-01 20:11:51 +04:00
|
|
|
ret = collect_mappings(pid, &vmas);
|
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-08-21 19:59:07 +04:00
|
|
|
ret = collect_fds(pid, dfds);
|
2012-02-29 16:06:48 +03:00
|
|
|
if (ret) {
|
2012-03-28 17:36:00 +04:00
|
|
|
pr_err("Collect fds (pid: %d) failed with %d\n", pid, ret);
|
2012-02-29 16:06:48 +03:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-09-07 19:16:36 +04:00
|
|
|
ret = -1;
|
2013-03-01 20:11:51 +04:00
|
|
|
parasite_ctl = parasite_infect_seized(pid, item, &vmas, dfds);
|
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;
|
|
|
|
}
|
|
|
|
|
2013-01-17 18:14:55 +04:00
|
|
|
if (current_ns_mask & CLONE_NEWPID && root_item == item) {
|
2012-09-07 19:16:36 +04:00
|
|
|
pidns_proc = parasite_get_proc_fd_seized(parasite_ctl);
|
|
|
|
if (pidns_proc < 0) {
|
|
|
|
pr_err("Can't get proc fd (pid: %d)\n", pid);
|
|
|
|
goto err_cure_fdset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-19 15:53:00 +04:00
|
|
|
ret = parasite_dump_misc_seized(parasite_ctl, &misc);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Can't dump misc (pid: %d)\n", pid);
|
|
|
|
goto err_cure_fdset;
|
|
|
|
}
|
|
|
|
|
2012-06-22 00:38:00 +04:00
|
|
|
item->pid.virt = misc.pid;
|
2012-06-19 15:53:00 +04:00
|
|
|
item->sid = misc.sid;
|
|
|
|
item->pgid = misc.pgid;
|
|
|
|
|
2012-11-27 19:20:20 +04:00
|
|
|
pr_info("sid=%d pgid=%d pid=%d\n",
|
|
|
|
item->sid, item->pgid, item->pid.virt);
|
|
|
|
|
2012-06-19 15:53:00 +04:00
|
|
|
ret = -1;
|
2012-06-22 00:38:00 +04:00
|
|
|
cr_fdset = cr_task_fdset_open(item->pid.virt, O_DUMP);
|
2012-06-19 15:53:00 +04:00
|
|
|
if (!cr_fdset)
|
|
|
|
goto err_cure;
|
|
|
|
|
2013-01-11 18:16:25 +04:00
|
|
|
ret = dump_task_ids(item, cr_fdset);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Dump ids (pid: %d) failed with %d\n", pid, ret);
|
|
|
|
goto err_cure;
|
|
|
|
}
|
|
|
|
|
2013-01-12 00:44:26 +04:00
|
|
|
if (!shared_fdtable(item)) {
|
|
|
|
ret = dump_task_files_seized(parasite_ctl, item, dfds);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Dump files (pid: %d) failed with %d\n", pid, ret);
|
|
|
|
goto err_cure;
|
|
|
|
}
|
2012-03-28 17:36:00 +04:00
|
|
|
}
|
|
|
|
|
2013-01-17 16:09:33 +08:00
|
|
|
if (opts.handle_file_locks) {
|
|
|
|
ret = dump_task_file_locks(parasite_ctl, cr_fdset, dfds);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Dump file locks (pid: %d) failed with %d\n",
|
|
|
|
pid, ret);
|
|
|
|
goto err_cure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-12 21:00:05 +04:00
|
|
|
ret = parasite_dump_pages_seized(parasite_ctl, item->pid.virt, &vmas, 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);
|
2012-04-11 15:25:03 +04:00
|
|
|
goto err_cure;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
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);
|
2012-04-11 15:25:03 +04:00
|
|
|
goto err_cure;
|
2011-11-29 15:12:25 +03:00
|
|
|
}
|
|
|
|
|
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);
|
2012-04-11 15:25:03 +04:00
|
|
|
goto err_cure;
|
2012-01-24 16:45:19 +04:00
|
|
|
}
|
|
|
|
|
2012-09-07 18:21:04 +04:00
|
|
|
ret = dump_task_core_all(pid, &pps_buf, &misc,
|
2013-03-01 20:11:51 +04:00
|
|
|
parasite_ctl, cr_fdset, &vmas);
|
2012-02-17 22:56:36 +04:00
|
|
|
if (ret) {
|
|
|
|
pr_err("Dump core (pid: %d) failed with %d\n", pid, ret);
|
2012-04-11 15:25:03 +04:00
|
|
|
goto err_cure;
|
2012-02-17 22:56:36 +04:00
|
|
|
}
|
|
|
|
|
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");
|
2012-04-11 15:25:03 +04:00
|
|
|
goto err_cure;
|
2012-02-17 22:56:36 +04:00
|
|
|
}
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
ret = dump_task_creds(parasite_ctl, cr_fdset);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret) {
|
2012-10-11 15:59:43 +04:00
|
|
|
pr_err("Dump creds (pid: %d) failed with %d\n", pid, ret);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-11-12 17:42:55 +04:00
|
|
|
ret = parasite_cure_seized(parasite_ctl, item);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret) {
|
2012-10-11 15:59:43 +04:00
|
|
|
pr_err("Can't cure (pid: %d) from parasite\n", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2013-03-01 20:11:51 +04:00
|
|
|
ret = dump_task_mappings(pid, &vmas, cr_fdset);
|
2012-01-27 21:43:32 +04:00
|
|
|
if (ret) {
|
2012-10-11 15:59:43 +04:00
|
|
|
pr_err("Dump mappings (pid: %d) failed with %d\n", pid, ret);
|
2012-01-27 21:43:32 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2012-04-09 13:41:05 +04:00
|
|
|
|
2013-01-10 12:48:31 +03:00
|
|
|
ret = dump_task_fs(pid, &misc, cr_fdset);
|
2012-04-09 13:41:05 +04:00
|
|
|
if (ret) {
|
|
|
|
pr_err("Dump fs (pid: %d) failed with %d\n", pid, ret);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2013-01-10 20:08:38 +04:00
|
|
|
ret = dump_task_rlims(pid, cr_fdset);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Dump %d rlimits failed %d\n", pid, ret);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-03-26 22:58:22 +04:00
|
|
|
close_cr_fdset(&cr_fdset);
|
2012-06-19 15:53:00 +04:00
|
|
|
err:
|
2012-02-17 01:39:36 +04:00
|
|
|
close_pid_proc();
|
2012-02-17 01:39:32 +04:00
|
|
|
err_free:
|
2013-03-01 20:11:51 +04:00
|
|
|
free_mappings(&vmas);
|
2012-08-21 19:59:07 +04:00
|
|
|
xfree(dfds);
|
2011-09-23 12:00:45 +04:00
|
|
|
return ret;
|
2012-04-11 15:25:03 +04:00
|
|
|
|
|
|
|
err_cure:
|
2012-06-19 15:53:00 +04:00
|
|
|
close_cr_fdset(&cr_fdset);
|
|
|
|
err_cure_fdset:
|
2012-11-12 17:42:55 +04:00
|
|
|
parasite_cure_seized(parasite_ctl, item);
|
2012-04-11 15:25:03 +04:00
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
struct pstree_item *item;
|
2012-05-18 15:39:00 +04:00
|
|
|
int ret = -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-10-06 14:07:48 +04:00
|
|
|
pr_info("========================================\n");
|
2012-07-19 17:55:34 +04:00
|
|
|
pr_info("Dumping processes (pid: %d)\n", pid);
|
2011-10-06 14:07:48 +04:00
|
|
|
pr_info("========================================\n");
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-12-21 17:35:36 +04:00
|
|
|
if (cpu_init())
|
|
|
|
goto err;
|
|
|
|
|
2012-07-19 17:37:25 +04:00
|
|
|
if (write_img_inventory())
|
|
|
|
goto err;
|
|
|
|
|
2012-05-31 14:50:00 +04:00
|
|
|
if (collect_pstree(pid, opts))
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
|
2013-01-17 18:14:55 +04:00
|
|
|
if (network_lock())
|
|
|
|
goto err;
|
|
|
|
|
2013-01-17 16:09:32 +08:00
|
|
|
if (collect_file_locks(opts))
|
|
|
|
goto err;
|
|
|
|
|
2013-01-14 20:48:09 +04:00
|
|
|
if (collect_mount_info())
|
|
|
|
goto err;
|
|
|
|
|
2012-08-14 12:49:21 +04:00
|
|
|
if (mntns_collect_root(root_item->pid.real))
|
|
|
|
goto err;
|
|
|
|
|
2013-01-25 15:20:38 +04:00
|
|
|
if (collect_sockets(pid))
|
2012-08-01 07:00:48 +04:00
|
|
|
goto err;
|
|
|
|
|
2012-03-26 17:47:38 +04:00
|
|
|
glob_fdset = cr_glob_fdset_open(O_DUMP);
|
|
|
|
if (!glob_fdset)
|
2012-03-26 17:38:59 +04:00
|
|
|
goto err;
|
|
|
|
|
2012-05-31 14:50:00 +04:00
|
|
|
for_each_pstree_item(item) {
|
2012-08-02 16:25:52 +04:00
|
|
|
if (dump_one_task(item))
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-10-29 13:37:34 +04:00
|
|
|
if (dump_verify_tty_sids())
|
|
|
|
goto err;
|
|
|
|
|
2012-09-07 19:17:18 +04:00
|
|
|
if (dump_zombies())
|
|
|
|
goto err;
|
|
|
|
|
2012-06-19 15:53:00 +04:00
|
|
|
if (dump_pstree(root_item))
|
|
|
|
goto err;
|
|
|
|
|
2013-01-17 18:14:55 +04:00
|
|
|
if (current_ns_mask)
|
|
|
|
if (dump_namespaces(&root_item->pid, current_ns_mask) < 0)
|
2012-06-19 15:53:00 +04:00
|
|
|
goto err;
|
|
|
|
|
2012-03-21 10:12:00 +04:00
|
|
|
ret = cr_dump_shmem();
|
2012-04-19 11:48:00 +04:00
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
|
2012-04-26 14:20:22 +04:00
|
|
|
ret = fix_external_unix_sockets();
|
2012-04-19 11:48:00 +04:00
|
|
|
if (ret)
|
|
|
|
goto err;
|
2012-03-24 16:52:09 +04:00
|
|
|
|
2012-09-20 13:35:39 +04:00
|
|
|
ret = tty_verify_active_pairs();
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
|
2012-03-24 16:52:09 +04:00
|
|
|
fd_id_show_tree();
|
2011-09-23 12:00:45 +04:00
|
|
|
err:
|
2012-03-26 17:47:38 +04:00
|
|
|
close_cr_fdset(&glob_fdset);
|
2012-04-28 17:38:46 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we've failed to do anything -- unlock all TCP sockets
|
|
|
|
* so that the connections can go on. But if we succeeded --
|
|
|
|
* don't, just close them silently.
|
|
|
|
*/
|
|
|
|
if (ret)
|
2012-09-17 20:05:55 +04:00
|
|
|
network_unlock();
|
2012-05-31 14:50:00 +04:00
|
|
|
pstree_switch_state(root_item,
|
2012-04-11 15:17:26 +04:00
|
|
|
ret ? TASK_ALIVE : opts->final_state);
|
2012-05-31 14:50:00 +04:00
|
|
|
free_pstree(root_item);
|
2013-01-17 16:09:32 +08:00
|
|
|
free_file_locks();
|
2011-10-24 23:01:42 +04:00
|
|
|
|
2012-09-07 19:16:36 +04:00
|
|
|
close_safe(&pidns_proc);
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
return ret;
|
|
|
|
}
|