[CRIU] [RFC PATCH 04/16] criu: lazy-pages: handle remaining pages based on IOVs rather than pages

Pavel Emelyanov xemul at virtuozzo.com
Wed Oct 5 06:07:43 PDT 2016


On 09/27/2016 04:42 PM, Mike Rapoport wrote:
> Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
> ---
>  criu/uffd.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 70 insertions(+), 14 deletions(-)
> 
> diff --git a/criu/uffd.c b/criu/uffd.c
> index 063ce4f..3f25b86 100644
> --- a/criu/uffd.c
> +++ b/criu/uffd.c
> @@ -325,6 +325,56 @@ out:
>  
>  static int find_vmas(struct lazy_pages_info *lpi);
>  
> +static int update_lazy_iovecs(struct lazy_pages_info *lpi, unsigned long addr,
> +			       int len)
> +{
> +	struct lazy_iovec *lazy_iov, *n;
> +
> +	list_for_each_entry_safe(lazy_iov, n, &lpi->iovs, l) {
> +		unsigned long start = (unsigned long)lazy_iov->iov.iov_base;
> +		unsigned long end = start + lazy_iov->iov.iov_len;
> +
> +		if (len <= 0)
> +			break;
> +
> +		if (addr < start || addr >= end)
> +			continue;
> +
> +		if (addr + len < end) {
> +			if (addr == start) {
> +				lazy_iov->iov.iov_base += len;
> +				lazy_iov->iov.iov_len -= len;
> +			} else {
> +				struct lazy_iovec *new;
> +
> +				lazy_iov->iov.iov_len -= (end - addr);
> +
> +				new = xzalloc(sizeof(*new));
> +				if (!new)
> +					return -1;
> +
> +				new->iov.iov_base = (void *)(addr + len);
> +				new->iov.iov_len = end - (addr + len);
> +
> +				list_add(&new->l, &lazy_iov->l);
> +			}
> +			break;
> +		}
> +
> +		if (addr == start) {
> +			list_del(&lazy_iov->l);
> +			xfree(lazy_iov);
> +		} else {
> +			lazy_iov->iov.iov_len -= (end - addr);
> +		}
> +
> +		len -= (end - addr);
> +		addr = end;
> +	}
> +
> +	return 0;
> +}
> +
>  static int collect_lazy_iovecs(struct lazy_pages_info *lpi)
>  {
>  	struct page_read *pr = &lpi->pr;
> @@ -585,28 +635,30 @@ static int collect_uffd_pages(struct page_read *pr, struct lazy_pages_info *lpi)
>  
>  static int handle_remaining_pages(struct lazy_pages_info *lpi, void *dest)
>  {
> -	struct uffd_pages_struct *uffd_pages;
> -	int rc;
> +	struct lazy_iovec *lazy_iov;
> +	int nr_pages, i, err;
> +	unsigned long base, addr;
>  
> -	list_for_each_entry(uffd_pages, &lpi->pages, list) {

The lpi->pages list is not longer in use after this, is it?

> -		pr_debug("Checking remaining pages 0x%lx (flags 0x%x)\n",
> -			 uffd_pages->addr, uffd_pages->flags);
> -		if (uffd_pages->flags & UFFD_FLAG_SENT)
> -			continue;
> +	lpi->pr.reset(&lpi->pr);
>  
> -		rc = uffd_handle_page(lpi, uffd_pages->addr, dest);
> -		if (rc < 0) {
> -			pr_err("Error during UFFD copy\n");
> -			return -1;
> -		}
> +	list_for_each_entry(lazy_iov, &lpi->iovs, l) {
> +		nr_pages = lazy_iov->iov.iov_len / PAGE_SIZE;
> +		base = (unsigned long)lazy_iov->iov.iov_base;
>  
> -		uffd_pages->flags |= UFFD_FLAG_SENT;
> +		for (i = 0; i < nr_pages; i++) {
> +			addr = base + i * PAGE_SIZE;
> +
> +			err = uffd_handle_page(lpi, addr, dest);
> +			if (err < 0) {
> +				pr_err("Error during UFFD copy\n");
> +				return -1;
> +			}
> +		}
>  	}
>  
>  	return 0;
>  }
>  
> -
>  static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest,
>  				__u64 address)
>  {
> @@ -628,6 +680,10 @@ static int handle_regular_pages(struct lazy_pages_info *lpi, void *dest,
>  			uffd_pages->flags |= UFFD_FLAG_SENT;
>  	}
>  
> +	rc = update_lazy_iovecs(lpi, address, PAGE_SIZE);

Ugh, why second scan for lpi->iovs? Can we update them right in the
place where we handle them?

> +	if (rc < 0)
> +		return -1;
> +
>  	return 0;
>  }
>  
> 



More information about the CRIU mailing list