[CRIU] [PATCH v2] page-pipe: (yet another) fix for split page-pipe buffers

Mike Rapoport mike.rapoport at gmail.com
Fri Nov 25 08:44:24 PST 2016


Ping?

On Wed, Nov 23, 2016 at 2:27 PM, Mike Rapoport <rppt at linux.vnet.ibm.com> wrote:
> Splitting of the trailing part of page-pipe buffer worked by coincidence
> for single page requests. Request longer than a single page were not
> handled correctly.
> The proper point for splitting the trailing part of the page-pipe buffer is
> the IOV following the IOV containing the desired page(s).
>
> Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
> ---
> v2: after split of the trailing part, the pointer to ppb in page_pipe_split
> was not update and pointed to the wrong buffer
>
>  criu/page-pipe.c | 56 +++++++++++++++++++++++---------------------------------
>  1 file changed, 23 insertions(+), 33 deletions(-)
>
> diff --git a/criu/page-pipe.c b/criu/page-pipe.c
> index 1981ff1..89cb27b 100644
> --- a/criu/page-pipe.c
> +++ b/criu/page-pipe.c
> @@ -393,10 +393,9 @@ static int page_pipe_split_iov(struct page_pipe *pp, struct page_pipe_buf *ppb,
>  }
>
>  static int page_pipe_split_ppb(struct page_pipe *pp, struct page_pipe_buf *ppb,
> -                              struct iovec *iov, unsigned long len)
> +                              struct iovec *iov, unsigned long len,
> +                              bool popup_new)
>  {
> -       struct page_pipe_buf *ppb_tmp;
> -       struct iovec *iov_tmp = iov;
>         struct page_pipe_buf *ppb_new;
>         int ret;
>
> @@ -414,36 +413,10 @@ static int page_pipe_split_ppb(struct page_pipe *pp, struct page_pipe_buf *ppb,
>         ppb->nr_segs -= ppb_new->nr_segs;
>         ppb->pages_in -= len / PAGE_SIZE;
>
> +       if (popup_new)
> +               ppb = ppb_new;
>         list_move(&ppb->l, &pp->bufs);
>
> -       /*
> -        * Only the leading iov's are split from the page_pipe_buffer.
> -        * The complete page_pipe_buffer at the start of the page_pipe
> -        * list will be deleted and therefore it is necessary to also
> -        * move unrelated iov's to their own page_pipe_buffers.
> -        */
> -
> -       if (ppb->nr_segs <= len / PAGE_SIZE)
> -               return 0;
> -
> -       /* Move to the iov after the current request */
> -       iov += len / PAGE_SIZE;
> -       ret = page_pipe_split_ppb(pp, ppb, iov, len);
> -       if (ret)
> -               return -1;
> -
> -       /*
> -        * Rotate until correct head pointer. The function transmitting
> -        * the page data expects that the head points to the right
> -        * page_pipe_buffer. The complete first page_pipe_buffer is
> -        * deleted even it contains additional elements.
> -        */
> -       ppb_tmp = list_first_entry(&pp->bufs, struct page_pipe_buf, l);
> -       while (ppb_tmp->iov != iov_tmp) {
> -               list_rotate_left(&pp->bufs);
> -               ppb_tmp = list_first_entry(&pp->bufs, struct page_pipe_buf, l);
> -       }
> -
>         return 0;
>  }
>
> @@ -471,14 +444,31 @@ int page_pipe_split(struct page_pipe *pp, unsigned long addr,
>                 return 0;
>         }
>
> -       /* split origingal ppb on boundary of iov that contains addr */
> +       /*
> +        * Split origingal ppb on boundary of iov that contains
> +        * addr. The ppb containing the address will remain at the
> +        * pp->buf list head.
> +        */
>         if (iov != ppb->iov) {
>                 len -= (addr - (unsigned long)iov->iov_base);
> -               ret = page_pipe_split_ppb(pp, ppb, iov, len);
> +               ret = page_pipe_split_ppb(pp, ppb, iov, len, false);
>                 if (ret)
>                         return -1;
>         }
>
> +       /*
> +        * Split the tail of the ppb. We presume that requests do not
> +        * cross IOV (that is pagemap entry) boundaries.
> +        * The newly created ppb will contain the desired IOV and will
> +        * be poped to the head of the pp->buf list
> +        */
> +       if (ppb->nr_segs > 1) {
> +               len = iov->iov_len;
> +               ret = page_pipe_split_ppb(pp, ppb, iov + 1, len, true);
> +               if (ret)
> +                       return -1;
> +               ppb = list_first_entry(&pp->bufs, struct page_pipe_buf, l);
> +       }
>
>         /*
>          * if address does not match iov base, split the iov and
> --
> 1.9.1
>



-- 
Sincerely yours,
Mike.


More information about the CRIU mailing list