mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-22 09:58:09 +00:00
pipe: all pipes are saved in one file (v2)
Information about pipe's file structs saved in one global file and fdinfo_entry is saved for each descriptor Signed-off-by: Andrey Vagin <avagin@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
382ebc3063
commit
bdb3932be5
205
cr-dump.c
205
cr-dump.c
@ -158,6 +158,89 @@ static int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PIPES_SIZE 1024
|
||||
static u32 *pipes; /* pipes for which data already dumped */
|
||||
static int nr_pipes = 0;
|
||||
|
||||
static int dump_one_pipe(int lfd, u32 id, const struct fd_parms *p)
|
||||
{
|
||||
struct pipe_entry pe;
|
||||
int fd_pipes;
|
||||
int steal_pipe[2];
|
||||
int pipe_size;
|
||||
int has_bytes = 0;
|
||||
int ret = -1;
|
||||
int i = 0;
|
||||
|
||||
pr_info("Dumping pipe %d with id %x pipe_id %x\n", lfd, id, p->id);
|
||||
|
||||
fd_pipes = fdset_fd(glob_fdset, CR_FD_PIPES);
|
||||
|
||||
if (p->flags & O_WRONLY)
|
||||
goto dump;
|
||||
|
||||
pr_info("Dumping data from pipe %x fd %d\n", id, lfd);
|
||||
|
||||
for (i = 0; i < nr_pipes; i++)
|
||||
if (pipes[i] == p->id)
|
||||
goto dump; /* data was dumped already */
|
||||
|
||||
nr_pipes++;
|
||||
if (nr_pipes > PIPES_SIZE) {
|
||||
pr_err("OOM storing pipe\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pipes[nr_pipes - 1] = p->id;
|
||||
|
||||
pipe_size = fcntl(lfd, F_GETPIPE_SZ);
|
||||
if (pipe_size < 0) {
|
||||
pr_err("Can't obtain piped data size\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pipe(steal_pipe) < 0) {
|
||||
pr_perror("Can't create pipe for stealing data");
|
||||
goto err;
|
||||
}
|
||||
|
||||
has_bytes = tee(lfd, steal_pipe[1], pipe_size, SPLICE_F_NONBLOCK);
|
||||
if (has_bytes < 0) {
|
||||
if (errno != EAGAIN) {
|
||||
pr_perror("Can't pick pipe data");
|
||||
goto err_close;
|
||||
} else
|
||||
has_bytes = 0;
|
||||
}
|
||||
dump:
|
||||
pe.id = id;
|
||||
pe.pipe_id = p->id;
|
||||
pe.bytes = has_bytes;
|
||||
pe.flags = p->flags;
|
||||
|
||||
if (write_img(fd_pipes, &pe))
|
||||
goto err_close;
|
||||
|
||||
if (has_bytes) {
|
||||
ret = splice(steal_pipe[0], NULL, fd_pipes,
|
||||
NULL, has_bytes, 0);
|
||||
if (ret < 0) {
|
||||
pr_perror("Can't push pipe data");
|
||||
goto err_close;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
err_close:
|
||||
if (has_bytes) {
|
||||
close(steal_pipe[0]);
|
||||
close(steal_pipe[1]);
|
||||
}
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_dump_one_fdinfo(const struct fd_parms *p, int lfd,
|
||||
const struct cr_fdset *cr_fdset)
|
||||
{
|
||||
@ -170,7 +253,14 @@ static int do_dump_one_fdinfo(const struct fd_parms *p, int lfd,
|
||||
|
||||
ret = fd_id_generate(p->pid, &e);
|
||||
if (ret == 1) /* new ID generated */
|
||||
ret = dump_one_reg_file(lfd, e.id, p);
|
||||
switch (p->type) {
|
||||
case FDINFO_PIPE:
|
||||
ret = dump_one_pipe(lfd, e.id, p);
|
||||
break;
|
||||
default:
|
||||
ret = dump_one_reg_file(lfd, e.id, p);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
@ -190,7 +280,10 @@ static int dump_one_fdinfo(struct fd_parms *p, int lfd,
|
||||
const struct cr_fdset *cr_fdset)
|
||||
{
|
||||
p->id = MAKE_FD_GENID(p->stat.st_dev, p->stat.st_ino, p->pos);
|
||||
p->type = FDINFO_REG;
|
||||
if (S_ISFIFO(p->stat.st_mode))
|
||||
p->type = FDINFO_PIPE;
|
||||
else
|
||||
p->type = FDINFO_REG;
|
||||
|
||||
return do_dump_one_fdinfo(p, lfd, cr_fdset);
|
||||
}
|
||||
@ -231,101 +324,6 @@ static int dump_task_special_files(pid_t pid, const struct cr_fdset *cr_fdset)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dump_pipe_and_data(int lfd, struct pipe_entry *e,
|
||||
const struct cr_fdset *cr_fdset)
|
||||
{
|
||||
int fd_pipes;
|
||||
int steal_pipe[2];
|
||||
int pipe_size;
|
||||
int has_bytes;
|
||||
int ret = -1;
|
||||
|
||||
fd_pipes = fdset_fd(cr_fdset, CR_FD_PIPES);
|
||||
|
||||
pr_info("Dumping data from pipe %x\n", e->pipeid);
|
||||
if (pipe(steal_pipe) < 0) {
|
||||
pr_perror("Can't create pipe for stealing data");
|
||||
goto err;
|
||||
}
|
||||
|
||||
pipe_size = fcntl(lfd, F_GETPIPE_SZ);
|
||||
if (pipe_size < 0) {
|
||||
pr_err("Can't obtain piped data size\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
has_bytes = tee(lfd, steal_pipe[1], pipe_size, SPLICE_F_NONBLOCK);
|
||||
if (has_bytes < 0) {
|
||||
if (errno != EAGAIN) {
|
||||
pr_perror("Can't pick pipe data");
|
||||
goto err_close;
|
||||
} else
|
||||
has_bytes = 0;
|
||||
}
|
||||
|
||||
e->bytes = has_bytes;
|
||||
if (write_img(fd_pipes, e))
|
||||
goto err_close;
|
||||
|
||||
if (has_bytes) {
|
||||
ret = splice(steal_pipe[0], NULL, fd_pipes,
|
||||
NULL, has_bytes, 0);
|
||||
if (ret < 0) {
|
||||
pr_perror("Can't push pipe data");
|
||||
goto err_close;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
err_close:
|
||||
close(steal_pipe[0]);
|
||||
close(steal_pipe[1]);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dump_one_pipe(const struct fd_parms *p, int lfd,
|
||||
const struct cr_fdset *cr_fdset)
|
||||
{
|
||||
struct pipe_entry e;
|
||||
int ret = -1;
|
||||
struct statfs stfs_buf;
|
||||
int id = p->stat.st_ino;
|
||||
|
||||
if (fstatfs(lfd, &stfs_buf) < 0) {
|
||||
pr_perror("Can't fstatfs on %ld", p->fd_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stfs_buf.f_type != PIPEFS_MAGIC) {
|
||||
pr_err("Dumping of FIFO's is not supported: %ld\n", p->fd_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pr_info("Dumping pipe %ld/%x flags %x\n", p->fd_name, id, p->flags);
|
||||
|
||||
e.fd = p->fd_name;
|
||||
e.pipeid = id;
|
||||
e.flags = p->flags;
|
||||
|
||||
if (p->flags & O_WRONLY) {
|
||||
e.bytes = 0;
|
||||
ret = write_img(fdset_fd(cr_fdset, CR_FD_PIPES), &e);
|
||||
} else
|
||||
ret = dump_pipe_and_data(lfd, &e, cr_fdset);
|
||||
|
||||
err:
|
||||
if (!ret)
|
||||
pr_info("Dumped pipe: fd: %8x pipeid: %8x flags: %8x bytes: %8x\n",
|
||||
e.fd, e.pipeid, e.flags, e.bytes);
|
||||
else
|
||||
pr_err("Dumping pipe %ld/%x flags %x\n", p->fd_name, id, p->flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fill_fd_params(pid_t pid, int fd, int lfd, struct fd_parms *p)
|
||||
{
|
||||
if (fstat(lfd, &p->stat) < 0) {
|
||||
@ -385,12 +383,11 @@ static int dump_one_fd(pid_t pid, int fd, int lfd,
|
||||
if (S_ISCHR(p.stat.st_mode))
|
||||
return dump_one_chrdev(&p, lfd, cr_fdset);
|
||||
|
||||
if (S_ISREG(p.stat.st_mode) || S_ISDIR(p.stat.st_mode))
|
||||
if (S_ISREG(p.stat.st_mode) ||
|
||||
S_ISDIR(p.stat.st_mode) ||
|
||||
S_ISFIFO(p.stat.st_mode))
|
||||
return dump_one_fdinfo(&p, lfd, cr_fdset);
|
||||
|
||||
if (S_ISFIFO(p.stat.st_mode))
|
||||
return dump_one_pipe(&p, lfd, cr_fdset);
|
||||
|
||||
return dump_unsupp_fd(&p);
|
||||
}
|
||||
|
||||
@ -1517,6 +1514,9 @@ int cr_dump_tasks(pid_t pid, const struct cr_options *opts)
|
||||
shmems = xmalloc(SHMEMS_SIZE);
|
||||
if (!shmems)
|
||||
goto err;
|
||||
pipes = xmalloc(PIPES_SIZE * sizeof(*pipes));
|
||||
if (!pipes)
|
||||
goto err;
|
||||
|
||||
list_for_each_entry(item, &pstree_list, list) {
|
||||
if (dump_one_task(item))
|
||||
@ -1527,10 +1527,11 @@ int cr_dump_tasks(pid_t pid, const struct cr_options *opts)
|
||||
}
|
||||
|
||||
ret = cr_dump_shmem();
|
||||
xfree(shmems);
|
||||
|
||||
fd_id_show_tree();
|
||||
err:
|
||||
xfree(shmems);
|
||||
xfree(pipes);
|
||||
close_cr_fdset(&glob_fdset);
|
||||
pstree_switch_state(&pstree_list, opts);
|
||||
free_pstree(&pstree_list);
|
||||
|
@ -139,8 +139,8 @@ void show_pipes(int fd_pipes, struct cr_options *o)
|
||||
ret = read_img_eof(fd_pipes, &e);
|
||||
if (ret <= 0)
|
||||
goto out;
|
||||
pr_msg("fd: %8x pipeid: %8x flags: %8x bytes: %8x\n",
|
||||
e.fd, e.pipeid, e.flags, e.bytes);
|
||||
pr_msg("id: %8x pipeid: %8x flags: %8x bytes: %8x\n",
|
||||
e.id, e.pipe_id, e.flags, e.bytes);
|
||||
if (e.bytes)
|
||||
lseek(fd_pipes, e.bytes, SEEK_CUR);
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ enum {
|
||||
CR_FD_PAGES,
|
||||
CR_FD_CORE,
|
||||
CR_FD_VMAS,
|
||||
CR_FD_PIPES,
|
||||
CR_FD_SIGACT,
|
||||
CR_FD_UNIXSK,
|
||||
CR_FD_ITIMERS,
|
||||
@ -49,6 +48,7 @@ enum {
|
||||
CR_FD_SK_QUEUES,
|
||||
CR_FD_REG_FILES,
|
||||
CR_FD_INETSK,
|
||||
CR_FD_PIPES,
|
||||
_CR_FD_GLOB_TO,
|
||||
|
||||
CR_FD_MAX
|
||||
@ -97,7 +97,7 @@ extern struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX];
|
||||
#define FMT_FNAME_REG_FILES "reg-files.img"
|
||||
#define FMT_FNAME_CORE "core-%d.img"
|
||||
#define FMT_FNAME_VMAS "vmas-%d.img"
|
||||
#define FMT_FNAME_PIPES "pipes-%d.img"
|
||||
#define FMT_FNAME_PIPES "pipes.img"
|
||||
#define FMT_FNAME_PSTREE "pstree.img"
|
||||
#define FMT_FNAME_SIGACTS "sigacts-%d.img"
|
||||
#define FMT_FNAME_UNIXSK "unixsk-%d.img"
|
||||
|
@ -33,6 +33,7 @@
|
||||
enum fd_types {
|
||||
FDINFO_UND,
|
||||
FDINFO_REG,
|
||||
FDINFO_PIPE,
|
||||
FDINFO_MAP,
|
||||
FDINFO_INETSK,
|
||||
FDINFO_CWD,
|
||||
@ -71,8 +72,8 @@ struct pstree_entry {
|
||||
} __packed;
|
||||
|
||||
struct pipe_entry {
|
||||
u32 fd;
|
||||
u32 pipeid;
|
||||
u32 id;
|
||||
u32 pipe_id;
|
||||
u32 flags;
|
||||
u32 bytes;
|
||||
u8 data[0];
|
||||
|
Loading…
x
Reference in New Issue
Block a user