[CRIU] [PATCH 5/5] page-pipe: allow to share pipes between page pipe buffers
Andrei Vagin
avagin at openvz.org
Wed Nov 8 03:36:05 MSK 2017
From: Andrei Vagin <avagin at virtuozzo.com>
Now criu create a new pipe buffer, if a previous one has another set of
flags. In this case, a pipe is not full and we can use it for the
next page buffer.
We need 88 pipes to pre-dump the zdtm/static/fork test without this
patch, and we need only 17 pipes with this patch.
Signed-off-by: Andrei Vagin <avagin at virtuozzo.com>
---
criu/include/page-pipe.h | 1 +
criu/page-pipe.c | 45 +++++++++++++++++++++++++++++++--------------
criu/page-xfer.c | 2 +-
3 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/criu/include/page-pipe.h b/criu/include/page-pipe.h
index 301edaae0..053ae3938 100644
--- a/criu/include/page-pipe.h
+++ b/criu/include/page-pipe.h
@@ -93,6 +93,7 @@ struct kernel_pipe_buffer {
struct page_pipe_buf {
int p[2]; /* pipe with pages */
unsigned int pipe_size; /* how many pages can be fit into pipe */
+ unsigned int pipe_off; /* where this buf is started in a pipe */
unsigned int pages_in; /* how many pages are there */
unsigned int nr_segs; /* how many iov-s are busy */
#define PPB_LAZY (1 << 0)
diff --git a/criu/page-pipe.c b/criu/page-pipe.c
index 0f5e39ee2..f7d691d13 100644
--- a/criu/page-pipe.c
+++ b/criu/page-pipe.c
@@ -50,7 +50,7 @@ static inline int ppb_resize_pipe(struct page_pipe_buf *ppb)
unsigned long new_size = ppb->pipe_size << 1;
int ret;
- if (ppb->pages_in < ppb->pipe_size)
+ if (ppb->pages_in + ppb->pipe_off < ppb->pipe_size)
return 0;
if (new_size > PIPE_MAX_SIZE)
@@ -63,7 +63,7 @@ static inline int ppb_resize_pipe(struct page_pipe_buf *ppb)
return 0;
}
-static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp)
+static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp, struct page_pipe_buf *prev)
{
struct page_pipe_buf *ppb;
@@ -72,15 +72,25 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp)
return NULL;
cnt_add(CNT_PAGE_PIPE_BUFS, 1);
- if (pipe(ppb->p)) {
- xfree(ppb);
- pr_perror("Can't make pipe for page-pipe");
- return NULL;
- }
- cnt_add(CNT_PAGE_PIPES, 1);
+ ppb->pipe_off = 0;
+
+ if (prev && ppb_resize_pipe(prev) == 0) {
+ /* The previous pipe isn't full and we can continue to use it. */
+ ppb->p[0] = prev->p[0];
+ ppb->p[1] = prev->p[1];
+ ppb->pipe_off = prev->pages_in + prev->pipe_off;
+ ppb->pipe_size = prev->pipe_size;
+ } else {
+ if (pipe(ppb->p)) {
+ xfree(ppb);
+ pr_perror("Can't make pipe for page-pipe");
+ return NULL;
+ }
+ cnt_add(CNT_PAGE_PIPES, 1);
- ppb->pipe_size = fcntl(ppb->p[0], F_GETPIPE_SZ, 0) / PAGE_SIZE;
- pp->nr_pipes++;
+ ppb->pipe_size = fcntl(ppb->p[0], F_GETPIPE_SZ, 0) / PAGE_SIZE;
+ pp->nr_pipes++;
+ }
list_add_tail(&ppb->l, &pp->bufs);
@@ -89,8 +99,11 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp)
static void ppb_destroy(struct page_pipe_buf *ppb)
{
- close(ppb->p[0]);
- close(ppb->p[1]);
+ /* Check whether a pipe is shared with another ppb */
+ if (ppb->pipe_off == 0) {
+ close(ppb->p[0]);
+ close(ppb->p[1]);
+ }
xfree(ppb);
}
@@ -106,7 +119,7 @@ static void ppb_init(struct page_pipe_buf *ppb, unsigned int pages_in,
static int page_pipe_grow(struct page_pipe *pp, unsigned int flags)
{
- struct page_pipe_buf *ppb;
+ struct page_pipe_buf *ppb, *prev = NULL;
struct iovec *free_iov;
pr_debug("Will grow page pipe (iov off is %u)\n", pp->free_iov);
@@ -120,7 +133,10 @@ static int page_pipe_grow(struct page_pipe *pp, unsigned int flags)
if ((pp->flags & PP_CHUNK_MODE) && (pp->nr_pipes == NR_PIPES_PER_CHUNK))
return -EAGAIN;
- ppb = ppb_alloc(pp);
+ /* don't allow to reuse a pipe in the PP_CHUNK_MODE mode */
+ if (!(pp->flags & PP_CHUNK_MODE) && !list_empty(&pp->bufs))
+ prev = list_entry(pp->bufs.prev, struct page_pipe_buf, l);
+ ppb = ppb_alloc(pp, prev);
if (!ppb)
return -1;
@@ -374,6 +390,7 @@ int page_pipe_read(struct page_pipe *pp, struct pipe_read_dest *prd,
(unsigned long)(*nr_pages) * PAGE_SIZE);
*nr_pages = len / PAGE_SIZE;
+ skip += ppb->pipe_off * PAGE_SIZE;
/* we should tee() the requested lenth + the beginning of the pipe */
len += skip;
diff --git a/criu/page-xfer.c b/criu/page-xfer.c
index f62bb6f47..2e4547c70 100644
--- a/criu/page-xfer.c
+++ b/criu/page-xfer.c
@@ -217,7 +217,7 @@ static int write_pages_loc(struct page_xfer *xfer,
ssize_t curr = 0;
while (1) {
- ret = splice(p, NULL, img_raw_fd(xfer->pi), NULL, len, SPLICE_F_MOVE);
+ ret = splice(p, NULL, img_raw_fd(xfer->pi), NULL, len - curr, SPLICE_F_MOVE);
if (ret == -1) {
pr_perror("Unable to spice data");
return -1;
--
2.13.6
More information about the CRIU
mailing list