forked from checkpoint-restore/criu
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fifo.c
168 lines (136 loc) · 3.94 KB
/
fifo.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include "imgset.h"
#include "image.h"
#include "files.h"
#include "files-reg.h"
#include "pipes.h"
#include "fifo.h"
#include "protobuf.h"
#include "protobuf/regfile.pb-c.h"
#include "protobuf/fifo.pb-c.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 descriptors which
* are useless for reg-files engine itself but needed for our fifo
* engine.
*
* In particular 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;
FifoEntry *fe;
bool restore_data;
struct file_desc *reg_d;
};
static LIST_HEAD(fifo_head);
static struct pipe_data_dump pd_fifo = { .img_type = CR_FD_FIFO_DATA, };
static int dump_one_fifo(int lfd, u32 id, const struct fd_parms *p)
{
struct cr_img *img = img_from_set(glob_imgset, CR_FD_FIFO);
FifoEntry e = FIFO_ENTRY__INIT;
/*
* 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, pipe_id(p));
e.id = id;
e.pipe_id = pipe_id(p);
if (pb_write_one(img, &e, PB_FIFO))
return -1;
return dump_one_pipe_data(&pd_fifo, lfd, p);
}
const struct fdtype_ops fifo_dump_ops = {
.type = FD_TYPES__FIFO,
.dump = dump_one_fifo,
};
static struct pipe_data_rst *pd_hash_fifo[PIPE_DATA_HASH_SIZE];
static int do_open_fifo(int ns_root_fd, struct reg_file_info *rfi, void *arg)
{
struct fifo_info *info = arg;
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 = openat(ns_root_fd, 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 = openat(ns_root_fd, 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->pipe_id, pd_hash_fifo)) {
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);
return open_path(info->reg_d, do_open_fifo, info);
}
static void collect_fifo_fd(struct file_desc *d,
struct fdinfo_list_entry *fle, struct rst_info *ri)
{
struct fifo_info *info;
info = container_of(d, struct fifo_info, d);
info->reg_d = collect_special_file(info->fe->id);
BUG_ON(info->reg_d == NULL);
collect_gen_fd(fle, ri);
}
static struct file_desc_ops fifo_desc_ops = {
.type = FD_TYPES__FIFO,
.open = open_fifo_fd,
.collect_fd = collect_fifo_fd,
};
static int collect_one_fifo(void *o, ProtobufCMessage *base)
{
struct fifo_info *info = o, *f;
info->fe = pb_msg(base, FifoEntry);
pr_info("Collected fifo entry ID %#x PIPE ID %#x\n",
info->fe->id, info->fe->pipe_id);
/* check who will restore the fifo data */
list_for_each_entry(f, &fifo_head, list)
if (f->fe->pipe_id == info->fe->pipe_id)
break;
if (&f->list == &fifo_head) {
list_add(&info->list, &fifo_head);
info->restore_data = true;
} else {
INIT_LIST_HEAD(&info->list);
info->restore_data = false;
}
return file_desc_add(&info->d, info->fe->id, &fifo_desc_ops);
}
struct collect_image_info fifo_cinfo = {
.fd_type = CR_FD_FIFO,
.pb_type = PB_FIFO,
.priv_size = sizeof(struct fifo_info),
.collect = collect_one_fifo,
};
int collect_fifo(void)
{
return collect_pipe_data(CR_FD_FIFO_DATA, pd_hash_fifo);
}