Commit ea1ce8e4 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Pavel Emelyanov

fifo: Add checkpoint restore for fifos v4

Checkpoint and restore of fifo is similar to
pipes c/r except the pipe end-points are named
file.

Because the fifo has a name we use regular files
facility for fifo path c/r.

Still there is a trick used to "open" fifo:
the opening procedure migh sleep if a fifo's peer
is not yet opened, so before doing a real open
we yield a fake open procedure (with O_RDWR flag)
which prevents us from sleeping even if peer
is not yet ready. Also we need writable fifo
end to restore data queued.

v2:
 - add open/priv members to reg_file_info
 - make open_fifo_fd to use open_fe_fd
 - comment on pipe_id
 - make sure the fifo data is not restored twice

v3:
 - drop useless fixme comment and add sane one
v4:
 - Use restore_data flag to escape data restore duplication
 - Use S_ISREG for file contents copying
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 18145c50
......@@ -47,6 +47,7 @@ OBJS += sk-queue.o
OBJS += files.o
OBJS += files-reg.o
OBJS += pipes.o
OBJS += fifo.o
OBJS += file-ids.o
OBJS += namespaces.o
OBJS += uts_ns.o
......
......@@ -37,6 +37,7 @@
#include "files.h"
#include "files-reg.h"
#include "pipes.h"
#include "fifo.h"
#include "shmem.h"
#include "sk-inet.h"
#include "eventfd.h"
......@@ -293,8 +294,12 @@ static int dump_one_file(pid_t pid, int fd, int lfd, char fd_flags,
if (S_ISREG(p.stat.st_mode) || S_ISDIR(p.stat.st_mode))
return dump_reg_file(&p, lfd, cr_fdset);
if (S_ISFIFO(p.stat.st_mode) && (statfs.f_type == PIPEFS_MAGIC))
if (S_ISFIFO(p.stat.st_mode)) {
if (statfs.f_type == PIPEFS_MAGIC)
return dump_pipe(&p, lfd, cr_fdset);
else
return dump_fifo(&p, lfd, cr_fdset);
}
return dump_unsupp_fd(&p);
}
......
......@@ -36,6 +36,7 @@
#include "files.h"
#include "files-reg.h"
#include "pipes.h"
#include "fifo.h"
#include "sk-inet.h"
#include "eventfd.h"
#include "eventpoll.h"
......@@ -86,6 +87,9 @@ static int prepare_shared(void)
if (collect_pipes())
return -1;
if (collect_fifo())
return -1;
if (collect_inet_sockets())
return -1;
......
......@@ -62,6 +62,7 @@ static char *fdtype2s(u8 type)
[FDINFO_REG] = "reg",
[FDINFO_INETSK] = "isk",
[FDINFO_PIPE] = "pipe",
[FDINFO_FIFO] = "fifo",
[FDINFO_UNIXSK] = "usk",
[FDINFO_EVENTFD] = "efd",
[FDINFO_EVENTPOLL] = "epl",
......@@ -175,24 +176,23 @@ void show_ghost_file(int fd, struct cr_options *o)
pr_img_tail(CR_FD_GHOST_FILE);
}
void show_pipes_data(int fd_pipes, struct cr_options *o)
void __show_pipes_data(int fd, struct cr_options *o)
{
struct pipe_data_entry e;
int ret;
pr_img_head(CR_FD_PIPES_DATA);
while (1) {
ret = read_img_eof(fd_pipes, &e);
if (ret <= 0)
goto out;
if (read_img_eof(fd, &e) <= 0)
break;
pr_msg("pipeid: 0x%8x bytes: 0x%8x off: 0x%8x\n",
e.pipe_id, e.bytes, e.off);
lseek(fd_pipes, e.off + e.bytes, SEEK_CUR);
lseek(fd, e.off + e.bytes, SEEK_CUR);
}
}
out:
void show_pipes_data(int fd_pipes, struct cr_options *o)
{
pr_img_head(CR_FD_PIPES_DATA);
__show_pipes_data(fd_pipes, o);
pr_img_tail(CR_FD_PIPES_DATA);
}
......@@ -217,6 +217,26 @@ out:
pr_img_tail(CR_FD_PIPES);
}
void show_fifo_data(int fd, struct cr_options *o)
{
pr_img_head(CR_FD_FIFO_DATA);
__show_pipes_data(fd, o);
pr_img_tail(CR_FD_FIFO_DATA);
}
void show_fifo(int fd, struct cr_options *o)
{
struct fifo_entry e;
pr_img_head(CR_FD_FIFO);
while (1) {
if (read_img_eof(fd, &e) <= 0)
break;
pr_msg("id: 0x%8x pipeid: 0x%8x\n", e.id, e.pipe_id);
}
pr_img_tail(CR_FD_FIFO);
}
void show_fs(int fd_fs, struct cr_options *o)
{
struct fs_entry fe;
......
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include "crtools.h"
#include "image.h"
#include "files.h"
#include "files-reg.h"
#include "pipes.h"
#include "fifo.h"
/*
* FIFO checkpoint and restore is done in a bit unusual manner.
* We use files-reg.c engine to save fifo path and flags,
* thus regular files image will contain fifo descriptos which
* are useless for reg-files engine itself but needed for our fifo
* engine.
*
* In particual we dump fifo-entry automatically and appropriate
* reg-file entry manually, thus on restore we need to ask reg-file
* engine to restore fifo path and flags via direct call.
*/
struct fifo_info {
struct list_head list;
struct file_desc d;
struct fifo_entry fe;
u32 bytes;
off_t off;
bool restore_data;
};
static LIST_HEAD(fifo_head);
static int dump_one_fifo(int lfd, u32 id, const struct fd_parms *p)
{
int img = fdset_fd(glob_fdset, CR_FD_FIFO);
struct fifo_entry e;
/*
* It's a trick here, we use regular files dumping
* code to save path to a fifo, then we reuse it
* on restore.
*/
if (dump_one_reg_file(lfd, id, p))
return -1;
pr_info("Dumping fifo %d with id %#x pipe_id %#x\n",
lfd, id, (u32)p->stat.st_ino);
e.id = id;
e.pipe_id = p->stat.st_ino;
if (write_img(img, &e) < 0)
return -1;
return dump_one_pipe_data(CR_FD_FIFO_DATA, lfd, id, p);
}
static const struct fdtype_ops fifo_ops = {
.type = FDINFO_FIFO,
.make_gen_id = make_gen_id,
.dump = dump_one_fifo,
};
int dump_fifo(struct fd_parms *p, int lfd, const struct cr_fdset *set)
{
return do_dump_gen_file(p, lfd, &fifo_ops, set);
}
static int __open_fifo_fd(struct reg_file_info *rfi)
{
struct fifo_info *info = rfi->priv;
int new_fifo, fake_fifo = -1;
/*
* The fifos (except read-write fifos) do wait until
* another pipe-end get connected, so to be able to
* proceed the restoration procedure we open a fake
* fifo here.
*/
fake_fifo = open(rfi->path, O_RDWR);
if (fake_fifo < 0) {
pr_perror("Can't open fake fifo %#x [%s]", info->fe.id, rfi->path);
return -1;
}
new_fifo = open(rfi->path, rfi->rfe.flags);
if (new_fifo < 0) {
pr_perror("Can't open fifo %#x [%s]", info->fe.id, rfi->path);
goto out;
}
if (info->restore_data) {
if (restore_pipe_data(CR_FD_FIFO_DATA, fake_fifo, info->fe.id,
info->bytes, info->off)) {
close(new_fifo);
new_fifo = -1;
}
}
out:
close(fake_fifo);
return new_fifo;
}
static int open_fifo_fd(struct file_desc *d)
{
struct fifo_info *info = container_of(d, struct fifo_info, d);
struct reg_file_info *rfi;
struct file_desc *rd;
pr_info("\t\tCreating fifo pipe_id=%#x id=%#x\n",
info->fe.pipe_id, info->fe.id);
rd = find_file_desc_raw(FDINFO_REG, info->fe.id);
if (!rd) {
pr_perror("Can't find regfile for fifo %#x\n", info->fe.id);
return -1;
}
rfi = container_of(rd, struct reg_file_info, d);
if (rfi->open != __open_fifo_fd)
rfi->open = __open_fifo_fd;
rfi->priv = info;
return open_fe_fd(rd);
}
static struct file_desc_ops fifo_desc_ops = {
.type = FDINFO_FIFO,
.open = open_fifo_fd,
};
static int handle_fifo_data(void)
{
int img, ret;
img = open_image_ro(CR_FD_FIFO_DATA);
if (img < 0)
return -1;
while (1) {
struct pipe_data_entry pde;
struct fifo_info *info;
ret = read_img_eof(img, &pde);
if (ret <= 0)
break;
list_for_each_entry(info, &fifo_head, list) {
if (info->fe.pipe_id != pde.pipe_id ||
info->restore_data)
continue;
info->off = lseek(img, 0, SEEK_CUR) + pde.off;
info->bytes = pde.bytes;
lseek(img, pde.bytes + pde.off, SEEK_CUR);
info->restore_data = true;
break;
}
}
close(img);
return ret;
}
int collect_fifo(void)
{
struct fifo_info *info = NULL;
int img, ret = -1;
img = open_image_ro(CR_FD_FIFO);
if (img < 0)
return -1;
while (1) {
info = xzalloc(sizeof(*info));
if (!info) {
ret = -1;
break;
}
ret = read_img_eof(img, &info->fe);
if (ret <= 0)
break;
pr_info("Collected fifo entry ID %#x PIPE ID %#x\n",
info->fe.id, info->fe.pipe_id);
file_desc_add(&info->d, info->fe.id, &fifo_desc_ops);
list_add(&info->list, &fifo_head);
}
if (!ret)
ret = handle_fifo_data();
xfree(info);
close(img);
return ret;
}
......@@ -14,14 +14,6 @@
#include "files-reg.h"
struct reg_file_info {
struct file_desc d;
struct reg_file_entry rfe;
char *remap_path;
char *path;
};
struct ghost_file {
struct list_head list;
u32 id;
......@@ -348,7 +340,12 @@ int dump_reg_file(struct fd_parms *p, int lfd,
return do_dump_gen_file(p, lfd, &regfile_ops, cr_fdset);
}
static int open_fe_fd(struct file_desc *d)
static int __open_reg_fd(struct reg_file_info *rfi)
{
return open(rfi->path, rfi->rfe.flags);
}
int open_fe_fd(struct file_desc *d)
{
struct reg_file_info *rfi;
int tmp;
......@@ -362,7 +359,7 @@ static int open_fe_fd(struct file_desc *d)
return -1;
}
tmp = open(rfi->path, rfi->rfe.flags);
tmp = rfi->open(rfi);
if (tmp < 0) {
pr_perror("Can't open file %s", rfi->path);
return -1;
......@@ -422,6 +419,7 @@ int collect_reg_files(void)
break;
rfi->remap_path = NULL;
rfi->open = __open_reg_fd;
pr_info("Collected [%s] ID %#x\n", rfi->path, rfi->rfe.id);
file_desc_add(&rfi->d, rfi->rfe.id, &reg_desc_ops);
......
......@@ -39,6 +39,8 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {
FD_ENTRY(VMAS, "vmas-%d", show_vmas),
FD_ENTRY(PIPES, "pipes", show_pipes),
FD_ENTRY(PIPES_DATA, "pipes-data", show_pipes_data),
FD_ENTRY(FIFO, "fifo", show_fifo),
FD_ENTRY(FIFO_DATA, "fifo-data", show_fifo_data),
FD_ENTRY(PSTREE, "pstree", show_pstree),
FD_ENTRY(SIGACT, "sigacts-%d", show_sigacts),
FD_ENTRY(UNIXSK, "unixsk", show_unixsk),
......
......@@ -54,6 +54,8 @@ enum {
CR_FD_UNIXSK,
CR_FD_PIPES,
CR_FD_PIPES_DATA,
CR_FD_FIFO,
CR_FD_FIFO_DATA,
CR_FD_REMAP_FPATH,
CR_FD_EVENTFD,
CR_FD_EVENTPOLL,
......@@ -104,6 +106,8 @@ void show_mm(int fd_mm, struct cr_options *o);
void show_vmas(int fd_vma, struct cr_options *o);
void show_pipes(int fd_pipes, struct cr_options *o);
void show_pipes_data(int fd_pipes, struct cr_options *o);
void show_fifo(int fd, struct cr_options *o);
void show_fifo_data(int fd_pipes, struct cr_options *o);
void show_pstree(int fd_pstree, struct cr_options *o);
void show_sigacts(int fd_sigacts, struct cr_options *o);
void show_itimers(int fd, struct cr_options *o);
......
#ifndef FIFO_H__
#define FIFO_H__
struct fd_parms;
struct cr_fdset;
extern int dump_fifo(struct fd_parms *p, int lfd, const struct cr_fdset *set);
extern int collect_fifo(void);
#endif /* FIFO_H__ */
......@@ -2,13 +2,28 @@
#define FILES_REG_H__
#include "types.h"
#include "files.h"
#include "image.h"
struct cr_fdset;
struct fd_parms;
struct reg_file_info {
struct file_desc d;
struct reg_file_entry rfe;
char *remap_path;
char *path;
int (*open)(struct reg_file_info *rfi);
void *priv;
};
extern int open_reg_by_id(u32 id);
extern void clear_ghost_files(void);
extern int collect_reg_files(void);
extern int open_fe_fd(struct file_desc *d);
extern int dump_reg_file(struct fd_parms *p, int lfd, const struct cr_fdset *cr_fdset);
extern int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p);
......
......@@ -17,6 +17,8 @@
#define VMAS_MAGIC 0x54123737 /* Tula */
#define PIPES_MAGIC 0x56513555 /* Tver */
#define PIPES_DATA_MAGIC 0x56453709 /* Dubna */
#define FIFO_MAGIC 0x58364939 /* Kirov */
#define FIFO_DATA_MAGIC 0x59333054 /* Tosno */
#define SIGACT_MAGIC 0x55344201 /* Murom */
#define UNIXSK_MAGIC 0x54373943 /* Ryazan */
#define INETSK_MAGIC 0x56443851 /* Pereslavl */
......@@ -45,6 +47,7 @@ enum fd_types {
FDINFO_UND,
FDINFO_REG,
FDINFO_PIPE,
FDINFO_FIFO,
FDINFO_INETSK,
FDINFO_UNIXSK,
FDINFO_EVENTFD,
......@@ -162,6 +165,11 @@ struct pipe_data_entry {
u8 data[0];
} __packed;
struct fifo_entry {
u32 id;
u32 pipe_id;
} __packed;
/*
* splice() connect cache pages to pipe buffer, so
* some part of pages may be loosed if data are not
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment