[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