[CRIU] [PATCH 4/4] page-pipe: allow to share pipes between page pipe buffers
Andrei Vagin
avagin at openvz.org
Tue Nov 7 03:02:37 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 | 46 ++++++++++++++++++++++++++++++++--------------
criu/page-xfer.c | 2 +-
3 files changed, 34 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 adad1819d..1a37cb5b9 100644
--- a/criu/page-pipe.c
+++ b/criu/page-pipe.c
@@ -28,7 +28,8 @@ static inline void iov_init(struct iovec *iov, unsigned long addr)
iov->iov_len = PAGE_SIZE;
}
-static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp)
+static inline int resize_pipe(struct page_pipe_buf *ppb);
+static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp, struct page_pipe_buf *prev)
{
struct page_pipe_buf *ppb;
@@ -37,15 +38,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 && 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);
@@ -54,8 +65,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);
}
@@ -88,7 +102,7 @@ static int ppb_resize_pipe(struct page_pipe_buf *ppb, unsigned long new_size)
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);
@@ -102,7 +116,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;
@@ -194,7 +211,7 @@ static inline int 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)
@@ -374,6 +391,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 814dc8367..63b88c78b 100644
--- a/criu/page-xfer.c
+++ b/criu/page-xfer.c
@@ -216,7 +216,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