Branch data Line data Source code
1 : : #include <sys/socket.h>
2 : : #include <netinet/in.h>
3 : : #include <arpa/inet.h>
4 : : #include <linux/falloc.h>
5 : : #include <unistd.h>
6 : : #include <fcntl.h>
7 : :
8 : : #include "cr_options.h"
9 : : #include "servicefd.h"
10 : : #include "image.h"
11 : : #include "page-xfer.h"
12 : : #include "page-pipe.h"
13 : :
14 : : #include "protobuf.h"
15 : : #include "protobuf/pagemap.pb-c.h"
16 : :
17 : : struct page_server_iov {
18 : : u32 cmd;
19 : : u32 nr_pages;
20 : : u64 vaddr;
21 : : u64 dst_id;
22 : : };
23 : :
24 : : static int open_page_local_xfer(struct page_xfer *xfer, int fd_type, long id);
25 : :
26 : : #define PS_IOV_ADD 1
27 : : #define PS_IOV_HOLE 2
28 : : #define PS_IOV_OPEN 3
29 : :
30 : : #define PS_IOV_FLUSH 0x1023
31 : :
32 : : #define PS_TYPE_BITS 8
33 : : #define PS_TYPE_MASK ((1 << PS_TYPE_BITS) - 1)
34 : :
35 : : static inline u64 encode_pm_id(int type, long id)
36 : : {
37 : 1854 : return ((u64)id) << PS_TYPE_BITS | type;
38 : : }
39 : :
40 : : static int decode_pm_type(u64 dst_id)
41 : : {
42 : 1854 : return dst_id & PS_TYPE_MASK;
43 : : }
44 : :
45 : : static long decode_pm_id(u64 dst_id)
46 : : {
47 : 1854 : return (long)(dst_id >> PS_TYPE_BITS);
48 : : }
49 : :
50 : : struct page_xfer_job {
51 : : u64 dst_id;
52 : : int p[2];
53 : : unsigned pipe_size;
54 : : struct page_xfer loc_xfer;
55 : : };
56 : :
57 : : static struct page_xfer_job cxfer = {
58 : : .dst_id = ~0,
59 : : };
60 : :
61 : : static void page_server_close(void)
62 : : {
63 [ + + ][ + - ]: 2750 : if (cxfer.dst_id != ~0)
64 : 1854 : cxfer.loc_xfer.close(&cxfer.loc_xfer);
65 : : }
66 : :
67 : 3708 : static int page_server_open(struct page_server_iov *pi)
68 : : {
69 : : int type;
70 : : long id;
71 : :
72 : 1854 : type = decode_pm_type(pi->dst_id);
73 : : id = decode_pm_id(pi->dst_id);
74 : 1854 : pr_info("Opening %d/%ld\n", type, id);
75 : :
76 : : page_server_close();
77 : :
78 [ + - ]: 1854 : if (open_page_local_xfer(&cxfer.loc_xfer, type, id))
79 : : return -1;
80 : :
81 : 1854 : cxfer.dst_id = pi->dst_id;
82 : : return 0;
83 : : }
84 : :
85 : 76880 : static int prep_loc_xfer(struct page_server_iov *pi)
86 : : {
87 [ - + ]: 76880 : if (cxfer.dst_id != pi->dst_id) {
88 : 0 : pr_warn("Deprecated IO w/o open\n");
89 : 0 : return page_server_open(pi);
90 : : } else
91 : : return 0;
92 : : }
93 : :
94 : 61566 : static int page_server_add(int sk, struct page_server_iov *pi)
95 : : {
96 : : size_t len;
97 : : struct page_xfer *lxfer = &cxfer.loc_xfer;
98 : : struct iovec iov;
99 : :
100 : 61566 : pr_debug("Adding %"PRIx64"/%u\n", pi->vaddr, pi->nr_pages);
101 : :
102 [ + - ]: 61566 : if (prep_loc_xfer(pi))
103 : : return -1;
104 : :
105 : 123132 : iov.iov_base = decode_pointer(pi->vaddr);
106 : 61566 : iov.iov_len = pi->nr_pages * PAGE_SIZE;
107 : :
108 [ + - ]: 61566 : if (lxfer->write_pagemap(lxfer, &iov))
109 : : return -1;
110 : :
111 : 61566 : len = iov.iov_len;
112 [ + + ]: 140460 : while (len > 0) {
113 : : ssize_t chunk;
114 : :
115 : 78894 : chunk = len;
116 [ + + ]: 78894 : if (chunk > cxfer.pipe_size)
117 : : chunk = cxfer.pipe_size;
118 : :
119 : 78894 : chunk = splice(sk, NULL, cxfer.p[1], NULL, chunk, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
120 [ - + ]: 78894 : if (chunk < 0) {
121 : 0 : pr_perror("Can't read from socket");
122 : 0 : return -1;
123 : : }
124 : :
125 [ + - ]: 78894 : if (lxfer->write_pages(lxfer, cxfer.p[0], chunk))
126 : : return -1;
127 : :
128 : 78894 : len -= chunk;
129 : : }
130 : :
131 : : return 0;
132 : : }
133 : :
134 : 30628 : static int page_server_hole(int sk, struct page_server_iov *pi)
135 : : {
136 : : struct page_xfer *lxfer = &cxfer.loc_xfer;
137 : : struct iovec iov;
138 : :
139 : 15314 : pr_debug("Adding %"PRIx64"/%u hole\n", pi->vaddr, pi->nr_pages);
140 : :
141 [ + - ]: 15314 : if (prep_loc_xfer(pi))
142 : : return -1;
143 : :
144 : 30628 : iov.iov_base = decode_pointer(pi->vaddr);
145 : 15314 : iov.iov_len = pi->nr_pages * PAGE_SIZE;
146 : :
147 [ + - ]: 15314 : if (lxfer->write_hole(lxfer, &iov))
148 : : return -1;
149 : :
150 : : return 0;
151 : : }
152 : :
153 : 896 : static int page_server_serve(int sk)
154 : : {
155 : : int ret = -1;
156 : : bool flushed = false;
157 : :
158 [ - + ]: 896 : if (pipe(cxfer.p)) {
159 : 0 : pr_perror("Can't make pipe for xfer");
160 : 0 : close(sk);
161 : 0 : return -1;
162 : : }
163 : :
164 : 896 : cxfer.pipe_size = fcntl(cxfer.p[0], F_GETPIPE_SZ, 0);
165 : 896 : pr_debug("Created xfer pipe size %u\n", cxfer.pipe_size);
166 : :
167 : : while (1) {
168 : : struct page_server_iov pi;
169 : :
170 : 80526 : ret = recv(sk, &pi, sizeof(pi), MSG_WAITALL);
171 [ + + ]: 80526 : if (!ret)
172 : : break;
173 : :
174 [ - + ]: 79630 : if (ret != sizeof(pi)) {
175 : 0 : pr_perror("Can't read pagemap from socket");
176 : : ret = -1;
177 : 0 : break;
178 : : }
179 : :
180 : : flushed = false;
181 : :
182 [ + + + + : 79630 : switch (pi.cmd) {
- ]
183 : : case PS_IOV_OPEN:
184 : 1854 : ret = page_server_open(&pi);
185 : 1854 : break;
186 : : case PS_IOV_ADD:
187 : 61566 : ret = page_server_add(sk, &pi);
188 : 61566 : break;
189 : : case PS_IOV_HOLE:
190 : 15314 : ret = page_server_hole(sk, &pi);
191 : 15314 : break;
192 : : case PS_IOV_FLUSH:
193 : : {
194 : 896 : int32_t status = 0;
195 : :
196 : : /*
197 : : * An answer must be sent back to inform another side,
198 : : * that all data were received
199 : : */
200 [ - + ]: 896 : if (write(sk, &status, sizeof(status)) != sizeof(status)) {
201 : 896 : pr_perror("Can't send the final package");
202 : : ret = -1;
203 : : }
204 : :
205 : : flushed = true;
206 : : ret = 0;
207 : : break;
208 : : }
209 : : default:
210 : 0 : pr_err("Unknown command %u\n", pi.cmd);
211 : : ret = -1;
212 : 0 : break;
213 : : }
214 : :
215 [ + - ]: 79630 : if (ret)
216 : : break;
217 : 79630 : }
218 : :
219 [ - + ]: 896 : if (!ret && !flushed) {
220 : 0 : pr_err("The data were not flushed\n");
221 : : ret = -1;
222 : : }
223 : :
224 : : page_server_close();
225 : 896 : pr_info("Session over\n");
226 : :
227 : 896 : close(sk);
228 : 896 : return ret;
229 : : }
230 : :
231 : 1792 : static int get_sockaddr_in(struct sockaddr_in *addr)
232 : : {
233 : : memset(addr, 0, sizeof(*addr));
234 : 1792 : addr->sin_family = AF_INET;
235 : :
236 [ + + ]: 1792 : if (!opts.addr)
237 : 896 : addr->sin_addr.s_addr = INADDR_ANY;
238 [ - + ]: 896 : else if (!inet_aton(opts.addr, &addr->sin_addr)) {
239 : 0 : pr_perror("Bad page server address");
240 : 0 : return -1;
241 : : }
242 : :
243 : 1792 : addr->sin_port = opts.ps_port;
244 : 1792 : return 0;
245 : : }
246 : :
247 : 896 : int cr_page_server(bool daemon_mode)
248 : : {
249 : : int sk, ask = -1, ret;
250 : : struct sockaddr_in saddr, caddr;
251 : 896 : socklen_t clen = sizeof(caddr);
252 : :
253 : 896 : up_page_ids_base();
254 : :
255 [ - + ]: 896 : pr_info("Starting page server on port %u\n", (int)ntohs(opts.ps_port));
256 : :
257 : 896 : sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
258 [ - + ]: 896 : if (sk < 0) {
259 : 0 : pr_perror("Can't init page server");
260 : 0 : return -1;
261 : : }
262 : :
263 [ + - ]: 896 : if (get_sockaddr_in(&saddr))
264 : : goto out;
265 : :
266 [ - + ]: 896 : if (bind(sk, (struct sockaddr *)&saddr, sizeof(saddr))) {
267 : 0 : pr_perror("Can't bind page server");
268 : 0 : goto out;
269 : : }
270 : :
271 [ - + ]: 896 : if (listen(sk, 1)) {
272 : 0 : pr_perror("Can't listen on page server socket");
273 : 0 : goto out;
274 : : }
275 : :
276 [ + - ]: 896 : if (daemon_mode) {
277 : 896 : ret = cr_daemon(1, 0);
278 [ - + ]: 1792 : if (ret == -1) {
279 : 0 : pr_perror("Can't run in the background");
280 : 0 : goto out;
281 : : }
282 [ + + ]: 1792 : if (ret > 0) /* parent task, daemon started */
283 : : return ret;
284 : : }
285 : :
286 [ - + ]: 896 : if (opts.pidfile) {
287 [ # # ]: 0 : if (write_pidfile(getpid()) == -1) {
288 : 0 : pr_perror("Can't write pidfile");
289 : 0 : return -1;
290 : : }
291 : : }
292 : :
293 : 896 : ret = ask = accept(sk, (struct sockaddr *)&caddr, &clen);
294 [ - + ]: 896 : if (ask < 0)
295 : 0 : pr_perror("Can't accept connection to server");
296 : :
297 : 896 : close(sk);
298 : :
299 [ + - ]: 896 : if (ask >= 0) {
300 [ - + ]: 896 : pr_info("Accepted connection from %s:%u\n",
301 : : inet_ntoa(caddr.sin_addr),
302 : : (int)ntohs(caddr.sin_port));
303 : :
304 : 896 : ret = page_server_serve(ask);
305 : : }
306 : :
307 [ + - ]: 896 : if (daemon_mode)
308 : 896 : exit(ret);
309 : :
310 : : return ret;
311 : :
312 : : out:
313 : 0 : close(sk);
314 : 0 : return -1;
315 : : }
316 : :
317 : : static int page_server_sk = -1;
318 : :
319 : 1792 : int connect_to_page_server(void)
320 : : {
321 : : struct sockaddr_in saddr;
322 : :
323 [ + + ]: 1792 : if (!opts.use_page_server)
324 : : return 0;
325 : :
326 [ - + ]: 896 : pr_info("Connecting to server %s:%u\n",
327 : : opts.addr, (int)ntohs(opts.ps_port));
328 : :
329 : 896 : page_server_sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
330 [ - + ]: 896 : if (page_server_sk < 0) {
331 : 0 : pr_perror("Can't create socket");
332 : 0 : return -1;
333 : : }
334 : :
335 [ + - ]: 896 : if (get_sockaddr_in(&saddr))
336 : : return -1;
337 : :
338 [ - + ]: 896 : if (connect(page_server_sk, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
339 : 0 : pr_perror("Can't connect to server");
340 : 0 : return -1;
341 : : }
342 : :
343 : : return 0;
344 : : }
345 : :
346 : 1792 : int disconnect_from_page_server(void)
347 : : {
348 : 1792 : struct page_server_iov pi = { .cmd = PS_IOV_FLUSH };
349 : 1792 : int32_t status = -1;
350 : : int ret = -1;
351 : :
352 [ + + ]: 1792 : if (!opts.use_page_server)
353 : : return 0;
354 : :
355 [ + - ]: 896 : if (page_server_sk == -1)
356 : : return 0;
357 : :
358 [ - + ]: 896 : pr_info("Disconnect from the page server %s:%u\n",
359 : : opts.addr, (int)ntohs(opts.ps_port));
360 : :
361 [ - + ]: 896 : if (write(page_server_sk, &pi, sizeof(pi)) != sizeof(pi)) {
362 : 0 : pr_perror("Can't write the fini command to server");
363 : 0 : goto out;
364 : : }
365 : :
366 [ - + ]: 896 : if (read(page_server_sk, &status, sizeof(status)) != sizeof(status)) {
367 : 0 : pr_perror("The page server doesn't answer");
368 : 0 : goto out;
369 : : }
370 : :
371 : : ret = 0;
372 : : out:
373 : 896 : close_safe(&page_server_sk);
374 [ + - ]: 896 : return ret ? : status;
375 : : }
376 : :
377 : 61566 : static int write_pagemap_to_server(struct page_xfer *xfer,
378 : : struct iovec *iov)
379 : : {
380 : : struct page_server_iov pi;
381 : :
382 : 61566 : pi.cmd = PS_IOV_ADD;
383 : 61566 : pi.dst_id = xfer->dst_id;
384 : 123132 : pi.vaddr = encode_pointer(iov->iov_base);
385 : 61566 : pi.nr_pages = iov->iov_len / PAGE_SIZE;
386 : :
387 [ - + ]: 61566 : if (write(xfer->fd, &pi, sizeof(pi)) != sizeof(pi)) {
388 : 0 : pr_perror("Can't write pagemap to server");
389 : 0 : return -1;
390 : : }
391 : :
392 : : return 0;
393 : : }
394 : :
395 : 61566 : static int write_pages_to_server(struct page_xfer *xfer,
396 : : int p, unsigned long len)
397 : : {
398 : 61566 : pr_debug("Splicing %lu bytes / %lu pages into socket\n", len, len / PAGE_SIZE);
399 : :
400 [ - + ]: 61566 : if (splice(p, NULL, xfer->fd, NULL, len, SPLICE_F_MOVE) != len) {
401 : 0 : pr_perror("Can't write pages to socket");
402 : 0 : return -1;
403 : : }
404 : :
405 : : return 0;
406 : : }
407 : :
408 : 15314 : static int write_hole_to_server(struct page_xfer *xfer, struct iovec *iov)
409 : : {
410 : : struct page_server_iov pi;
411 : :
412 : 15314 : pi.cmd = PS_IOV_HOLE;
413 : 15314 : pi.dst_id = xfer->dst_id;
414 : 30628 : pi.vaddr = encode_pointer(iov->iov_base);
415 : 15314 : pi.nr_pages = iov->iov_len / PAGE_SIZE;
416 : :
417 [ - + ]: 15314 : if (write(xfer->fd, &pi, sizeof(pi)) != sizeof(pi)) {
418 : 0 : pr_perror("Can't write pagehole to server");
419 : 0 : return -1;
420 : : }
421 : :
422 : : return 0;
423 : : }
424 : :
425 : 1854 : static void close_server_xfer(struct page_xfer *xfer)
426 : : {
427 : 1854 : xfer->fd = -1;
428 : 1854 : }
429 : :
430 : 1854 : static int open_page_server_xfer(struct page_xfer *xfer, int fd_type, long id)
431 : : {
432 : : struct page_server_iov pi;
433 : :
434 : 1854 : xfer->fd = page_server_sk;
435 : 1854 : xfer->write_pagemap = write_pagemap_to_server;
436 : 1854 : xfer->write_pages = write_pages_to_server;
437 : 1854 : xfer->write_hole = write_hole_to_server;
438 : 1854 : xfer->close = close_server_xfer;
439 : 1854 : xfer->dst_id = encode_pm_id(fd_type, id);
440 : :
441 : 1854 : pi.cmd = PS_IOV_OPEN;
442 : 1854 : pi.dst_id = xfer->dst_id;
443 : 1854 : pi.vaddr = 0;
444 : 1854 : pi.nr_pages = 0;
445 : :
446 [ - + ]: 1854 : if (write(xfer->fd, &pi, sizeof(pi)) != sizeof(pi)) {
447 : 0 : pr_perror("Can't write to page server");
448 : 0 : return -1;
449 : : }
450 : :
451 : : return 0;
452 : : }
453 : :
454 : 122936 : static int write_pagemap_loc(struct page_xfer *xfer,
455 : : struct iovec *iov)
456 : : {
457 : : int ret;
458 : 122936 : PagemapEntry pe = PAGEMAP_ENTRY__INIT;
459 : :
460 : 245872 : pe.vaddr = encode_pointer(iov->iov_base);
461 : 122936 : pe.nr_pages = iov->iov_len / PAGE_SIZE;
462 : :
463 [ + - ][ + + ]: 122936 : if (opts.auto_dedup && xfer->parent != NULL) {
464 : 87464 : ret = dedup_one_iovec(xfer->parent, iov);
465 [ - + ]: 87464 : if (ret == -1) {
466 : 0 : pr_perror("Auto-deduplication failed");
467 : 0 : return ret;
468 : : }
469 : : }
470 : 122936 : return pb_write_one(xfer->fd, &pe, PB_PAGEMAP);
471 : : }
472 : :
473 : 140264 : static int write_pages_loc(struct page_xfer *xfer,
474 : : int p, unsigned long len)
475 : : {
476 : : ssize_t ret;
477 : 140264 : ret = splice(p, NULL, xfer->fd_pg, NULL, len, SPLICE_F_MOVE);
478 [ - + ]: 140264 : if (ret == -1) {
479 : 0 : pr_perror("Unable to spice data");
480 : 0 : return -1;
481 : : }
482 [ - + ]: 140264 : if (ret != len) {
483 : 0 : pr_err("Only %zu of %lu bytes have been spliced\n", ret, len);
484 : 0 : return -1;
485 : : }
486 : :
487 : : return 0;
488 : : }
489 : :
490 : 30707 : static int check_pagehole_in_parent(struct page_read *p, struct iovec *iov)
491 : : {
492 : : int ret;
493 : : unsigned long off, end;
494 : :
495 : : /*
496 : : * Try to find pagemap entry in parent, from which
497 : : * the data will be read on restore.
498 : : *
499 : : * This is the optimized version of the page-by-page
500 : : * read_pagemap_page routine.
501 : : */
502 : :
503 : 30707 : pr_debug("Checking %p/%zu hole\n", iov->iov_base, iov->iov_len);
504 : 30707 : off = (unsigned long)iov->iov_base;
505 : 30707 : end = off + iov->iov_len;
506 : : while (1) {
507 : : struct iovec piov;
508 : : unsigned long pend;
509 : :
510 : 31795 : ret = seek_pagemap_page(p, off, true);
511 [ + - ][ + - ]: 31795 : if (ret <= 0 || !p->pe)
512 : 30707 : return -1;
513 : :
514 : 31795 : pagemap2iovec(p->pe, &piov);
515 : 31795 : pr_debug("\tFound %p/%zu\n", piov.iov_base, piov.iov_len);
516 : :
517 : : /*
518 : : * The pagemap entry in parent may heppen to be
519 : : * shorter, than the hole we write. In this case
520 : : * we should go ahead and check the remainder.
521 : : */
522 : :
523 : 31795 : pend = (unsigned long)piov.iov_base + piov.iov_len;
524 [ + + ]: 31795 : if (end <= pend)
525 : : return 0;
526 : :
527 : 1088 : pr_debug("\t\tcontinue on %lx\n", pend);
528 : : off = pend;
529 : 1088 : }
530 : : }
531 : :
532 : 30731 : static int write_pagehole_loc(struct page_xfer *xfer, struct iovec *iov)
533 : : {
534 : 30731 : PagemapEntry pe = PAGEMAP_ENTRY__INIT;
535 : :
536 [ + + ]: 30731 : if (xfer->parent != NULL) {
537 : : int ret;
538 : :
539 : 30707 : ret = check_pagehole_in_parent(xfer->parent, iov);
540 [ - + ]: 30707 : if (ret) {
541 : 0 : pr_err("Hole %p/%zu not found in parent\n",
542 : : iov->iov_base, iov->iov_len);
543 : 0 : return -1;
544 : : }
545 : : }
546 : :
547 : 61462 : pe.vaddr = encode_pointer(iov->iov_base);
548 : 30731 : pe.nr_pages = iov->iov_len / PAGE_SIZE;
549 : 30731 : pe.has_in_parent = true;
550 : 30731 : pe.in_parent = true;
551 : :
552 [ + - ]: 30731 : if (pb_write_one(xfer->fd, &pe, PB_PAGEMAP) < 0)
553 : : return -1;
554 : :
555 : 30731 : return 0;
556 : : }
557 : :
558 : 3706 : static void close_page_xfer(struct page_xfer *xfer)
559 : : {
560 [ + + ]: 3706 : if (xfer->parent != NULL) {
561 : 2742 : xfer->parent->close(xfer->parent);
562 [ + - ]: 2742 : xfree(xfer->parent);
563 : 2742 : xfer->parent = NULL;
564 : : }
565 : 3706 : close(xfer->fd_pg);
566 : 3706 : close(xfer->fd);
567 : 3706 : }
568 : :
569 : 3706 : int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp,
570 : : unsigned long off)
571 : : {
572 : : struct page_pipe_buf *ppb;
573 : : struct iovec *hole = NULL;
574 : :
575 : 3706 : pr_debug("Transfering pages:\n");
576 : :
577 [ + + ]: 3706 : if (pp->free_hole)
578 : 2740 : hole = &pp->holes[0];
579 : :
580 [ + + ]: 8644 : list_for_each_entry(ppb, &pp->bufs, l) {
581 : : int i;
582 : :
583 : 4938 : pr_debug("\tbuf %d/%d\n", ppb->pages_in, ppb->nr_segs);
584 : :
585 [ + + ]: 127874 : for (i = 0; i < ppb->nr_segs; i++) {
586 : 122936 : struct iovec *iov = &ppb->iov[i];
587 : :
588 [ + + ][ + + ]: 148069 : while (hole && (hole->iov_base < iov->iov_base)) {
589 : 25133 : pr_debug("\th %p [%u]\n", hole->iov_base,
590 : : (unsigned int)(hole->iov_len / PAGE_SIZE));
591 [ + - ]: 25133 : if (xfer->write_hole(xfer, hole))
592 : : return -1;
593 : :
594 : 25133 : hole++;
595 [ - + ]: 25133 : if (hole >= &pp->holes[pp->free_hole])
596 : : hole = NULL;
597 : : }
598 : :
599 [ - + ]: 122936 : BUG_ON(iov->iov_base < (void *)off);
600 : 122936 : iov->iov_base -= off;
601 : 122936 : pr_debug("\tp %p [%u]\n", iov->iov_base,
602 : : (unsigned int)(iov->iov_len / PAGE_SIZE));
603 : :
604 [ + - ]: 122936 : if (xfer->write_pagemap(xfer, iov))
605 : : return -1;
606 [ + - ]: 122936 : if (xfer->write_pages(xfer, ppb->p[0], iov->iov_len))
607 : : return -1;
608 : : }
609 : : }
610 : :
611 [ + + ]: 9304 : while (hole) {
612 : 5598 : pr_debug("\th* %p [%u]\n", hole->iov_base,
613 : : (unsigned int)(hole->iov_len / PAGE_SIZE));
614 [ + - ]: 5598 : if (xfer->write_hole(xfer, hole))
615 : : return -1;
616 : :
617 : 5598 : hole++;
618 [ + + ]: 5598 : if (hole >= &pp->holes[pp->free_hole])
619 : : hole = NULL;
620 : : }
621 : :
622 : : return 0;
623 : : }
624 : :
625 : 3706 : static int open_page_local_xfer(struct page_xfer *xfer, int fd_type, long id)
626 : : {
627 : 3706 : xfer->fd = open_image(fd_type, O_DUMP, id);
628 [ + - ]: 3706 : if (xfer->fd < 0)
629 : : return -1;
630 : :
631 : 3706 : xfer->fd_pg = open_pages_image(O_DUMP, xfer->fd);
632 [ - + ]: 3706 : if (xfer->fd_pg < 0) {
633 : 0 : close(xfer->fd);
634 : 0 : return -1;
635 : : }
636 : :
637 : : /*
638 : : * Open page-read for parent images (if it exists). It will
639 : : * be used for two things:
640 : : * 1) when writing a page, those from parent will be dedup-ed
641 : : * 2) when writing a hole, the respective place would be checked
642 : : * to exist in parent (either pagemap or hole)
643 : : */
644 : 3706 : xfer->parent = NULL;
645 [ + + ]: 3706 : if (fd_type == CR_FD_PAGEMAP) {
646 : : int ret;
647 : : int pfd;
648 : :
649 : 3664 : pfd = openat(get_service_fd(IMG_FD_OFF), CR_PARENT_LINK, O_RDONLY);
650 [ + + ][ - + ]: 3664 : if (pfd < 0 && errno == ENOENT)
651 : : goto out;
652 : :
653 [ - + ]: 2749 : xfer->parent = xmalloc(sizeof(*xfer->parent));
654 [ - + ]: 2749 : if (!xfer->parent) {
655 : 0 : close(pfd);
656 : 0 : return -1;
657 : : }
658 : :
659 : 2749 : ret = open_page_read_at(pfd, id, xfer->parent, O_RDWR, false);
660 [ + + ]: 2749 : if (ret) {
661 : 7 : pr_perror("No parent image found, though parent directory is set");
662 [ + - ]: 7 : xfree(xfer->parent);
663 : 7 : xfer->parent = NULL;
664 : 7 : close(pfd);
665 : 7 : goto out;
666 : : }
667 : 2742 : close(pfd);
668 : : }
669 : :
670 : : out:
671 : 3706 : xfer->write_pagemap = write_pagemap_loc;
672 : 3706 : xfer->write_pages = write_pages_loc;
673 : 3706 : xfer->write_hole = write_pagehole_loc;
674 : 3706 : xfer->close = close_page_xfer;
675 : 3706 : return 0;
676 : : }
677 : :
678 : 3706 : int open_page_xfer(struct page_xfer *xfer, int fd_type, long id)
679 : : {
680 [ + + ]: 3706 : if (opts.use_page_server)
681 : 1854 : return open_page_server_xfer(xfer, fd_type, id);
682 : : else
683 : 1852 : return open_page_local_xfer(xfer, fd_type, id);
684 : : }
|