Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <sys/types.h>
3 : : #include <sys/stat.h>
4 : : #include <fcntl.h>
5 : : #include <stdlib.h>
6 : :
7 : : #include "fdset.h"
8 : : #include "image.h"
9 : : #include "files.h"
10 : : #include "files-reg.h"
11 : : #include "pipes.h"
12 : :
13 : : #include "fifo.h"
14 : :
15 : : #include "protobuf.h"
16 : : #include "protobuf/regfile.pb-c.h"
17 : : #include "protobuf/fifo.pb-c.h"
18 : :
19 : : /*
20 : : * FIFO checkpoint and restore is done in a bit unusual manner.
21 : : * We use files-reg.c engine to save fifo path and flags,
22 : : * thus regular files image will contain fifo descriptors which
23 : : * are useless for reg-files engine itself but needed for our fifo
24 : : * engine.
25 : : *
26 : : * In particular we dump fifo-entry automatically and appropriate
27 : : * reg-file entry manually, thus on restore we need to ask reg-file
28 : : * engine to restore fifo path and flags via direct call.
29 : : */
30 : :
31 : : struct fifo_info {
32 : : struct list_head list;
33 : : struct file_desc d;
34 : : FifoEntry *fe;
35 : : bool restore_data;
36 : : struct file_desc *reg_d;
37 : : };
38 : :
39 : : static LIST_HEAD(fifo_head);
40 : : static struct pipe_data_dump pd_fifo = { .img_type = CR_FD_FIFO_DATA, };
41 : :
42 : 28 : static int dump_one_fifo(int lfd, u32 id, const struct fd_parms *p)
43 : : {
44 : 28 : int img = fdset_fd(glob_fdset, CR_FD_FIFO);
45 : 28 : FifoEntry e = FIFO_ENTRY__INIT;
46 : :
47 : : /*
48 : : * It's a trick here, we use regular files dumping
49 : : * code to save path to a fifo, then we reuse it
50 : : * on restore.
51 : : */
52 [ + - ]: 28 : if (dump_one_reg_file(lfd, id, p))
53 : : return -1;
54 : :
55 : 28 : pr_info("Dumping fifo %d with id %#x pipe_id %#x\n",
56 : : lfd, id, pipe_id(p));
57 : :
58 : 28 : e.id = id;
59 : 28 : e.pipe_id = pipe_id(p);
60 : :
61 [ + - ]: 28 : if (pb_write_one(img, &e, PB_FIFO))
62 : : return -1;
63 : :
64 : 28 : return dump_one_pipe_data(&pd_fifo, lfd, p);
65 : : }
66 : :
67 : : const struct fdtype_ops fifo_dump_ops = {
68 : : .type = FD_TYPES__FIFO,
69 : : .dump = dump_one_fifo,
70 : : };
71 : :
72 : : static struct pipe_data_rst *pd_hash_fifo[PIPE_DATA_HASH_SIZE];
73 : :
74 : 14 : static int do_open_fifo(struct reg_file_info *rfi, void *arg)
75 : : {
76 : : struct fifo_info *info = arg;
77 : : int new_fifo, fake_fifo = -1;
78 : :
79 : : /*
80 : : * The fifos (except read-write fifos) do wait until
81 : : * another pipe-end get connected, so to be able to
82 : : * proceed the restoration procedure we open a fake
83 : : * fifo here.
84 : : */
85 : 14 : fake_fifo = open(rfi->path, O_RDWR);
86 [ - + ]: 14 : if (fake_fifo < 0) {
87 : 0 : pr_perror("Can't open fake fifo %#x [%s]", info->fe->id, rfi->path);
88 : 0 : return -1;
89 : : }
90 : :
91 : 14 : new_fifo = open(rfi->path, rfi->rfe->flags);
92 [ - + ]: 14 : if (new_fifo < 0) {
93 : 0 : pr_perror("Can't open fifo %#x [%s]", info->fe->id, rfi->path);
94 : 0 : goto out;
95 : : }
96 : :
97 [ + + ]: 14 : if (info->restore_data)
98 [ - + ]: 10 : if (restore_pipe_data(CR_FD_FIFO_DATA, fake_fifo,
99 : 10 : info->fe->pipe_id, pd_hash_fifo)) {
100 : 0 : close(new_fifo);
101 : : new_fifo = -1;
102 : : }
103 : :
104 : : out:
105 : 14 : close(fake_fifo);
106 : 14 : return new_fifo;
107 : : }
108 : :
109 : 14 : static int open_fifo_fd(struct file_desc *d)
110 : : {
111 : 14 : struct fifo_info *info = container_of(d, struct fifo_info, d);
112 : :
113 : 14 : return open_path(info->reg_d, do_open_fifo, info);
114 : : }
115 : :
116 : 28 : static void collect_fifo_fd(struct file_desc *d,
117 : : struct fdinfo_list_entry *fle, struct rst_info *ri)
118 : : {
119 : : struct fifo_info *info;
120 : :
121 : : info = container_of(d, struct fifo_info, d);
122 : 28 : info->reg_d = collect_special_file(info->fe->id);
123 [ - + ]: 28 : BUG_ON(info->reg_d == NULL);
124 : : collect_gen_fd(fle, ri);
125 : 28 : }
126 : :
127 : : static struct file_desc_ops fifo_desc_ops = {
128 : : .type = FD_TYPES__FIFO,
129 : : .open = open_fifo_fd,
130 : : .collect_fd = collect_fifo_fd,
131 : : };
132 : :
133 : 24 : static int collect_one_fifo(void *o, ProtobufCMessage *base)
134 : : {
135 : : struct fifo_info *info = o, *f;
136 : :
137 : 24 : info->fe = pb_msg(base, FifoEntry);
138 : 24 : pr_info("Collected fifo entry ID %#x PIPE ID %#x\n",
139 : : info->fe->id, info->fe->pipe_id);
140 : :
141 : : /* check who will restore the fifo data */
142 [ + + ]: 28 : list_for_each_entry(f, &fifo_head, list)
143 [ + + ]: 12 : if (f->fe->pipe_id == info->fe->pipe_id)
144 : : break;
145 : :
146 [ + + ]: 24 : if (&f->list == &fifo_head) {
147 : 16 : list_add(&info->list, &fifo_head);
148 : 16 : info->restore_data = true;
149 : : } else {
150 : 8 : INIT_LIST_HEAD(&info->list);
151 : 8 : info->restore_data = false;
152 : : }
153 : :
154 : 24 : return file_desc_add(&info->d, info->fe->id, &fifo_desc_ops);
155 : :
156 : : }
157 : :
158 : : struct collect_image_info fifo_cinfo = {
159 : : .fd_type = CR_FD_FIFO,
160 : : .pb_type = PB_FIFO,
161 : : .priv_size = sizeof(struct fifo_info),
162 : : .collect = collect_one_fifo,
163 : : };
164 : :
165 : 355 : int collect_fifo(void)
166 : : {
167 : 355 : return collect_pipe_data(CR_FD_FIFO_DATA, pd_hash_fifo);
168 : : }
|