[CRIU] [RFC PATCH 07/12] lazy-pages: add handling of UFFD_EVENT_REMAP

Pavel Emelyanov xemul at virtuozzo.com
Tue Jan 10 06:07:01 PST 2017


On 01/09/2017 11:23 AM, Mike Rapoport wrote:
> When the restored process calls mremap(), we will see #PF's on the new
> addresses and we have to create a correspondence between the addresses
> found in the dump and the actual addresses the process uses. If the
> mremap() call causes the mapping to grow, the additional part will receive
> zero pages, as expected.
> 
> FIXME: is the mapping shrinks, we will try to fill the dropped part and
> lazy-pages daemon will fail. It should be possible to track VMA changes in
> the lazy-pages daemon, but simpler, and, apparently, more correct would be
> to add UFFD_EVENT_MUNMAP to the kernel.
> 
> Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
> ---
>  criu/uffd.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 46 insertions(+), 1 deletion(-)
> 
> diff --git a/criu/uffd.c b/criu/uffd.c
> index 3bc7bc1..8bf4a14 100644
> --- a/criu/uffd.c
> +++ b/criu/uffd.c
> @@ -53,7 +53,12 @@ struct lazy_iovec {
>  	unsigned long len;
>  };
>  
> -struct lazy_pages_info;
> +struct lazy_remap {
> +	struct list_head l;
> +	unsigned long from;
> +	unsigned long to;
> +	unsigned long len;
> +};
>  
>  struct pf_info {
>  	unsigned long addr;
> @@ -65,6 +70,7 @@ struct lazy_pages_info {
>  
>  	struct list_head iovs;
>  	struct list_head pfs;
> +	struct list_head remaps;
>  
>  	struct page_read pr;
>  
> @@ -92,6 +98,7 @@ static struct lazy_pages_info *lpi_init(void)
>  	memset(lpi, 0, sizeof(*lpi));
>  	INIT_LIST_HEAD(&lpi->iovs);
>  	INIT_LIST_HEAD(&lpi->pfs);
> +	INIT_LIST_HEAD(&lpi->remaps);
>  	INIT_LIST_HEAD(&lpi->l);
>  	lpi->lpfd.revent = handle_uffd_event;
>  
> @@ -101,12 +108,15 @@ static struct lazy_pages_info *lpi_init(void)
>  static void lpi_fini(struct lazy_pages_info *lpi)
>  {
>  	struct lazy_iovec *p, *n;
> +	struct lazy_remap *p1, *n1;
>  
>  	if (!lpi)
>  		return;
>  	free(lpi->buf);
>  	list_for_each_entry_safe(p, n, &lpi->iovs, l)
>  		xfree(p);
> +	list_for_each_entry_safe(p1, n1, &lpi->remaps, l)
> +		xfree(p1);
>  	if (lpi->lpfd.fd > 0)
>  		close(lpi->lpfd.fd);
>  	if (lpi->pr.close)
> @@ -515,9 +525,17 @@ out:
>  static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages)
>  {
>  	struct uffdio_copy uffdio_copy;
> +	struct lazy_remap *r;
>  	unsigned long len = nr_pages * page_size();
>  	int rc;
>  
> +	list_for_each_entry(r, &lpi->remaps, l) {
> +		if (address >= r->from && address < r->from + r->len) {
> +			address += (r->to - r->from);
> +			break;
> +		}
> +	}
> +
>  	uffdio_copy.dst = address;
>  	uffdio_copy.src = (unsigned long)lpi->buf;
>  	uffdio_copy.len = len;
> @@ -670,9 +688,27 @@ static int handle_madv_dontneed(struct lazy_pages_info *lpi,
>  	return 0;
>  }
>  
> +static int handle_remap(struct lazy_pages_info *lpi, struct uffd_msg *msg)
> +{
> +	struct lazy_remap *remap;
> +
> +	remap = xmalloc(sizeof(*remap));
> +	if (!remap)
> +		return -1;
> +
> +	INIT_LIST_HEAD(&remap->l);
> +	remap->from = msg->arg.remap.from;
> +	remap->to = msg->arg.remap.to;
> +	remap->len = msg->arg.remap.len;
> +	list_add_tail(&remap->l, &lpi->remaps);

Shouldn't we punch a hole in original region? Not to handle #PF there?
Also, what if one region is remapped somewhere, then remapped back? Will
we have two "patches" for it?
Also, what if we swap two regs with remap (a->c, b->a, c->b) what kind of
mess will we have here? %)

> +
> +	return 0;
> +}
> +
>  static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg)
>  {
>  	struct pf_info *pf;
> +	struct lazy_remap *r;
>  	__u64 address;
>  	int ret;
>  
> @@ -695,6 +731,13 @@ static int handle_page_fault(struct lazy_pages_info *lpi, struct uffd_msg *msg)
>  	}
>  #endif
>  
> +	list_for_each_entry(r, &lpi->remaps, l) {
> +		if (address >= r->to && address < r->to + r->len) {
> +			address -= (r->to - r->from);
> +			break;
> +		}
> +	}
> +
>  	list_for_each_entry(pf, &lpi->pfs, l)
>  		if (pf->addr == address)
>  			return 0;
> @@ -742,6 +785,8 @@ static int handle_uffd_event(struct epoll_rfd *lpfd)
>  		return handle_page_fault(lpi, &msg);
>  	case UFFD_EVENT_MADVDONTNEED:
>  		return handle_madv_dontneed(lpi, &msg);
> +	case UFFD_EVENT_REMAP:
> +		return handle_remap(lpi, &msg);
>  	default:
>  		pr_err("unexpected uffd event %u\n", msg.event);
>  		return -1;
> 



More information about the CRIU mailing list