[CRIU] [PATCH 4/4] page-pipe: allow to share pipes between page pipe buffers
Mike Rapoport
rppt at linux.vnet.ibm.com
Tue Nov 7 17:45:44 MSK 2017
On Tue, Nov 07, 2017 at 03:02:37AM +0300, Andrei Vagin wrote:
> 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);
Nit: can we move resize_pipe in the previous patch before its use to avoid
forward declaration?
> +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
>
> _______________________________________________
> CRIU mailing list
> CRIU at openvz.org
> https://lists.openvz.org/mailman/listinfo/criu
>
--
Sincerely yours,
Mike.
More information about the CRIU
mailing list