2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-30 22:05:36 +00:00

page-xfer: adjust a buffer to a pipe size

Due to side effects of F_SETPIPE_SZ, the actual pipe size can be greater
than PIPE_MAX_SIZE.

Signed-off-by: Andrei Vagin <avagin@gmail.com>
This commit is contained in:
Andrei Vagin
2022-04-27 06:56:37 +03:00
parent 0df0a7dace
commit b2bfb7745d
2 changed files with 40 additions and 25 deletions

View File

@@ -10,7 +10,7 @@ struct ps_info {
extern int cr_page_server(bool daemon_mode, bool lazy_dump, int cfd); extern int cr_page_server(bool daemon_mode, bool lazy_dump, int cfd);
/* User buffer for read-mode pre-dump*/ /* User buffer for read-mode pre-dump*/
#define BUFFER_SIZE (PIPE_MAX_SIZE << PAGE_SHIFT) #define PIPE_MAX_BUFFER_SIZE (PIPE_MAX_SIZE << PAGE_SHIFT)
/* /*
* page_xfer -- transfer pages into image file. * page_xfer -- transfer pages into image file.

View File

@@ -777,31 +777,48 @@ int page_xfer_predump_pages(int pid, struct page_xfer *xfer, struct page_pipe *p
struct page_pipe_buf *ppb; struct page_pipe_buf *ppb;
unsigned int cur_hole = 0, i; unsigned int cur_hole = 0, i;
unsigned long ret, bytes_read; unsigned long ret, bytes_read;
unsigned long userbuf_len;
struct iovec bufvec; struct iovec bufvec;
struct iovec aux_iov[PIPE_MAX_SIZE]; struct iovec *aux_iov;
unsigned long aux_len; unsigned long aux_len;
void *userbuf;
char *userbuf = mmap(NULL, BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); userbuf_len = PIPE_MAX_BUFFER_SIZE;
userbuf = mmap(NULL, userbuf_len, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (userbuf == MAP_FAILED) { if (userbuf == MAP_FAILED) {
pr_perror("Unable to mmap a buffer"); pr_perror("Unable to mmap a buffer");
return -1; return -1;
} }
aux_iov = xmalloc(userbuf_len / PAGE_SIZE * sizeof(aux_iov[0]));
if (!aux_iov)
goto err;
list_for_each_entry(ppb, &pp->bufs, l) { list_for_each_entry(ppb, &pp->bufs, l) {
if (ppb->pipe_size * PAGE_SIZE > userbuf_len) {
void *addr;
addr = mremap(userbuf, userbuf_len, ppb->pipe_size * PAGE_SIZE, MREMAP_MAYMOVE);
if (addr == MAP_FAILED) {
pr_perror("Unable to mmap a buffer");
goto err;
}
userbuf_len = ppb->pipe_size * PAGE_SIZE;
userbuf = addr;
addr = xrealloc(aux_iov, ppb->pipe_size * sizeof(aux_iov[0]));
if (!addr)
goto err;
aux_iov = addr;
}
timing_start(TIME_MEMDUMP); timing_start(TIME_MEMDUMP);
aux_len = 0; aux_len = 0;
bufvec.iov_len = BUFFER_SIZE; bufvec.iov_len = userbuf_len;
bufvec.iov_base = userbuf; bufvec.iov_base = userbuf;
bytes_read = fill_userbuf(pid, ppb, &bufvec, aux_iov, &aux_len); bytes_read = fill_userbuf(pid, ppb, &bufvec, aux_iov, &aux_len);
if (bytes_read == -ESRCH)
if (bytes_read == -ESRCH) { goto err;
munmap(userbuf, BUFFER_SIZE);
return -1;
}
bufvec.iov_base = userbuf; bufvec.iov_base = userbuf;
bufvec.iov_len = bytes_read; bufvec.iov_len = bytes_read;
@@ -809,8 +826,7 @@ int page_xfer_predump_pages(int pid, struct page_xfer *xfer, struct page_pipe *p
if (ret == -1 || ret != bytes_read) { if (ret == -1 || ret != bytes_read) {
pr_err("vmsplice: Failed to splice user buffer to pipe %ld\n", ret); pr_err("vmsplice: Failed to splice user buffer to pipe %ld\n", ret);
munmap(userbuf, BUFFER_SIZE); goto err;
return -1;
} }
timing_stop(TIME_MEMDUMP); timing_stop(TIME_MEMDUMP);
@@ -822,10 +838,8 @@ int page_xfer_predump_pages(int pid, struct page_xfer *xfer, struct page_pipe *p
u32 flags; u32 flags;
ret = dump_holes(xfer, pp, &cur_hole, iov.iov_base); ret = dump_holes(xfer, pp, &cur_hole, iov.iov_base);
if (ret) { if (ret)
munmap(userbuf, BUFFER_SIZE); goto err;
return ret;
}
BUG_ON(iov.iov_base < (void *)xfer->offset); BUG_ON(iov.iov_base < (void *)xfer->offset);
iov.iov_base -= xfer->offset; iov.iov_base -= xfer->offset;
@@ -833,24 +847,25 @@ int page_xfer_predump_pages(int pid, struct page_xfer *xfer, struct page_pipe *p
flags = ppb_xfer_flags(xfer, ppb); flags = ppb_xfer_flags(xfer, ppb);
if (xfer->write_pagemap(xfer, &iov, flags)) { if (xfer->write_pagemap(xfer, &iov, flags))
munmap(userbuf, BUFFER_SIZE); goto err;
return -1;
}
if (xfer->write_pages(xfer, ppb->p[0], iov.iov_len)) { if (xfer->write_pages(xfer, ppb->p[0], iov.iov_len))
munmap(userbuf, BUFFER_SIZE); goto err;
return -1;
}
} }
timing_stop(TIME_MEMWRITE); timing_stop(TIME_MEMWRITE);
} }
munmap(userbuf, BUFFER_SIZE); munmap(userbuf, userbuf_len);
xfree(aux_iov);
timing_start(TIME_MEMWRITE); timing_start(TIME_MEMWRITE);
return dump_holes(xfer, pp, &cur_hole, NULL); return dump_holes(xfer, pp, &cur_hole, NULL);
err:
munmap(userbuf, userbuf_len);
xfree(aux_iov);
return -1;
} }
int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp) int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp)