2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-30 05:48:05 +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);
/* 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.

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;
unsigned int cur_hole = 0, i;
unsigned long ret, bytes_read;
unsigned long userbuf_len;
struct iovec bufvec;
struct iovec aux_iov[PIPE_MAX_SIZE];
struct iovec *aux_iov;
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) {
pr_perror("Unable to mmap a buffer");
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) {
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);
aux_len = 0;
bufvec.iov_len = BUFFER_SIZE;
bufvec.iov_len = userbuf_len;
bufvec.iov_base = userbuf;
bytes_read = fill_userbuf(pid, ppb, &bufvec, aux_iov, &aux_len);
if (bytes_read == -ESRCH) {
munmap(userbuf, BUFFER_SIZE);
return -1;
}
if (bytes_read == -ESRCH)
goto err;
bufvec.iov_base = userbuf;
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) {
pr_err("vmsplice: Failed to splice user buffer to pipe %ld\n", ret);
munmap(userbuf, BUFFER_SIZE);
return -1;
goto err;
}
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;
ret = dump_holes(xfer, pp, &cur_hole, iov.iov_base);
if (ret) {
munmap(userbuf, BUFFER_SIZE);
return ret;
}
if (ret)
goto err;
BUG_ON(iov.iov_base < (void *)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);
if (xfer->write_pagemap(xfer, &iov, flags)) {
munmap(userbuf, BUFFER_SIZE);
return -1;
}
if (xfer->write_pagemap(xfer, &iov, flags))
goto err;
if (xfer->write_pages(xfer, ppb->p[0], iov.iov_len)) {
munmap(userbuf, BUFFER_SIZE);
return -1;
}
if (xfer->write_pages(xfer, ppb->p[0], iov.iov_len))
goto err;
}
timing_stop(TIME_MEMWRITE);
}
munmap(userbuf, BUFFER_SIZE);
munmap(userbuf, userbuf_len);
xfree(aux_iov);
timing_start(TIME_MEMWRITE);
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)