Commit cef1efe5 authored by Andrei Vagin's avatar Andrei Vagin

page-pipe: allow to share pipes between page pipe buffers

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.
Acked-by: 's avatarMike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 6feebf3a
...@@ -93,6 +93,7 @@ struct kernel_pipe_buffer { ...@@ -93,6 +93,7 @@ struct kernel_pipe_buffer {
struct page_pipe_buf { struct page_pipe_buf {
int p[2]; /* pipe with pages */ int p[2]; /* pipe with pages */
unsigned int pipe_size; /* how many pages can be fit into pipe */ 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 pages_in; /* how many pages are there */
unsigned int nr_segs; /* how many iov-s are busy */ unsigned int nr_segs; /* how many iov-s are busy */
#define PPB_LAZY (1 << 0) #define PPB_LAZY (1 << 0)
......
...@@ -50,7 +50,7 @@ static inline int ppb_resize_pipe(struct page_pipe_buf *ppb) ...@@ -50,7 +50,7 @@ static inline int ppb_resize_pipe(struct page_pipe_buf *ppb)
unsigned long new_size = ppb->pipe_size << 1; unsigned long new_size = ppb->pipe_size << 1;
int ret; int ret;
if (ppb->pages_in < ppb->pipe_size) if (ppb->pages_in + ppb->pipe_off < ppb->pipe_size)
return 0; return 0;
if (new_size > PIPE_MAX_SIZE) if (new_size > PIPE_MAX_SIZE)
...@@ -63,7 +63,7 @@ static inline int ppb_resize_pipe(struct page_pipe_buf *ppb) ...@@ -63,7 +63,7 @@ static inline int ppb_resize_pipe(struct page_pipe_buf *ppb)
return 0; 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; struct page_pipe_buf *ppb;
...@@ -72,15 +72,25 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp) ...@@ -72,15 +72,25 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp)
return NULL; return NULL;
cnt_add(CNT_PAGE_PIPE_BUFS, 1); cnt_add(CNT_PAGE_PIPE_BUFS, 1);
if (pipe(ppb->p)) { ppb->pipe_off = 0;
xfree(ppb);
pr_perror("Can't make pipe for page-pipe"); if (prev && ppb_resize_pipe(prev) == 0) {
return NULL; /* The previous pipe isn't full and we can continue to use it. */
} ppb->p[0] = prev->p[0];
cnt_add(CNT_PAGE_PIPES, 1); 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; ppb->pipe_size = fcntl(ppb->p[0], F_GETPIPE_SZ, 0) / PAGE_SIZE;
pp->nr_pipes++; pp->nr_pipes++;
}
list_add_tail(&ppb->l, &pp->bufs); list_add_tail(&ppb->l, &pp->bufs);
...@@ -89,8 +99,11 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp) ...@@ -89,8 +99,11 @@ static struct page_pipe_buf *ppb_alloc(struct page_pipe *pp)
static void ppb_destroy(struct page_pipe_buf *ppb) static void ppb_destroy(struct page_pipe_buf *ppb)
{ {
close(ppb->p[0]); /* Check whether a pipe is shared with another ppb */
close(ppb->p[1]); if (ppb->pipe_off == 0) {
close(ppb->p[0]);
close(ppb->p[1]);
}
xfree(ppb); xfree(ppb);
} }
...@@ -106,7 +119,7 @@ static void ppb_init(struct page_pipe_buf *ppb, unsigned int pages_in, ...@@ -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) 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; struct iovec *free_iov;
pr_debug("Will grow page pipe (iov off is %u)\n", pp->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) ...@@ -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)) if ((pp->flags & PP_CHUNK_MODE) && (pp->nr_pipes == NR_PIPES_PER_CHUNK))
return -EAGAIN; 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) if (!ppb)
return -1; return -1;
...@@ -374,6 +390,7 @@ int page_pipe_read(struct page_pipe *pp, struct pipe_read_dest *prd, ...@@ -374,6 +390,7 @@ int page_pipe_read(struct page_pipe *pp, struct pipe_read_dest *prd,
(unsigned long)(*nr_pages) * PAGE_SIZE); (unsigned long)(*nr_pages) * PAGE_SIZE);
*nr_pages = len / PAGE_SIZE; *nr_pages = len / PAGE_SIZE;
skip += ppb->pipe_off * PAGE_SIZE;
/* we should tee() the requested lenth + the beginning of the pipe */ /* we should tee() the requested lenth + the beginning of the pipe */
len += skip; len += skip;
......
...@@ -216,7 +216,7 @@ static int write_pages_loc(struct page_xfer *xfer, ...@@ -216,7 +216,7 @@ static int write_pages_loc(struct page_xfer *xfer,
ssize_t curr = 0; ssize_t curr = 0;
while (1) { 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) { if (ret == -1) {
pr_perror("Unable to spice data"); pr_perror("Unable to spice data");
return -1; return -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment